АнглийскийФранцузскийИспанский

Ad


Значок OnWorks

makepp_cookbook - Интернет в облаке

Запустите makepp_cookbook в бесплатном хостинг-провайдере OnWorks через Ubuntu Online, Fedora Online, онлайн-эмулятор Windows или онлайн-эмулятор MAC OS

Это команда makepp_cookbook, которую можно запустить в провайдере бесплатного хостинга OnWorks, используя одну из наших многочисленных бесплатных онлайн-рабочих станций, таких как Ubuntu Online, Fedora Online, онлайн-эмулятор Windows или онлайн-эмулятор MAC OS.

ПРОГРАММА:

ИМЯ


makepp_cookbook - лучший способ настроить make-файлы для различных ситуаций

ОПИСАНИЕ


Я обнаружил, что практически никто никогда не читает руководство к инструменту make, потому что, откровенно говоря,
на самом деле никого не интересует сам процесс make - нас интересуют только результаты.
Итак, эта поваренная книга была составлена ​​в надежде, что люди смогут получить то, что им нужно.
быстро из примеров, не углубляясь в руководство. Это показывает, как набрать
вопросы, а инструкции по установке и камни преткновения можно найти в
Часто задаваемые вопросы.

Строительство библиотеки
Do являетесь на самом деле необходимость a библиотека?

Я видел несколько больших программ, состоящих из большого количества модулей, каждый из которых
который живет в собственном каталоге. Обычно каждый каталог помещается в свою собственную библиотеку,
а затем последняя программа связывается со всеми библиотеками.

Во многих случаях я думаю, что есть лучший подход, чем использовать библиотеку. Библиотеки
не совсем правильное решение, если каждый модуль не может или не будет повторно использован в каком-либо другом
программа, потому что тогда вы получите все недостатки библиотек и ни один из
преимущества. Библиотеки полезны в следующих случаях:

1. Когда у вас есть несколько подпрограмм, которые нужно связать с несколькими разными
программ, и ни одна программа на самом деле не использует 100% подпрограмм - каждая программа использует
другое подмножество. В этом случае, вероятно, будет хорошей идеей использовать статическую библиотеку (
.a файл или архивный файл).

2. Когда у вас есть модуль, который нужно связать с несколькими разными программами, и вы
хотите загружать его динамически, чтобы у каждой программы не было отдельной копии
библиотека. Динамические библиотеки могут сэкономить пространство исполняемого файла и иногда улучшить
производительность системы, потому что загружена только одна копия библиотеки для всех
разные программы, которые его используют.

3. Если время компоновки недопустимо велико, использование общих библиотек для больших частей
программа позволяет значительно ускорить переход по ссылке.

Использование статических библиотек имеет один главный недостаток: в некоторых системах (например, Linux) порядок
в котором вы связываете библиотеки, это критически важно. Компоновщик обрабатывает библиотеки
в порядке, указанном в его командной строке. Он берет все, что ему нужно, от
каждая библиотека, затем переходит к следующей библиотеке. Если какая-либо последующая библиотека ссылается на
символ, который еще не был включен из предыдущей библиотеки, компоновщик не
знать, что нужно вернуться и взять его из предыдущей библиотеки. В результате может возникнуть необходимость
чтобы перечислить библиотеку несколько раз в командной строке компоновщика. (Я работал над проектом
где нам пришлось трижды повторить весь список библиотек. Этот проект сделал
Я предпочитаю альтернативный подход, предложенный ниже, - постепенное связывание.)

Использование динамических библиотек имеет ряд недостатков. Во-первых, ваша программа может быть немного
медленнее запускается, если библиотека еще не используется какой-либо другой программой, потому что
его нужно найти и загрузить. Во-вторых, получить всю динамику может быть непросто.
библиотеки установлены в правильные места; нельзя просто скопировать исполняемый файл программы,
вы также должны убедиться, что вы скопировали все его библиотеки. В-третьих, в некоторых системах
сложно отлаживать код внутри разделяемых библиотек, потому что отладчики не поддерживают
им хорошо.

Если ваш модуль никогда не будет использоваться в какой-либо другой программе, тогда нет особых причин использовать
библиотека: вы получаете все недостатки использования библиотек и ни одного преимущества.
Я предпочитаю использовать инкрементное связывание там, где оно доступно.

Вот как это можно сделать в Linux:

my_module.o: $ (filter_out my_module.o, $ (подстановочный знак * .o))
ld -r -o $ (выход) $ (входы)

Это приведет к созданию еще одного .o файл называется my_module.o, который будет состоять из
все .o файлы в этом подкаталоге. Компоновщик разрешит как можно больше
ссылки по мере возможности, а оставшиеся ссылки будут разрешены в
последующий этап связывания. На верхнем уровне, когда вы, наконец, построите свою программу,
вместо ссылки на libmy_module.a or libmy_module.so, вы бы просто связались с
my_module.o. Когда вы связываете .o файлов, у вас нет проблем с зависимостью от порядка в
Командная строка компоновщика.

Высокий потенциал недвижимости для сдачи в аренду макияж понять внешний который библиотека модули Он необходимый

Даже если у вас есть настоящая библиотека, где данной программе нужно всего несколько файлов из нее.
(а не каждый модуль), makepp может определить, какие модули
необходимо из библиотеки и включать только те, которые входят в сборку. Это может спасти компиляцию
время, если вы разрабатываете библиотеку вместе с программой, потому что вы не беспокоитесь о
компилировать библиотечные модули, которые не нужны для конкретной программы, над которой вы работаете.

Если ваша библиотека строго соблюдает соглашение о том, что все функции или классы, объявленные в
файл xyz.h полностью реализованы в исходном файле, который компилируется в xyz.o (т.е. вы
не разбивайте реализацию на xyz1.o и xyz2.o), то вы можете использовать
Функция "$ (infer_objects)", указывающая makepp на необходимость извлечения только соответствующих модулей из
библиотека. Это может работать на удивление хорошо для библиотек даже с десятками включаемых файлов.
Обычно "$ (infer_objects)" проверяет список .h файлы, которые включены, и выглядит
для соответствующих .o файлы. Если вы быстро разрабатываете библиотеку и программу
вместе, это может сэкономить время компиляции, потому что вы никогда не будете компилировать модули
библиотека, которую программа не использует.

Вот пример того, как я его использую:

моя_программа: $ (infer_objects * .o, $ (LIB1) / *. o $ (LIB2) / *. o)
$ (CXX) $ (входы) -o $ (выход) $ (SYSTEM_LIBRARIES)

Функция «$ (infer_objects)» возвращает свой первый аргумент (после выполнения подстановочного знака
расширение на нем), а также просматривает список файлов во втором аргументе для поиска
файлы, имя которых совпадает с именем любого .h файлы, включенные любым файлом в его первый
аргумент. Если такие файлы обнаруживаются, они добавляются в список.

Строительство a статический библиотека

Если вы уверены, что вам действительно нужна библиотека, а добавочное связывание недоступно или
это не то, чем вы хотите заниматься, есть несколько способов сделать это. Во-первых, вот пример
где все файлы явно перечислены:

LIBRARY_FILES = abcde

libmine.a: $ (БИБЛИОТЕКА_ФАЙЛОВ) .o
& rm -f $ (вывод)
$ (AR) cr $ (выход) $ (входы)
ranlib $ (output) # Может не понадобиться, в зависимости от вашей ОС.

& Rm - это встроенная команда makepp "rm". Если вы привыкли писать make-файлы, возможно, вы
немного удивлен этой командой; Возможно, вы привыкли к чему-то более похожему:

libmine.a: $ (БИБЛИОТЕКА_ФАЙЛОВ) .o
$ (AR) ru $ @ $? # Не рекомендуется!!!!!!!
ranlib $ (вывод)

где $? (также известная как «$ (changed_inputs)») - автоматическая переменная, означающая любые файлы
которые изменились с момента последней сборки библиотеки, и $ @ примерно то же самое
как «$ (вывод)».

Такой подход не рекомендуется по нескольким причинам:

· Предположим, вы удалили исходный файл из текущего каталога. Это все еще в
library, потому что вы не перестраивали библиотеку с нуля. В итоге ничего
ссылки с этой библиотекой будут иметь устаревшие .o файл, и это может испортить ваш
строит. (Однажды меня это полностью сбило с толку, когда я пытался удалить мертвый код
из проекта: я продолжал удалять файлы, но они все еще были связаны, поэтому я подумал, что код был
мертвых. Однако, когда кто-то перестраивал проект с нуля, он не связывал ни одного
более! Проблема заключалась в том, что старый .o файлы все еще были в архиве.)

Кроме того, в зависимости от ваших вариантов «ar» и вашей реализации «ar» (например, если вы
используйте параметр «q» вместо «r»), вы можете получить несколько версий
то же .o внутри .a файл. Если разные версии определяют разные глобальные объекты,
компоновщик может попытаться задействовать их обоих. Это, наверное, плохо.

Вот почему мы сначала удаляем файл библиотеки и создаем его с нуля. Это будет
займет немного больше времени, чем просто обновление модулей в библиотеке, но ненамного; на
современный компьютер, время, затрачиваемое ar программа ничтожна по сравнению
к тому, что компилятор C принимает в типичной сборке, так что не стоит беспокоиться
около.

· Один из способов, которым makepp пытается гарантировать правильную сборку, заключается в том, что он
автоматически перестраивать, если командная строка для построения заданной цели изменилась. Но
используя $? переменная может вызвать проблемы, потому что каждый раз, когда библиотека обновляется,
команда сборки отличается. (Вы можете подавить это, используя
": build_check ignore_action"; подробности см. в makepp_build_check.)

· Обновление архива вместо его перестройки сделает невозможным выполнение makepp.
правильно поместите файл в кеш сборки (подробности см. в makepp_build_cache).

Иногда вы можете обнаружить, что перечисление всех файлов - это немного, если больно, особенно если
проект находится в стадии бурного развития и список файлов постоянно меняется. Это
Может быть проще построить библиотеку с использованием подстановочных знаков, например:

libmine.a: $ (only_targets * .o)
& rm $ (вывод)
$ (AR) cr $ (выход) $ (входы)

Это ставит все .o файлы в текущем каталоге в библиотеку. Подстановочный знак
соответствует любому .o файл, который существует или может быть создан, поэтому он будет работать, даже если файлы не
еще существуют.

Функция only_targets используется для исключения .o файлы, у которых нет соответствующих
исходных файлов больше нет. Предположим, у вас есть файл с именем xyz.c что вы вкладывали в свой
библиотека. Это означает, что есть xyz.o файл валяется. Теперь вы удаляете xyz.c
потому что он устарел, но вы забыли удалить xyz.o. Без "only_targets"
Функция, xyz.o все равно будет включен в список .o файлы, включенные в библиотеку.

Строительство a динамический библиотека

Процесс создания динамических библиотек полностью зависит от системы. Я бы очень
рекомендую использовать libtool для создания динамической библиотеки (см.
<http://www.gnu.org/software/libtool/>), поэтому вам не нужно придумывать, как это сделать на
вашей платформе, и чтобы ваш make-файл продолжал работать, даже когда вы переключаетесь на
разные ОС. Подробности смотрите в документации libtool. Вот пример Makefile:

LIBTOOL: = libtool

libflick.la: $ (only_targets * .lo)
$ (LIBTOOL) --mode = ссылка $ (CC) $ (входы) -o $ (выход)

% .lo:% .c
$ (LIBTOOL) --mode = compile $ (CC) $ (CFLAGS) $ (ВКЛЮЧАЕТ) -c $ (ввод) -o $ (вывод)

Строительство on несколько различный и машины всегда новые для производства лучших продуктов. or сетей
Одна из самых неприятных проблем с make-файлами заключается в том, что они почти никогда не работают, когда вы
переключиться на другую машину или в другую сеть. Если ваши make-файлы должны работать
каждая возможная машина на планете, тогда вам, вероятно, понадобится какая-то конфигурация
сценарий. Но если вам нужно работать только на нескольких разных машинах, есть несколько способов.
вы можете подойти к этой проблеме:

Используйте a различный включают файл in Найти домен средах

В начале каждого make-файла вы можете включить такую ​​строку:

включить system_defs.mk

Файл system_defs.mk обычно располагаются в разных местах для каждого
среда. Если вы хотите, чтобы ваши каталоги сборки были одинаковыми на всех машинах, поместите
system_defs.mk в каталоге над каталогами сборки или укажите путь включения
для makepp с помощью параметра командной строки "-I".

Обычно это довольно болезненно, но это хорошо работает, если существует огромное количество
различия.

Используйте if отчетность

Это самый уродливый способ сделать это, но обычно он работает.

i386
CC: = gcc
еще ifsys sun4u
CC: = cc
еще ifsys hpux11
СС = с89
ENDIF

Если все, что вам нужно сделать, это найти несколько программ или библиотек или включить файлы в разные
мест, могут быть способы получше (см. ниже).

найти_программа, первый_доступный, найти файл

Эти функции могут выполнять поиск в различных каталогах вашей системы, чтобы найти
соответствующие файлы. Это, конечно, не так мощно, как скрипт конфигурации, но я считаю его
полезный. Например, я делаю следующее:

CXX; = $ (программа поиска g ++ c ++ pg ++ cxx CC aCC)
# Выберите первый компилятор C ++, который доступен в PATH.
# (Кстати, если вы вообще не определяете CXX, это
# - это способ определения.)
TCL_INCLUDE; = -I $ (dir_noslash $ (findfile tcl.h, \
/usr/local/stow/tcl-8.4.5-nothread/include \
/usr/include/tcl8.4 / usr / include / tcl \
/net/na1/tcl8.4a3/include /net/na1/tcl8.4a3/include))
# $ (findfile) ищет tcl.h в каждом из указанных
# каталогов и возвращает полный путь. Это тогда
# преобразован в вариант компиляции, удалив
# имя файла (выход из каталога) с префиксом -I.
% .o:% .cpp
$ (CXX) $ (CXXFLAGS) $ (TCL_INCLUDE) $ (вход) -o $ (выход)

TCL_LIB; = $ ((first_available
/usr/local/stow/tcl-8.4.5-nothread/lib/libtcl8.4.so
/usr/lib/libtcl8.4.so /usr/lib/libtcl.so
/net/na1/tcl8.4a3/lib/libtcl8.4.a
/net/na1/tcl8.4a3/lib/libtcl8.4.sl))
# Найдите, где находится библиотека Tcl. Тогда это явно
# указано в команде ссылки:
моя_программа: * .o
$ (CXX) $ (CXXFLAGS) $ (входы) -o $ (выход) $ (TCL_LIB)

взять преимущество of в Perl конфиг информация

Вышеуказанных методов может быть недостаточно, если вам нужна дополнительная информация о
вашей системе, например, существует ли длинный двойной или какой порядок байтов. Тем не мение,
Perl уже вычислил эти вещи, так что вы можете просто использовать его ответы.

Скрипт автоконфигурации Perl делает всю информацию о конфигурации доступной через
хеш% Config. Нет синтаксиса для доступа к хешу Perl непосредственно в makepp, но вы можете
зайдите в Perl и установите скалярные переменные, которые доступны напрямую из makepp:

perl_begin
# Извлечь значения из хэша конфигурации.
использовать Config;
$ CC = $ Config {'cc'}; # Компилятор C, который использовал perl;
$ byteorder_flags = "-DBYTEORDER = $ Config {'byteorder'}";
$ longdouble_defined = $ Config {'d_longdbl'} eq 'определить';
$ CFLAGS_for_shared_libs = $ Config {'cccdlflags'};
$ LDFLAGS_for_shared_libs = $ Config {'ccdlflags'};
perl_end

Кроме того, после того, как вы выполнили команду 'use Config', вы можете использовать оператор «$ (perl)», например
это:

SHARED_LIB_EXTENSION: = $ (Perl $ Config {'dlext'})

Введите «perldoc Config», чтобы узнать, какая информация доступна через хэш% Config.

Конфигурация Perl - хорошее место для получения информации о целочисленных типах, байтах
порядок и другие вещи, для поиска которых обычно требуется отдельный сценарий конфигурации. Некоторые из
его информация, относящаяся к наличию вещей в файловой системе, может не быть
действительный. Например, $ Config {'cc'} относится к компилятору C, с помощью которого был создан perl,
который может быть не тем компилятором C, который вы хотите использовать. На самом деле, может даже не существовать
в вашей системе, поскольку вы, вероятно, установили Perl через бинарный пакет.

Советы для через подстановочные
Согласование Найти файлов кроме a определенный подмножество

Подстановочные знаки Makepp в настоящее время не могут сопоставить все файлы кроме определенный
набор, но вы можете сделать это с помощью комбинации функций.

Например, предположим, что у вас есть тестовая программа для каждого модуля в библиотеке, но у вас ее нет.
хотите включить тестовые программы в библиотеку. Если все тестовые программы начинаются с
тестXNUMX, то вы можете исключить их следующим образом:

libproduction.a: $ (filter_out test *, $ (подстановочный знак * .o))

Функции «$ (filter)» и «$ (filter_out)» представляют собой очень мощный набор фильтров для выполнения
всевозможные операции пересечения и разности множеств. Например,

SUBDIRS; = $ (filter_out * test * * $ (ARCH) *, $ (оболочка find. -Type d -print))
# Возвращает все подкаталоги, в которых нет
# "test" или $ (ARCH) в них.

$ (filter $ (patsubst test_dir / test _%. o,% .o, $ (wildcard test_dir / *. o)), \
$ (подстановочный знак * .o))
# Возвращает список файлов .o в текущем
# каталог, для которого есть соответствующий
# test _ *. o файл в подкаталоге test_dir.
$ (filter_out $ (patsubst man / man3 /%. 3,% .o, $ (подстановочный знак man / man3 / *. 3)), \
$ (подстановочный знак * .o))
# Возвращает список файлов .o в текущем
# каталог, для которого нет справочной страницы
# с тем же именем файла в подкаталоге man / man3.

. домен "$ (only_targets )" функция в ликвидировать несвежий .o файлов

Предположим, вы создаете программу или библиотеку с помощью такой команды сборки:

программа: * .o
$ (CC) $ (входы) -o $ (выход)

Предположим, вы удалили исходный файл. Если вы забыли удалить соответствующий .o файл,
он по-прежнему будет связан, хотя возможности его создания больше нет. в
в будущем makepp, вероятно, распознает эту ситуацию автоматически и исключит ее из
список подстановочных знаков, но в настоящее время вы должны указать ему исключить его вручную:

программа: $ (only_targets * .o)
$ (CC) $ (входы) -o $ (выходы)

Makepp не знает способа собрать устаревший .o файл больше, так как его исходный файл
ушел, поэтому функция «$ (only_targets)» исключит его из списка зависимостей.

Советы для с разными каталоги
Одной из основных причин написания makepp было упрощение обработки нескольких
каталоги. Makepp может комбинировать команды сборки из нескольких make-файлов, поэтому он может
правильно работать с правилом в одном make-файле, который зависит от файла, созданного
другой make-файл.

Что в do in место of рекурсивный сделать

Makepp поддерживает рекурсивный make для обратной совместимости, но настоятельно рекомендуется
Что Вы не используй это. Если вы не знаете, что это, хорошо.

См. «Лучшая система для иерархических сборок» в makepp, чтобы узнать, почему вы не хотите
используйте рекурсивный make или выполните поиск в Интернете по запросу "рекурсивный make считается вредным".

Вместо того, чтобы делать рекурсивную команду make, чтобы сделать цель "все" в каждом make-файле, это
обычно проще позволить makepp определить, какие цели на самом деле нужно создать.
Кроме того, если вы поместите все свои .o и файлы библиотеки в том же каталоге, что и
makefiles, то makepp автоматически определит, какие файлы make тоже нужны -
единственное, что необходимо, это сделать список необходимых файлов на верхнем уровне.
для последнего шага связывания. См. Примеры ниже.

один Makefile для каждый каталог: безоговорочно погрузка

Самый распространенный способ работы с несколькими каталогами - это поместить make-файл в каждый каталог.
который описывает, как построить все в этом каталоге или из него. Если вы положите .o файлы в
в том же каталоге, что и исходные файлы, затем неявная загрузка (см. «Неявная загрузка» в
makepp_build_algorithm) автоматически найдет все файлы сборки. Если вы положите свой .o
файлы в другом каталоге (например, в подкаталоге, зависящем от архитектуры), то вы
вероятно, придется загрузить все соответствующие make-файлы с помощью оператора load_makefile.

Вот пример make-файла верхнего уровня для иерархии каталогов, которая использует неявную загрузку.
для создания программы, состоящей из множества разделяемых библиотек (но см. «Вам действительно нужен
библиотека? "в makepp_cookbook, потому что создание программы из кучи разделяемых библиотек
не обязательно хорошая идея):

# Makefile верхнего уровня:
program: main.o ** / *. la # Ссылка на разделяемые библиотеки из всех подкаталогов.
$ (LIBTOOL) --mode = ссылка $ (CC) $ (CFLAGS) $ (входы) -o $ (выход) $ (LIBS)

Это почти все, что вам нужно в make-файле верхнего уровня. В каждом подкаталоге вы
вероятно сделал бы что-то вроде этого:

# Makefile в каждом подкаталоге:
include standard_defs.mk # Поиск., .., ../ ..и т. д., пока он
# находит указанный включаемый файл.
# здесь переопределить некоторые определения переменных
SPECIAL_FLAGS: = -do_something_different

Каждый make-файл, вероятно, может быть почти таким же, если команды для создания целей
очень похожи.

Наконец, вы должны поместить следующее в стандарт_defs.mk файл (который, вероятно, должен
находиться в каталоге верхнего уровня):

# Общие настройки переменных и правила сборки для всех каталогов.
CFLAGS: = -g -O2
INCLUDE_DIR: = $ (find_upwards включает)
# Поиски., .., ../ ..и т. д. для файла или
# каталог с именем includes, поэтому, если вы поместите
# все ваши включаемые файлы, это будет
# Найди их.
ВКЛЮЧАЕТ: = -I $ (INCLUDE_DIR)

% .lo:% .c
$ (LIBTOOL) --mode = compile $ (CC) $ (CFLAGS) $ (ВКЛЮЧАЕТ) -c $ (ввод) -o $ (вывод)

lib $ (относительное_то., ..). la: $ (only_targets * .lo)
$ (LIBTOOL) --mode = ссылка $ (CC) $ (CFLAGS) -o $ (выход) $ (входы)
# $ (relative_to., ..) возвращает имя текущего
# подкаталог относительно верхнего уровня
# подкаталог. Итак, если это make-файл xyz / Makefile,
# это правило построит xyz / libxyz.la.

# Публикация общедоступных включаемых файлов в подкаталог верхнего уровня:
$ (INCLUDE_DIR) / public _%. H: public _%. H
: build_check symlnk
& ln -fr $ (ввод) $ (вывод)

один Makefile для каждый каталог: явный погрузка

Если вы хотите поставить все свои .o файлы в подкаталог, зависящий от архитектуры, затем
приведенный выше пример следует изменить, чтобы он выглядел примерно так:

# Makefile верхнего уровня:
MAKEFILES: = $ (wildcard ** / Makeppfile) # Список всех подкаталогов в
# получить make-файлы из.

load_makefile $ (MAKEFILES) # Загрузить их все.

include standard_defs.mk # Получить команду компиляции для main.o.

программа: $ (ARCH) /main.o * / ** / $ (ARCH) / *. la
$ (LIBTOOL) --mode = ссылка $ (CC) $ (CFLAGS) $ (входы) -o $ (выход) $ (LIBS)
# * / ** / $ (ARCH) исключает подкаталог
# $ (ARCH), где мы не хотим строить
# общая библиотека.

Каждый make-файл будет таким же, как и раньше:

# Makefile в каждом подкаталоге:
включить standard_defs.mk
# ... здесь переопределяются переменные

И, наконец, стандарт_defs.mk будет содержать что-то вроде следующего:

# Общие настройки переменных и правила сборки для всех каталогов.
ARCH; = $ (оболочка uname -s) - $ (оболочка uname -m) - $ (оболочка uname -r)
# Иногда люди используют только $ (shell uname -m), но
# это будет то же самое для FreeBSD и Linux на
# x86. -R не очень полезен в Linux,
# но важно для других ОС: бинарные файлы для
# SunOS 5.8 обычно не работает с SunOS 5.7.
& mkdir -p $ (ARCH) # Убедитесь, что выходной каталог существует.
CFLAGS: = -g -O2
INCLUDE_DIR: = $ (find_upwards включает)
# Поиски., .., ../ ..и т. д. для файла или
# каталог с именем includes, поэтому, если вы поместите
# все ваши включаемые файлы, это будет
# Найди их.
ВКЛЮЧАЕТ: = -I $ (INCLUDE_DIR)

$ (ARCH) /%. Lo:% .c
$ (LIBTOOL) --mode = compile $ (CC) $ (CFLAGS) $ (ВКЛЮЧАЕТ) -c $ (ввод) -o $ (вывод)

$ (АРКА)/ Lib$ (относительное_то., ..). la: $ (only_targets * .lo)
$ (LIBTOOL) --mode = ссылка $ (CC) $ (CFLAGS) -o $ (выход) $ (входы)
# $ (relative_to., ..) возвращает имя текущего
# подкаталог относительно верхнего уровня
# подкаталог. Итак, если это make-файл xyz / Makefile,
# это правило построит xyz / $ (ARCH) /libxyz.la.

# Скопируйте общедоступные включаемые файлы в каталог include верхнего уровня:
$ (INCLUDE_DIR) / public _%. H: public _%. H
& cp $ (ввод) $ (вывод)

Автоматически изготовление домен Makefiles

Если все ваши make-файлы очень похожи (как в приведенном выше примере), вы можете указать Makepp
чтобы построить их автоматически, если они не существуют. Просто добавьте следующее в свой верхний уровень
make-файл:

SUBDIRS: = $ (filter_out нежелательный_каталог1, нежелательный_каталог2, $ (подстановочный знак * / **))
$ (foreach) / Makeppfile:: foreach $ (SUBDIRS)
& echo "include standard_defs.mk" -o $ (вывод)
& echo "_include additional_defs.mk" -o >> $ (вывод)
# Если файл additional_defs.mk существует, то
# он будет включен, но если его не существует,
# оператор _include будет проигнорирован.

Теперь сами make-файлы будут построены автоматически.

один Makefile только at домен топ уровень

Если все ваши make-файлы идентичны, вы можете спросить: зачем мне создавать make-файлы на каждом
уровень? Почему бы не поместить все это в make-файл верхнего уровня?

Да, это можно сделать. Главный недостаток в том, что становится сложнее указать
различные варианты сборки для каждого подкаталога. Второй недостаток заключается в том, что ваш
makefile, вероятно, станет труднее читать.

Вот пример того, как это сделать:

# Makefile верхнего уровня для иерархии каталогов. Строит программу
# из набора разделяемых библиотек в качестве примера. (См. Предостережения выше
# почему вы можете захотеть использовать инкрементное связывание или другое
# подход, а не общие библиотеки.)
makepp_percent_subdirs: = 1 # Разрешить% сопоставлять несколько каталогов.
SUBDIRS: = $ (filter_out * CVS * другие-нежелательные_диры $ (подстановочный знак **))
CFLAGS: = -g -O2
ВКЛЮЧАЕТ: = -Iincludes

% .lo:% .c
$ (LIBTOOL) --mode = compile $ (CC) $ (ВКЛЮЧАЕТ) $ (CFLAGS) -c $ (ввод) -o $ (вывод)

$ (foreach)/ Lib$ (notdir $ (foreach)). la: $ (foreach) / *. lo: foreach $ (SUBDIRS)
$ (LIBTOOL) --mode = ссылка $ (CC) $ (CFLAGS) -o $ (выход) $ (входы)
# Правило сделать все библиотеки.

программа: main.o ** / *. la
$ (LIBTOOL) --mode = ссылка $ (CC) $ (CFLAGS) -o $ (выход) $ (входы)

включает / $ (notdir $ (foreach)): $ (foreach): foreach ** / public _ *. h
& cp $ (ввод) $ (вывод)
# Пример правила для публичного копирования
# доступные файлы .h в нужное место.

A чистым цель

Традиционные make-файлы содержат чистую цель, которая позволяет удалить все, что было
построен. Есть три причины, по которым вам не следует делать это с помощью makepp:

1. Makepp делает все возможное, чтобы обеспечить правильную сборку. Так что отчаянное "я не
знай, что не так », заставлявшие вас начинать с нуля, уходит в прошлое.

2. Иногда люди пытаются сэкономить время, делая сразу две противоречивые вещи:
"очистить все". Это может сбить с толку систему умных подстановочных знаков makepp, потому что она
сначала узнайте факты, прежде чем что-либо делать. Затем следует чистое действие, которое делает
не сообщать makepp, что он делает (на самом деле он не может, потому что что-то отменяет -
вопреки тому, для чего предназначен инструмент сборки). Затем идет "все", но последние файлы,
которые там, где есть, таинственным образом исчезли.

3. Есть команда makeppclean, которая делает то же самое, но более эффективно.

Тем не менее, мы сохраняем этот исторический раздел, поскольку он кое-что рассказывает вам о
как работает makepp: Фальшивая цель под названием "clean" - это просто название набора команд для
удалите все файлы, полученные в результате процесса make. Обычно чистая цель выглядит
что-то вроде этого:

$ (фиктивная чистота):
& rm -fm $ (подстановочный знак * .o .makepp_log)
# -m и .makepp_log избавляются от всего мусора makepp.

Вместо явного перечисления файлов, которые вы хотите удалить, вы также можете указать makepp
удалите все, что он умеет строить, вот так:

$ (фиктивная чистота):
& rm -fm .makepp_log $ (только_назначения *)

Это имеет то преимущество, что если какой-либо из ваших исходных файлов может быть построен из других файлов,
они тоже будут удалены; с другой стороны, несвежий .o файлы (файлы, которые раньше были
buildable, но исходный файл которого был удален) не будет удален.

Если у вас есть сборка, которая включает в себя make-файлы в нескольких разных каталогах, ваш главный
make-файл уровня может ссылаться на "чистую" цель (или любую другую фальшивую цель) в другом
make-файл:

# Makefile верхнего уровня
SUBDIRS: = sub1 sub2

# правила сборки здесь

# Очистить после сборки:
$ (фальшивая чистка): $ (ПОДКАТУСЫ) / чистая
& rm -fm .makepp_log $ (только_назначения *)

В качестве альтернативы вы можете поместить свою "чистую" цель только в make-файл верхнего уровня и получить ее
обработать все каталоги следующим образом:

$ (фиктивная чистота):
& rm -fm $ (только_цели ** / *)

. механизм Qt мок препроцессор
В этом примере показан make-файл для служебной программы, использующей библиотеку графического интерфейса пользователя Qt от Nokia (см.
<http://qt.nokia.com>). Единственное, что здесь немного необычно, так это то, что вы
должен запускать препроцессор с именем «moc» для большинства файлов «.h», содержащих определения виджетов,
но вы не хотите запускать «moc» для любых файлов «.h», которые не используют макрос «Q_OBJECT».

Автоматически определения который файлов необходимость мок файлов

Вы, конечно, можете просто перечислить все файлы с расширением ".h", для которых нужно запустить "moc".
Однако, если вы быстро разрабатываете новые виджеты, это может быть неприятно для
продолжайте обновлять список в make-файле. Вы можете обойти необходимость перечисления moc
модули явно с чем-то вроде этого:

MOC: = $ (QTDIR) / bin / moc
МОДУЛИ: = любые модули, которые у вас есть в вашей программе
MOC_MODULES: = $ (patsubst% .h, moc_%, $ (& grep -l / Q_OBJECT / * .h))
# Сканирует все файлы .h на наличие макроса Q_OBJECT.

my_program: $ (МОДУЛИ) .o $ (MOC_MODULES) .o
$ (CXX) $ (входы) -o $ (выход)

moc _%. cxx:% .h # Создает файлы moc из файлов .h.
$ (MOC) $ (ввод) -o $ (вывод)

% .o:% .cxx
$ (CXX) $ (CXXFLAGS) -c $ (ввод) -o $ (вывод)

Этот подход сканирует каждый из ваших .h файлы каждый раз при запуске makepp, ища
Макрос «Q_OBJECT». Звучит дорого, но, вероятно, это не займет много времени. (В .h
файлы все равно должны быть загружены с диска в процессе компиляции, поэтому они будут
быть в кэше.)

#включают домен .moc файл

Другой подход - "# включить" вывод препроцессора "moc" в ваш виджет.
файл реализации. Это означает, что вы должны не забыть написать "#include", но в нем
преимущество в том, что требуется компилировать меньше модулей, и поэтому компиляция выполняется быстрее.
(Для большинства компиляций C ++ большая часть времени тратится на чтение файлов заголовков и
вывод препроцессора должен включать почти столько же файлов, сколько ваш виджет
в любом случае.) Например:

// мой_виджет.h
class MyWidget: public QWidget {
Q_OBJECT
// ...
}

// мой_виджет.cpp

#include "my_widget.h"
#include "my_widget.moc" // my_widget.moc - это результат
// препроцессор moc.
// Прочие вещи реализации здесь.
MyWidget :: MyWidget (QWidget * parent, const char * name):
QWidget (родитель, имя)
{
// ...
}

Теперь вам нужно иметь правило в вашем make-файле для создания всех файлов ".moc", например:

MOC: = $ (QTDIR) / bin / moc
# Правило создания файлов .moc:
% .moc:% .h
$ (MOC) $ (ввод) -o $ (вывод)

Makepp достаточно умен, чтобы понять, что ему нужно создать my_widget.moc, если это не так.
уже существуют или устарели.

Я обычно использую второй подход, потому что он ускоряет компиляцию.

Замены для устарела сделать идиомы
МАКЕСМДГОАЛС

Иногда в make-файле есть правила, зависящие от того, какую цель они создают,
с помощью специальной переменной MAKECMDGOALS. Например, иногда встречаются такие вещи, как
это:

ifneq ($ (производство фильтров, $ (MAKECMDGOALS)),)
CFLAGS: = -O2
еще
CFLAGS: = -g
ENDIF

Это будет нормально работать с makepp. Однако я рекомендую не использовать "MAKECMDGOALS" для таких
случаях (как и руководство GNU). Вам лучше положить оптимизированные и
отладочно-скомпилированный .o файлы в разных каталогах, или давая им разные префиксы, или
суффиксы или использование репозиториев, чтобы хранить их отдельно.

Вероятно, единственный раз, когда вы действительно можете захотеть сослаться на «MAKECMDGOALS», - это если он
занимает много времени, чтобы загрузить ваши make-файлы, и вам это не нужно для вашей "чистой" цели
(но вам не нужна чистая цель). Например,

ifneq ($ (MAKECMDGOALS), чистый)
load_makefile $ (подстановочный знак ** / Makeppfile)
еще
no_implicit_load. # Запретить автоматическую загрузку любых других make-файлов.
ENDIF

$ (фиктивная чистота):
& rm -f $ (подстановочный знак ** / *. o)

рекурсивный сделать в строить in различный каталоги

См. «Советы по использованию нескольких каталогов» в makepp_cookbook.

рекурсивный сделать в изменение ценностное of a переменная

Некоторые make-файлы повторно вызывают себя с другим значением переменной, например, debug
цель в следующем фрагменте make-файла

.PHONY: все отладки

оптимизировано:
$ (MAKE) программа CFLAGS = -O2

отлаживать:
$ (MAKE) программа CFLAGS = -g

программа: ао бо
$ (CC) $ (CFLAGS) $ ^ -o $ @

% .o:% .c
$ (CC) $ (CFLAGS) -c $ <-o $ @

Если пользователь вводит «сделать отладку», программа строит программу в режиме по умолчанию с включенной отладкой.
а не с оптимизацией.

Лучший способ сделать это - создать две разные программы с двумя разными наборами
объектные файлы, например:

CFLAGS: = -O2
DEBUG_FLAGS: = -g
МОДУЛИ: = ab

программа: $ (МОДУЛИ) .o
$ (CC) $ (CFLAGS) $ (входы) -o $ (выход)

отладка / программа: отладка / $ (МОДУЛИ) .o
$ (CC) $ (DEBUG_FLAGS) $ (входы) -o $ (выход)

% .o:% .c
$ (CC) $ (CFLAGS) -c $ (ввод) -o $ (вывод)

отладка /%. o:% .c
$ (CC) $ (DEBUG_FLAGS) -c $ (ввод) -o $ (вывод)

$ (фальшивая отладка): отладка / программа

Преимущество этого способа состоит в том, что (а) вам не нужно все перестраивать, когда вы
переключиться с отладки на оптимизированную и обратно; (б)

Вышесказанное можно написать несколько более кратко, используя репозитории. Следующий
makefile в точности эквивалентен:

репозиторий отладка =. # Делает подкаталог отладки как копию
# текущий подкаталог.
load_makefile отладка CFLAGS = -g
# Переопределить CFLAGS при вызове в подкаталоге отладки
CFLAGS: = -O2 # Значение CFLAGS при вызове в этом подкаталоге

программа: ао бо
$ (CC) $ (CFLAGS) $ ^ -o $ @

% .o:% .c
$ (CC) $ (CFLAGS) -c $ <-o $ @

$ (фальшивая отладка): отладка / программа
# Если пользователь набирает "makepp debug", строит
# отладка / программа вместо программы.

Прочее Советы
Как do I строить one часть по-разному всего однажды?

Makepp затрудняет это, потому что результат противоречит правилам.
Но есть ситуации, когда вам это может понадобиться, например, чтобы скомпилировать только один модуль с
тяжелая отладочная информация. Вы можете добиться этого в два этапа, сначала построив
зависимость отдельно, а затем исключив ее из фазы компоновки:

makepp DEBUG = 3 buggy.o # Скомпилируйте с другим параметром.
makepp --dont-build = buggy.o buggy # Использовать, несмотря на "неправильную" опцию сборки.

Как do I сделать Убедитесь my выходной каталоги существовать?

Вы можете указать правило для создания выходного каталога, а затем убедиться, что каждый файл, который
идет в выходной каталог, зависит от этого. Но обычно проще сделать что-то вроде
это:

# Классический способ
dummy: = $ (тест оболочки -d $ (OUTPUT_DIRECTORY) || mkdir -p $ (OUTPUT_DIRECTORY))
# Обычно это проще, чем делать все файлы зависимыми от
# $ (OUTPUT_DIRECTORY) и наличие правила для его создания.
# Обратите внимание, что вы должны использовать: = вместо =, чтобы заставить его
# выполнить немедленно.
# Альтернативный подход: использование кода Perl, локальная переменная OUTPUT_DIRECTORY
perl_begin
-d $ OUTPUT_DIRECTORY или mkdir $ OUTPUT_DIRECTORY;
perl_end
# Современный способ ничего не делает для существующих каталогов
& mkdir -p $ (КАТАЛОГ_ВЫХ.)

Один из этих операторов должен быть в верхней части вашего make-файла, чтобы они выполнялись
прежде всего, что может понадобиться каталог.

Как do I сила a команду в выполнять on каждую строить?

Самый простой способ - вообще не использовать механизм правил, а просто выполнить его, например
это:

dummy: = $ (дата оболочки> last_build_timestamp)

Или поместите его в блок perl, например:

perl_begin
system («команда на выполнение»);
perl_end

Этот подход имеет тот недостаток, что он будет выполняться, даже если не связанная цель
запущен.

Второй подход - объявить файл фальшивой целью, даже если это настоящий файл.
Это заставит makepp повторно выполнять команду для сборки каждый раз, но только если она
появляется в списке зависимостей некоторого правила.

Как do I сокращать домен отображается строить команды?

Часто для команд компиляции так много опций, что то, что отображается на
экран нечитаемый. Вы можете изменить то, что отображается, отключив отображение
всю команду, а затем явно распечатать интересную часть команды. Это
легко распечатать только соответствующую часть команды, используя "$ (filter_out)", например
это:

ALL_CFLAGS = $ (CFLAGS) $ (ВКЛЮЧАЕТ) $ (ADDL_CXX_FLAGS) $ (DEBUG_FLAGS)

% .o:% .c
@ & echo $ (notdir $ (CC)) ... \
$ (filter_out -I * $ (ADDL_CXX_FLAGS), $ (ALL_CFLAGS)) \
-c $ (ввод)
@ $ (CC) $ (ALL_CFLAGS) -c $ (ввод) -o $ (вывод)

(Символ «@» перед командой запрещает вывод команды на печать.)

Это позволит вам увидеть большинство интересных опций, но не все
включить каталоги (которых часто бывает очень много!). Если интересующая вас часть
in является смежным в вашей команде, вы также можете использовать функцию "print" (которая добавляет
новая строка, поэтому вам не нужно их несколько):

цель:
@ ... $ (распечатать интересную часть) ...

Как do I конвертировать a файл в зависимости?

Для некоторых малоизвестных форматов файлов не стоит реализовывать сканер. В одном проекте
у нас есть файлы xml, скажем foobar.xml который содержит зависимости для foobar.out:


а
б
c


Мы решили придерживаться этого простого макета, поэтому нам не нужно разбирать xml. С
builtin & sed, вот что мы делаем с тремя простыми заменами для трех типов
линии:

% .d:% .xml
& sed! ! $ (стержень) .out: \\! || с! (. +) ! $$ 1 \\! || с! !# Пустой!' \
$ (вход) -o $ (выход)

включить foobar.d

При попытке включить это сначала производит "foobar.d":

foobar.out: \
а \
б \
с \
# Пустой

Пустая (просто комментарий или действительно пустая) строка позволяет не беспокоиться о конечной
обратная косая черта. Альтернативный вариант создания многострочного списка:

% .d:% .xml
& sed! ! $ (основа) .out: \ $$ ((! || s! !))! || s! <. +?> !! g '\
$ (вход) -o $ (выход)

включить foobar.d

Это дает эквивалент:

foobar.out: $ ((
a
b
c
))

Если вам нужно выполнить более сложное переписывание, определите функцию в make-файле или в
модуль, который вы включаете. Например, undefining $ _ пропустит строки ввода:

суб мой фильтр {
return undef $ _ if /
мой $ стержень = f_stem;
с! ! $ stem.out: \ $ ((! || s! !))! || s! <. +?> !! g;
}

% .d:% .xml
& sed! ! $ (основа) .out: \ $$ ((! || s! !))! || s! <. +?> !! g '\
$ (вход) -o $ (выход)

включить foobar.d

Используйте makepp_cookbook в Интернете с помощью сервисов onworks.net


Бесплатные серверы и рабочие станции

Скачать приложения для Windows и Linux

Команды Linux

Ad