Продолжение перевода руководства GNU make [1].
Примечание: объяснение некоторых специфических терминов make/makefile см. в разделе "Словарик Makefile", в конце статьи [2].
[7. Операции проверки условий в файлах Makefile]
Проверки условия (conditional) приводят к тому, что часть makefile становится либо работающей, либо игнорируемой в зависимости от значений переменных. Проверки условий могут сравнивать значение одной переменной с другой, или сравнивать значение переменной со строкой константы. Проверки условий управляют тем, что make реально "видит" в makefile, так что их нельзя использовать для управления рецептами во время выполнения.
7.1. Пример проверки условия
Следующий пример говорит make использовать один набор библиотек, если переменная CC равна 'gcc', и другой набор библиотек, если это не так. Это работает путем управления, какой из двух рецептов будет использоваться для правила. В результате 'CC=gcc' в качестве аргумента для make поменяет не только какой компилятор используется, но и какие библиотеки линкуются.
libs_for_gcc = -lgnu
normal_libs =
foo: $(objects)
ifeq ($(CC),gcc)
$(CC) -o foo $(objects) $(libs_for_gcc)
else
$(CC) -o foo $(objects) $(normal_libs)
endif
Эта проверка условия использует 3 директивы: одну ifeq, одну else и одну endif.
Директива ifeq начинает проверку условия и задает условие. Она содержит два аргумента, отделенные запятой и заключенные в круглые скобки. Подстановка значения переменной происходит в момент, когда они сравниваются. Строки файла makefile, которые идут за ifeq, будут работающими, если эти два аргумента совпали; иначе эти строки игнорируются.
Директива else приводит к тому, что следующие за ней строки работающие если два аргумента ifeq не совпали. В примере, приведенном выше, это означает, что вторая альтернатива команды линковки используется всякий раз, когда не используется первая альтернатива. Наличие директивы else в проверке условия не обязательно.
Директива endif завершает проверку условия. Каждая проверка условия должна оканчиваться на endif. За ней идет безусловный текст makefile.
Как иллюстрирует этот пример, проверки условия работают на уровне текста: строки проверки условия обрабатываются как часть makefile или игнорируются, в согласно условию. По этой причине большие синтаксические единицы makefile, такие как правила, могут пересекать начало или конец проверки условия.
Когда у переменной CC значение 'gcc', пример выше дает следующий эффект:
foo: $(objects)
$(CC) -o foo $(objects) $(libs_for_gcc)
Когда у переменной CC любое другое значение (или когда CC пустая, или когда переменная CC не существует), эффект будет следующий:
foo: $(objects)
$(CC) -o foo $(objects) $(normal_libs)
Эквивалентные результаты могут быть получены другим способом, когда в тело проверки условия вставлены присваивания переменной, после чего эта переменная используется безусловно:
libs_for_gcc = -lgnu
normal_libs =
ifeq ($(CC),gcc)
libs=$(libs_for_gcc)
else
libs=$(normal_libs)
endif
foo: $(objects)
$(CC) -o foo $(objects) $(libs)
7.2. Синтаксис проверок условия
Простой синтаксис без else:
conditional-directive
text-if-true
endif
Здесь text-if-true может быть любыми строками текста, которые считаются частью файла makefile, если проверка условия показала true. Если проверка условия вычислена как false, то вместо этого никакой текст не используется.
Сложный синтаксис проверки условия следующий:
conditional-directive
text-if-true
else
text-if-false
endif
.. или:
conditional-directive-one
text-if-one-is-true
else conditional-directive-two
text-if-two-is-true
else
text-if-one-and-two-are-false
endif
Здесь может быть столько предложений "else conditional-directive", сколько это необходимо. Как только какое-то из условий было вычислено как true, сразу подставляются её строки text-if-true, и никакие другие предложения не подставляются; если ни одно из условий не было true, то используется текст text-if-false. Здесь text-if-true и text-if-false могут содержать любое количество строк текста.
Синтаксис проверки условия одинаковый, независимо от того, сложный он или нет; после else или нет. Существует 4 различных директивы для проверки разных условий: ifeq, ifneq, ifdef, ifndef. Вот их таблица:
ifeq (arg1, arg2)
ifeq 'arg1' 'arg2'
ifeq "arg1" "arg2"
ifeq "arg1" 'arg2'
ifeq 'arg1' "arg2"
Ссылки на все переменные в arg1 и arg2 расширяются и сравниваются. Если они идентичны, то эффективен text-if-true; иначе эффективен text-if-false, если он имеется.
Вы часто можете захотеть проверить переменную, что у неё не пустое значение. Когда значение является результатом сложны расширений переменных и функций, расширения которые вы посчитали пустыми могут содержать символы пробела, и поэтому могут не считаться пустыми. Однако вы можете использовать функцию strip (см. 8.2. Функции для подстановки и анализа строк), чтобы избежать интерпретации пробела как непустое значение. Например:
ifeq ($(strip $(foo)),)
text-if-empty
endif
.. вычислит text-if-empty, даже если расширение $(foo) содержит символы пробела.
ifneq (arg1, arg2)
ifneq 'arg1' 'arg2'
ifneq "arg1" "arg2"
ifneq "arg1" 'arg2'
ifneq 'arg1' "arg2"
Ссылки на все переменные в arg1 и arg2 расширяются и сравниваются. Если они НЕ идентичны, то эффективен text-if-true; иначе эффективен text-if-false, если он имеется.
ifdef variable-name
Форма ifdef берет в качестве аргумента имя переменной, а не ссылку на переменную. Если переменная имеет не пустое значение, то эффективен text-if-true; иначе эффективен text-if-false, если он имеется. Переменные, которые никогда не были определены, имеют пустое значение. Текст variable-name расширяется, так что он может быть переменной или функцией, которая расширяется до имени переменной. Например:
bar = true
foo = bar
ifdef $(foo)
frobozz = yes
endif
Здесь ссылка на переменную $(foo) расширяется, давая bar, которая считается именем переменной. Переменная bar не расширяется, однако её значение проверяется, чтобы определить, является ли она непустой.
Обратите внимание, что ifdef проверяет только, имеет ли переменная значение. Директива ifdef не разворачивает переменную, чтобы увидеть, является ли её значение непустым. Как следствие тесты, использующие ifdef, возвратят true для всех определений, кроме таких, как foo =. Чтобы проверить на пустое значение, используйте ifeq ($(foo),). Например,
bar =
foo = $(bar)
ifdef foo
frobozz = yes
else
frobozz = no
endif
.. установит 'frobozz' значением 'yes', в то время как:
foo =
ifdef foo
frobozz = yes
else
frobozz = no
endif
.. установит 'frobozz' значением 'no'.
ifndef variable-name
Если у переменной variable-name пустое значение, то эффективен text-if-true; иначе эффективен text-if-false, если он присутствует. Правила для расширения и тестирования variable-name идентичны директиве ifdef.
Дополнительные пробелы разрешены и игнорируются в начале строки директивы проверки условия, однако символ табуляции не допускается (если строка начинается на tab, то она считается частью рецепта для правила). Помимо этого дополнительные пробелы или символы табуляции могут быть вставлены без какого-то влияния в любом месте, кроме как внутри имени директивы или внутри аргумента. В конце строки может появиться начинающийся на '#' комментарий.
Двумя другими директивами, которые играют роль в проверке условия, являются else и endif. Каждая из этих них записывается одним словом, без аргументов. В начале строки допускаются и игнорируются дополнительные пробелы, а в конце - пробелы или знаки табуляции. В конце строки может появиться комментарий, начинающийся с '#'.
Проверки условия влияют на то, какие строки makefile использует make. Если условие true, то make считывает строки text-if-true как часть makefile; если условие false, то make полностью игнорирует эти строки. Отсюда следует, что синтаксические единицы makefile, такие как правила, могут быть безопасно разделены по началу или концу условия.
Утилита make вычисляет условия, когда читает makefile. Следовательно, вы не можете использовать автоматические переменные в тестах условий, потому что они не определены до запуска рецептов (см. 10.5.3. Автоматические переменные make).
Во избежание недопустимой путаницы не разрешается начинать проверку условия в одном makefile и заканчивать в другом. Тем не менее вы можете написать директиву include внутри проверки условия, если не пытаетесь завершить условие внутри подключенного файла.
7.3. Проверка флагов
Вы можете написать проверку условия для анализа опций командной строки (флагов), таких как '-t', используя переменную MAKEFLAGS вместе с функцией findstring (см. 8.2. Функции для подстановки и анализа строк). Это полезно, когда команды touch недостаточно, чтобы представить файл обновленным.
Вспомним, что MAKEFLAGS поместит все однобуквенные опции (такие как '-t') в первое слово, и оно будет пустое, если не было предоставлено ни одной однобуквенной опции. Чтобы с этим работать, полезно добавить значение в самом начале, чтобы гарантировать наличие этого слова: например '-$(MAKEFLAGS)'.
Функция findstring определяет, имеется ли одна строка внутри другой как часть строки. Если вы хотите проверить наличие флага '-t', то используйте 't' в качестве первой строки параметра findstring, и первое слово MAKEFLAGS в качестве второй строки параметра (первое слово извлекается функцией firstword).
Вот пример, как организовать использование 'ranlib -t' для завершения маркировки файла архива, что он обновленный:
archive.a: ...
ifneq (,$(findstring t,$(firstword -$(MAKEFLAGS))))
+touch archive.a
+ranlib -t archive.a
else
ranlib archive.a
endif
Префикс '+' пометит эти строки рецепта как "рекурсивные", чтобы они были выполнены несмотря на от использование флага '-t'. См. 5.7. Рекурсивное использование make.
[8. Функции для преобразования текста]
Функции позволят вам делать обработку текста в makefile, чтобы вычислить файлы, с которыми надо работать, или команд, используемых в рецептах. Функция используется в вызове, где вы предоставляете имя функции вместе с некоторым текстом (аргументы), над которым функция работает. Результат обработки функции подставляется в файле makefile в том месте, где функция была вызвана, точно также как может быть подставлена переменная.
8.1. Синтаксис вызова функции
Вызов функции напоминает вставку ссылки на переменную. Вызов может появляться в любом месте, где может появиться ссылка на переменную, и вызов расширяется по таким же правилам, что и ссылка на переменную. Вызов функции выглядит так:
$(function arguments)
.. или так:
${function arguments}
Здесь function это имя функции, одно из короткого списка имен встроенных функций make. Вы можете также создать свои собственные функции, используя встроенную функцию call.
Под arguments подразумеваются аргументы функции. Они отделяются от имени функции одним или большим количеством пробелов или табуляций, и если аргумент не один, то аргументы отделяются друг от друга запятой. Такие разделители из пробелов и запятых не являются частью значений аргументов. Другой вид разделителей в виде круглых или фигурных скобок, которые вы используете вокруг вызова функции, могут появляться в аргументе только согласованными парами; другие виды разделителей могут появляться по одному. Если сами аргументы содержат либо вызов другой функции, либо ссылки на переменные, то лучше всего использовать один и тот же вид разделителей для всех ссылок; записывайте '$(subst a,b,$(x))', но не '$(subst a,b,${x})'. Причина в более понятном оформлении, и потому, что только один тип разделителя сопоставляется, чтобы найти конец ссылки.
Каждый аргумент расширяется перед тем, как вовлекается функция, если не указано нечто иное, о чем далее. Подстановка осуществляется в том порядке, в котором появляются аргументы.
Специальные символы. При использовании специальных символов в качестве аргументов функции может понадобиться их сокрытие. GNU make не поддерживает экранирование символов с помощью символов обратного слеша или других последовательностей экранирования; однако из-за того, что аргументы разделяются перед их расширением, вы можете скрыть специальные символы путем размещения их в переменных.
Символы, которые может понадобиться скрыть:
• Запятые. • Начальные пробелы в первом аргументе. • Не согласованные круглые или фигурные скобки. • Открывающие круглые или фигурные скобки, если вы не хотите, чтобы они начинали согласованную пару.
Например, вы можете определить переменные comma и space, которые представляют собой изолированные запятую и пробел соответственно, и затем подставить эти переменные туда, куда заходите, примерно так:
comma:= ,
empty:=
space:= $(empty) $(empty)
foo:= a b c
bar:= $(subst $(space),$(comma),$(foo))
# bar теперь 'a,b,c'.
Здесь функция subst заменит каждый пробел на запятую внутри значения foo, и подставит результат.
8.2. Функции для подстановки и анализа строк
Вот несколько функций, работающих с текстом:
$(subst from,to,text)
Выполнит замену текста text: каждое значение from заменяется на значение to. Результат подставляется в месте вызова функции. Например,
$(subst ee,EE,feet on the street)
.. сгенерирует значение 'fEEt on the strEEt'.
$(patsubst pattern,replacement,text)
Ищет разделенные пробелом слова в text, которые совпали с шаблоном pattern, и заменит их на replacement. Здесь pattern может содержать '%', действующий как wildcard, совпадающее с любыми символами в слове. Если replacement также содержит '%', то '%' заменяется на текст, который совпал с '%' в pattern. Слова, которые не совпали с pattern, сохраняются как есть на выходе. Таким способом обрабатывается только первый '%' в pattern и replacement; любые последующие '%' остаются без изменений.
Символы '%' в вызовах функции могут экранироваться предстоящими обратными слешами ('\'). Обратные слеши, которые в противном случае экранировали бы символы '%', могут быть экранированы дополнительными обратными слешами. Обратные слеши, которые экранируют символы '%' или другие обратные слеши, удаляются из шаблона pattern перед тем, как он сравнивается с именами файлов или когда stem подставляется в него. Обратные слеши, которым не угрожает экранирование '%', остаются неизменными. Например, шаблон the\%weird\\%pattern\\ имеет 'the%weird\' перед оперативным символом '%', b 'pattern\\', который идет за ним. Конечные два обратных слеша останутся как есть, потому что они не могут повлиять ни на один символ '%'.
Пробелы между словами складывается в одиночные символы пробела; начальный и завершающий пробелы отбрасываются.
Например,
$(patsubst %.c,%.o,x.c.c bar.c)
.. сгенерирует значение 'x.c.o bar.o'.
Подстановка ссылок (см. 6.3.1. Ссылка с подстановкой) это более простой способ получить эффект функции patsubst:
$(var:pattern=replacement)
.. эквивалентно следующему:
$(patsubst pattern,replacement,$(var))
Второе сокращение упрощает одно из самых распространенных использований patsubst: замена суффикса (расширения) в конце имен файлов.
$(var:suffix=replacement)
.. эквивалентно следующему:
$(patsubst %suffix,%replacement,$(var))
Например, у вас есть список объектных файлов:
objects = foo.o bar.o baz.o
Чтобы получить список соответствующих исходных файлов, вы можете просто написать:
$(objects:.o=.c)
.. вместо более общей формы:
$(patsubst %.o,%.c,$(objects))
$(strip string)
Удалит начальные и конечные пробелы из строки string, и заменит в ней каждую внутреннюю последовательность из одного или нескольких пробелов на одиночный символ пробела. Таким образом, '$(strip a b c )' превратится в 'a b c'.
Функция strip может быть очень полезной, когда используется совместно с проверками условий. Когда сравнивается что-нибудь с пустой строкой '', используя ifeq или ifneq, вы обычно хотите, чтобы строка, состоящая только из пробелов, соответствовала пустой строке (см. 7.3. Проверка флагов).
Таким образом, следующее может потерпеть неудачу, и желаемый результат не получится:
.PHONY: all
ifneq "$(needs_made)" ""
all: $(needs_made)
else
all:;@echo 'Nothing to make!'
endif
Замена ссылки '$(needs_made)' на вызов функции '$(strip $(needs_made))' в директиве ifneq сделает её более надезной.
$(findstring find,in)
Ищет в строке in вхождения сроки find. Если вхождение обнаружено, вернет значение find; иначе вернет пустое значение. Вы можете использовать эту функцию в проверках условия, чтобы обнаружить присутствие определенной подстроки в предоставленной строке. Таким образом, следующие два примера,
$(findstring a,a b c)
$(findstring a,b c)
.. сформируют значения 'a' и '' (пустая строка) соответственно. См. 7.3. Проверка флагов, для практического применения findstring.
$(filter pattern...,text)
Возвратит все слова, разделенные пробелом, содержащиеся в text, которые совпадут с любым из слов шаблонов pattern, без слов, которые не совпали. Шаблоны, записанные с использованием '%', действуют точно так же, как шаблоны при использовании описанной выше функции patsubst.
Функция filter может использоваться для разделения различных типов строк (таких как имен файлов) в переменной. Например:
sources := foo.c bar.c baz.s ugh.h
foo: $(sources)
cc $(filter %.c %.s,$(sources)) -o foo
.. скажет, что foo зависит от foo.c, bar.c, baz.s и ugh.h, однако только foo.c, bar.c и baz.s должны быть указаны в команде для компилятора.
$(filter-out pattern...,text)
Возвратит все разделенные пробелом слова в text, которые не совпали ни с одним словом шаблонов pattern, без слов, которые совпали с одним или большим количеством шаблонов. Это поведение полностью противоположно функции filter.
Например, если у нас:
objects=main1.o foo.o main2.o bar.o
mains=main1.o main2.o
.. то следующее сгенерирует список, который содержит все объектные файлы, не находящиеся в 'mains':
$(filter-out $(mains),$(objects))
$(sort list)
Сортирует список слов в лексическом порядке, с удалением дубликатов строк. Вывод будет списком слов, разделенных пробелами. Таким образом,
$(sort foo bar lose)
.. возвратит значение 'bar foo lose'.
Заметим, что поскольку функция sort удаляет дубликаты, вы можете использовать её для этих целей, если вам не важен порядок сортировки слов.
$(word n,text)
Возвратит n-ное слово строки text. Допустимы значения для n начиная с 1. Если n больше, чем количество слов в тексте, то вернет пустое значение. Например,
$(word 2, foo bar baz)
.. возвратит 'bar'.
$(wordlist s,e,text)
Возвратит список слов в text, начиная со лова s и заканчивая словом e (включительно). Допустимые значения s начинаются от 1; e может начинаться от 0. Если s больше, чем количество слов в text, то возвращенное значение будет пустым. Если e больше, чем количество слов тексте, то возвращаются слова до самого конца text. Если s больше, чем e, то ничего не возвращается. Например,
$(wordlist 2, 3, foo bar baz)
.. возвратит 'bar baz'.
$(words text)
Возвратит количество слов в text. Таким образом, последнее слово text извлекается $(word $(words text),text).
$(firstword names...)
Аргумент names обрабатывается как последовательность слов, отделенных друг от друга пробелом. Возвратит первое слово в последовательности names, остальная часть names игнорируется.
Например,
$(firstword foo bar)
.. вернет результат 'foo'. Хотя $(firstword text) то же самое, что и $(word 1,text), функция firstword сохранена из-за своей простоты.
$(lastword names...)
Аргумент names обрабатывается как последовательность слов, отделенных друг от друга пробелом. Возвратит последнее слово в последовательности слов names.
Например,
$(lastword foo bar)
.. возвратит результат 'bar'. Хотя $(lastword text) это то же самое, что и $(word $(words text),text), функция lastword была добавлена для упрощения и улучшения производительности.
Применение subst и patsubst. Ниже показан реалистичный пример использования subst и patsubst. Предположим, что makefile использует переменную VPATH, чтобы указать список директорий, которые make должна просматривать в поиске файлов prerequisite (см. 4.5.1. VPATH: путь поиска для всех prerequisites). Этот пример показывает, как указать компилятору C искать файлы заголовка в том же самом списке директорий.
Значение VPATH это список директорий, разделенных двоеточием, такой как 'src:../headers'. Сначала функция subst используется для замены двоеточий на пробелы:
$(subst :, ,$(VPATH))
Это сгенерирует 'src ../headers'. Затем patsubst используется для вставки имени каждой директории в флаг '-I'. Они могут быть добавлены к значению переменной CFLAGS, которая автоматически передается компилятору C, примерно так:
override CFLAGS += $(patsubst %,-I%,$(subst :, ,$(VPATH)))
Получится эффект добавления текста '-Isrc -I../headers' к предыдущему значению CFLAGS. Директива override используется для того, чтобы новое значение присваивалось даже если предыдущее значение CFLAGS было указано в аргументе командной строки (см. 6.7. Директива override).
8.3. Функции для имен файлов
Некоторые встроенные функции расширения специально относятся к разбору имен файлов или списков имен файлов.
Каждая из следующих функций выполняет специфическое преобразование имени файла. Аргумент функции обрабатывается как последовательность имен файлов, отделенных друг от друга пробелом (начальный и конечный пробелы игнорируются). Каждое имя файла в последовательности преобразуется одинаково, и результаты склеиваются друг с другом с отделением друг от друга пробелами.
$(dir names...)
Извлекает часть имени файла, относящаяся к директории. Это часть полного имени до последнего прямого слеша, включая его. Если имя файла не содержит слеш, то относящаяся к директории часть будет строка './'. Например,
$(dir src/foo.c hacks)
.. сгенерирует результат 'src/ ./'.
$(notdir names...)
Извлечет из каждой составляющей names все, кроме части имени, относящейся к директории. Если имя файла не содержит слеша, то оно остается без изменений. Иначе удаляется все до слеша включительно.
Имя файла, которое оканчивается на слеш, превращается в пустую строку. Это печально, потому что не означает, что не всегда результат будет содержать такое же количество разделенных пробелами имен файлов, которое имел аргумент names; однако разработчики make не видят другой допустимой альтернативы.
Например,
$(notdir src/foo.c hacks)
.. сгенерирует результат 'foo.c hacks'.
$(suffix names...)
Извлечет суффикс (расширение) из каждого имени файла в names. Если имя файла содержит точку, то суффикс это все, что начинается с последней точки. Иначе суффикс это пустая строка. Это часто означает, что результат может быть пустым, или может содержать меньшее количество элементов, чем содержалось в names.
Например,
$(suffix src/foo.c src-1.0/bar.c hacks)
.. сгенерирует результат '.c .c'.
$(basename names...)
Извлечет базовую часть имени файла, т. е. все, кроме суффикса из каждого имени файла в списке names (имена файлов, разделенные пробелами). Если имя файл содержит точку, то basename это все что идет до последней точки (не включая её). Точки в части директории игнорируются. Если точки нет, то basename это имя файла полностью. Например,
$(basename src/foo.c src-1.0/bar hacks)
.. сгенерирует результат 'src/foo src-1.0/bar hacks'.
$(addsuffix suffix,names...)
Аргумент names это последовательность имен, разделенных пробелами. Значение suffix прибавляется в конец каждого отдельного имени из списка names, и получающиеся более длинные имена выводятся в результат также разделенные одиночными пробелами. Например,
$(addsuffix .c,foo bar)
.. сгенерирует результат 'foo.c bar.c'.
$(addprefix prefix,names...)
Аргумент names это последовательность имен, разделенных пробелами. Значение prefix прикрепляется спереди каждого отдельного имени, и полученные более длинные имена имена выводятся в результат также разделенные одиночными пробелами. Например,
$(addprefix src/,foo bar)
.. сгенерирует результат 'src/foo src/bar'.
$(join list1,list2)
Склеивает попарно два каждый из элементов аргумента list1, list2 друг с другом: первое слово (из каждого аргумента) в склеенной форме передается в результат, второе слово (из каждого аргумента) передается в результат, и так далее, и каждые элементы результата отделяются друг от друга пробелами. Таким образом, n-ое слово результата получается слиянием n-ного слова из каждого аргумента. Если в одном аргументе больше слов, чем в другом, то лишние слова копируются на выход как есть, без изменения.
Например, '$(join a b,.c .o)' сгенерирует 'a.c b.o'.
Лишние пробелы между словами в списках list1, list2 не сохраняются; они заменяются одиночными пробелами.
Эта функция может соединить друг с другом результаты работы функций dir и notdir, чтобы сформировать оригинальный список файлов, который был предоставлен для этих двух функций.
$(wildcard pattern)
Аргумент pattern это шаблон имени файла, обычно содержащий символы wildcard (которые традиционно используются в шаблонах имен файлов шелла). Результатом функции wildcard будет разделенный пробелом список имен существующих файлов, совпавших с шаблоном pattern. См. 4.4. Использование Wildcard в именах файлов.
$(realpath names...)
Для каждого имени файла из списка names на выходе будет возвращено абсолютное каноническое имя. Каноническое имя не содержит внутри себя ни компоненты . или .., ни какие-либо повторяющиеся разделители пути (/) или символические ссылки (symlinks). В случае ошибки возвращается пустая строка. Проконсультируйтесь с документацией realpath(3) для списка возможных случаев ошибки.
$(abspath names...)
Для каждого имени файла из списка names на выходе будет возвращено абсолютное абсолютное имя, которое не содержит внутри себя ни компоненты . или .., ни повторяющиеся разделители пути (/). Обратите внимание, что в отличие от функции realpath, функция abspath не обрабатывает символические ссылки (symlinks) и не требует, чтобы имена файлов относились к существующему файлу или директории. Для проверки существования файла на диске используйте функцию wildcard.
8.4. Функции для проверки условий
Существует 4 функции, предоставляющие расширение для проверок условий. Ключевой аспект этих функций в том, что не все их аргументы изначально расширяются. Будут расширены только те аргументы, которые требуют расширения.
$(if condition,then-part[,else-part])
Функция if предоставляет расширение поддержки проверки условия в контексте функции (в отличие от операторов проверки условий GNU make, таких как ifeq, см. 7.2. Синтаксис проверок условия).
Сначала вокруг первого аргумента condition удаляются все предшествующие и последующие пробелы, затем аргумент расширяется. Если он расширяется в любые не пустые строки, то он вычисляется как true. Если он расширяется в пустую строки, то условие condition считается false.
Если condition вычислено как true, то второй аргумент then-part, вычисляется и используется как результат вычисления всей функции if.
Если condition вычислено как false, то третий аргумент else-part, вычисляется его результата это результат функции if. Если третьего аргумента нет, то функция if вычисляется в ничто (пустая строка).
Обратите внимание, что будет вычислена только then-part или else-part, но не они обе. Таким образом, любая из этих частей могут содержать побочные эффекты (такие как вызовы функции shell, и т. д.).
$(or condition1[,condition2[,condition3...]])
Функция or обеспечивает "короткое замыкание" функции ИЛИ. Каждый аргумент расширяется по порядку. Если аргумент расширен в непустую строку, то обработка останавливается, и результатом функции будет эта строка. Если после того, как все аргументы были расширены, все они получились false (пустые), то результатом функции будет пустая строка.
$(and condition1[,condition2[,condition3...]])
Функция and обеспечивает "короткое замыкание" функции И. Каждый аргумент расширяется по порядку. Если аргумент расширился в пустую строку, то обработка останавливается, и результатом будет пустая строка. Если все аргументы расширились в непустую строку, то результатом функции будет расширение последнего аргумента.
$(intcmp lhs,rhs[,lt-part[,eq-part[,gt-part]]])
Функция intcmp предоставляет поддержку сравнения цифровых чисел. Эта функция не имеет аналогов среди условных makefile-операторов GNU make.
Левая часть lhs и правая часть rhs обе расширяются и парсятся как целые числа по основанию 10. Расширение остальных частей аргумента управляется тем, как сравниваются числовые значения левой и правой части lhs и rhs.
Если аргументов кроме lhs, rhs больше нет, то функция расширится в пустоту, если если lhs и rhs при сравнении не одинаковые, или в их числовое значение, если при сравнении они одинаковые.
Иначе если левая сторона точно меньше чем правая, то функция intcmp вычисляется в расширение третьего аргумента lt-part. Если обе стороны сравнения одинаковые, то функция intcmp вычисляется в расширение четвертого аргумента eq-part. Если левая сторона точно больше правой, то функция intcmp вычисляется в расширение пятого аргумента gt-part.
Если часть gt-part отсутствует, то по умолчанию используется eq-part. Если eq-part отсутствует, то по умолчанию используется пустая строка. Таким образом, оба выражения '$(intcmp 9,7,hello)' и '$(intcmp 9,7,hello,world,)' вычисляются в пустую строк, в то время как '$(intcmp 9,7,hello,world)' (обратите внимание на отсутствие запятой после world) будет вычислено в значение 'world'.
8.5. Функция let
Функция let предоставляет возможность ограничить область действия переменной. Присваивание именованной переменной в выражении let действует только внутри текста, предоставленного выражением let, и это присваивание никак не влияет переменную с таким же именем в из любой внешней области действия.
Дополнительно функция let позволяет распаковать список путем присваивания все не назначенных значений последней именованной переменной.
Синтаксис функции let следующий:
$(let var [var ...],[list],text)
Первые 2 аргумента var и list расширяются до того, как что-то еще будет сделано; обратите внимание, что последний аргумент text не расширяется в тот же момент. Далее каждое слово в расширенном значении list привязывается к каждому из имен переменных var по очереди, при этом последнее име переменной привязывается к остатку расширенного list. Другими словами, первое слово из list привязывается к первой переменной var, второе слово list ко второй переменной var, и так далее.
Если в var больше имен переменных, чем слов в list, то оставшиеся переменные в var устанавливаются в пустые строки. Если же переменных в var меньше, чем слов в list, то последняя переменная var установится во все оставшиеся слова из list.
При выполнении let переменные в var присваиваются как просто расширяемые переменные, см. 6.2. Две разновидности (flavor) переменных.
После того, как все переменные были привязаны таким образом, text расширяется для предоставления результата функции let.
Например, следующий макрос меняет на обратный порядок слов в списке, который был предоставлен в первом аргументе:
reverse = $(let first rest,$1,\
$(if $(rest),$(call reverse,$(rest)) )$(first))
all: ; @echo $(call reverse,d c b a)
.. напечатает a b c d. При первом вызове let расширит $1 в d c b a. Затем first присваивается значение d, и rest присваивается c b a. Это затем расширит оператор if, где $(rest) окажется не пустым, так что приведет к рекурсивному вызову функции reverse со значением rest, которое теперь c b a. Рекурсивный вызов let назначит first в c и rest в b a. Рекурсия продолжится до тех пор, пока let будет вызвана с одиночным значением a. Здесь first будет a, и rest окажется пустой, так что рекурсия прекратиться, вместо этого просто произойдет расширение $(first) и возврат, что добавит b, и так далее.
После завершения вызова reverse переменные first и rest больше не устанавливаются. Если переменные с этими именами существовали ранее, то на них не влияет расширение макроса reverse.
8.6. Функция foreach
Функция foreach подобна функции let, однако очень отличается от других функций. Она приводит к повторяющимся использованиям одной части текста, каждый раз с другой подстановкой для него. Функция foreach напоминает команду for шелла sh, и команду foreach в C-шелле csh.
Синтаксис функции foreach следующий:
$(foreach var,list,text)
Первые два аргумента var и list расширяются до того, как что-то еще будет сделано; обратите внимание, что последний аргумент text не расширяется в тот же момент. Затем для каждого слова расширенного значения list, именованные переменные расширенного значения var устанавливаются в это слово, и text расширяется. Предположительно text содержит ссылки на эту переменную variable, так что её расширение будет каждый раз разное.
В результате text расширяется столько раз, сколько разделенных пробелами слов находилось в list. Множественные расширения text объединяются друг с другом через пробел, чтобы сформировать результат foreach.
Следующий простой пример установит переменную 'files' в список всех файлов в директориях списка 'dirs':
dirs := a b c d
files := $(foreach dir,$(dirs),$(wildcard $(dir)/*))
Здесь text это '$(wildcard $(dir)/*)'. Первое повторение найдет значение 'a' для dir, так что это даст такой же результат, что и '$(wildcard a/*)'; второе повторение даст результат '$(wildcard b/*)'; и третий '$(wildcard c/*)'.
Этот пример дает тот же результат (за исключением установки 'dirs'), что и следующий пример:
files := $(wildcard a/* b/* c/* d/*)
Когда text сложный, вы можете улучшить читаемость предоставлением ему понятного имени с помощью дополнительной переменной:
find_files = $(wildcard $(dir)/*)
dirs := a b c d
files := $(foreach dir,$(dirs),$(find_files))
Здесь для этого мы используем переменную find_files. Простой '=' используется для определения рекурсивно расширяемой переменной, так что её значение содержит фактический вызов функции, повторно расширяемый под управлением foreach; просто расширяемая переменная не подойдет, поскольку wildcard будет вызываться только один раз во время определения find_files.
Как и функция let, функция foreach не оказывает перманентный эффект на переменной var; её значение и вид переменной (flavor) после каждого вызова функции foreach такие же, как были до этого. Другие значения, взятые из list, эффективны только временно, во время выполнения foreach. Переменная var это просто расширяемая переменная во время выполнения foreach. Если var была не определена перед вызовом функции foreach, то она не определена после этого вызова. См. 6.2. Две разновидности (flavor) переменных.
Вы должны быть осторожными при использовании сложных выражений переменных, которые приводят к именам переменных потому что многие странные вещи являются действительными именами переменных, но это вероятно не то, что входит в ваши намерения. Например,
files := $(foreach Esta-escrito-en-espanol!,b c ch,$(find_files))
.. может быть полезным, если значение find_files ссылается на переменную, у которой имя 'Esta-escrito-en-espanol!' (es un nombre bastante largo, no?), но это скорее всего будет ошибкой.
8.7. Функция file
Функция file позволяет makefile записывать или читать из файла. Поддерживается два режима записи: перезапись файла (overwrite), когда текст записывается в начало файла и при этом любое его предыдущее содержимое теряется, и добавление к файлу (append), где текст записывается в конец файла, сохраняя его существующее предыдущее содержание. В обоих случаях файл создается, если он еще не существует. Произойдет фатальная ошибка, если файл не может быть открыт на запись, или если операция записи в файл потерпит неудачу. Функция file расширяется в пустую строку, когда происходит запись в файл.
При чтении из файла функция file расширяется в дословное содержимое файла, за исключением последнего символа newline (если он имеется) который будет вырезан. Попытка прочитать из несуществующего файла расширится в пустую строку.
Синтаксис функции file следующий:
$(file op filename[,text])
При вычислении функции file сначала расширяются все её аргументы, затем открывается файл, на который указывает аргумент filename в режиме, описанном аргументом op.
Оператор op может быть >, чтобы показать перезапись файла новым содержимым, >> чтобы показать добавление к текущему содержимому файла, или < чтобы показать содержимое файла, который будет прочитан. Аргумент filename указывает файл, который записывается или читается. Между этим оператором и именем файла может опционально существовать пробел.
При чтении файла будет ошибкой предоставить значение аргумента text.
При записи файлов значение text будет записано в файл. Если текст text не содержит в конце символ новой строки (newline), то он будет добавлен в конец записываемого text (даже если text пустая строка). Если аргумент text вообще не предоставлен, то ничего не будет записано.
Например, функция file может быть полезной, если ваша система сборки имеет ограничение на размер командной строки, и ваш рецепт запускает команду, которая может принять также аргументы из файла. Многие команды используют соглашение в котором аргумент с префиксом @ указывает файл, содержащий дополнительные аргументы. Тогда вы можете написать свой рецепт следующим образом:
program: $(OBJECTS)
$(file >$@.in,$^)
$(CMD) $(CMDFLAGS) @$@.in
@rm $@.in
Если команда требует, чтобы каждый аргумент был на отдельной строке во входном файле, то вы можете написать свой рецепт примерно так:
program: $(OBJECTS)
$(file >$@.in) $(foreach O,$^,$(file >>$@.in,$O))
$(CMD) $(CMDFLAGS) @$@.in
@rm $@.in
8.8. Функция call
Функция call уникальна тем, что она может использоваться для создания новых параметризованных функций. Вы можете написать сложное выражение в качестве значения переменной, и затем использовать call для её расширения с различными значениями.
Синтаксис функции call следующий:
$(call variable,param,param,...)
Когда утилита make расширяет эту функцию, она назначает каждому параметру param временные переменные $(1), $(2), и так далее. Переменная $(0) будет содержать variable. Не существует ограничения на максимальное количество аргументов. Ограничения на минимум тоже нет, однако пользоваться call без параметров не имеет смысла.
Затем variable расширяется как make-переменная в контексте этих временных присваиваний. Таким образом, любая ссылка на $(1) в значении variable будет разрешаться в первый параметр param применения call.
Обратите внимание, что variable это имя переменной, но не ссылка на эту переменную. Таким образом, не следует использовать '$' или круглые скобки (однако вы можете использовать в имени ссылку на переменную, если имя не должно быть константой).
Если variable это имя встроенной функции, то всегда будет вовлечена встроенная функция (даже если уже также существует make-переменная с таким именем).
Функция call расширяет аргументы param перед присваиванием их временным переменным. Это означает, что значения variable, содержащие ссылки на встроенные функции, имеющие специальные правила расширения, такие как foreach или if, могут работать не так, как ожидалось.
Некоторые примеры помогут это пояснить. Следующий макрос просто меняет порядок своих аргументов:
reverse = $(2) $(1)
foo = $(call reverse,a,b)
Здесь foo будет содержать 'b a'.
А вот этот пример уже интереснее: он определяет макрос для поиска первого вхождения программы в PATH:
pathsearch = $(firstword $(wildcard $(addsuffix /$(1),$(subst :, ,$(PATH)))))
LS := $(call pathsearch,ls)
Теперь переменная LS содержит /bin/ls или что-то подобное.
Функция call может быть вложенной. Каждое рекурсивное вовлечение получает свои собственные локальные значения для $(1), и так далее, которое маскирует значения call более высокого уровня. Вот например реализация функции map:
map = $(foreach a,$(2),$(call $(1),$(a)))
Теперь вы можете отобразить функцию, которая нормально принимает только один аргумент, такой как origin, в несколько значений за один шаг:
o = $(call map,origin,o map MAKE)
.. что завершится значением o, содержащим что-то наподобие 'file file default'.
Последнее предостережение: будьте осторожны при добавлении пробела к аргументам для call. Как и в случае с другими функциями, любой пробел, содержащийся во втором и последующих аргументах, будет сохранен; это может привести к странным последствиям. Как правило безопаснее всего удалить все посторонние пробелы при предоставлении параметров для call.
8.9. Функция value
Функция value предоставит вам способ использовать значение переменной без её расширения. Обратите внимание, это не отменяет расширения, которые уже произошли; например, если вы создаете просто расширяемую переменную, её значение будет расширено во время определения; в этом случае функция value возвратит тот же результат, что и при непосредственном использовании переменной.
Синтаксис функции value следующий:
$(value variable)
Обратите внимание, что variable это имя переменной, а не ссылка на эту переменную. Таким образом, при её написании не следует использовать '$' или круглые скобки (однако вы можете использовать ссылку на переменную в имени, если не хотите, чтобы имя было константой).
Результатом это функции будет строка, содержащая значение variable, без какого-либо выполнения расширения. Например, в этом makefile:
FOO = $PATH
all:
@echo $(FOO)
@echo $(value FOO)
Первая выведенная строка будет ATH, поскольку "$P" расширится как переменная make, в то время как вторая выведенная строка будет текущим значением вашей переменной окружения $PATH, поскольку функция value позволяет избежать расширения.
Функция value чаще всего используется совместно с функцией eval (см. 8.10. Функция eval).
8.10. Функция eval
Функция eval очень необычная: она позволяет определять новые конструкции makefile, которые не константы и являются результатом вычисления других переменных и функций. Аргумент функции eval расширяется, затем результаты этого расширения парсится как синтаксис makefile. Расширенные результаты могут определять новые переменные make, цели неявные правила, и т. д.
Результат функции eval всегда пустая строка; таким образом, она может быть помещена виртуально в любое место makefile, что не приведет к ошибкам синтаксиса.
Важно понимать, что аргумент eval расширяется дважды; сначала функцией eval, затем результаты этого расширения снова расширяются, когда анализируются как синтаксис makefile. Это означает, что вам может понадобиться предоставить дополнительные уровни экранирования для символов "$", когда используете eval. Функция value (см. 8.9. Функция value) может быть иногда полезна в этих ситуациях, чтобы обойти нежелательные расширения.
Ниже показан пример, как может использоваться eval; этот пример комбинирует некоторые концепции и другие функции. Хотя может выглядеть очень сложным такой пример использования eval, вместо того, чтобы просто написать правила, рассмотрите две вещи: во-первых определение шаблона (в PROGRAM_template) может быть гораздо более сложным, чем здесь; и во-вторых, вы можете поместить сложную, "generic" часть этого примера в другой makefile, и затем подключать его во все ваши отдельные файлы makefile. Теперь ваши отдельные makefile станут довольно простыми.
PROGRAMS = server client
server_OBJS = server.o server_priv.o server_access.o
server_LIBS = priv protocol
client_OBJS = client.o client_api.o client_mem.o
client_LIBS = protocol
# Все после этого обычное
.PHONY: all
all: $(PROGRAMS)
define PROGRAM_template =
$(1): $$($(1)_OBJS) $$($(1)_LIBS:%=-l%)
ALL_OBJS += $$($(1)_OBJS)
endef
$(foreach prog,$(PROGRAMS),$(eval $(call PROGRAM_template,$(prog))))
$(PROGRAMS):
$(LINK.o) $^ $(LDLIBS) -o $@
clean:
rm -f $(ALL_OBJS) $(PROGRAMS)
8.11. Функция origin
Функция origin в отличие от большинства других функций тем, что она не оперирует значениями переменных; она говорит вам что-нибудь о переменной. В частности, она говорит вам, откуда она взялась.
Синтаксис функции origin следующий:
$(origin variable)
Обратите внимание, что variable это имя запрашиваемой переменной, а не ссылка на эту переменную. Таким образом вам не следует использовать '$' или круглые скобки при его написании (однако вы можете использовать в имени ссылку на переменную, если хотите, чтобы имя не было константой).
Результат этой функции будет строкой, которая сообщит, как была определена переменная:
'undefined' если переменная variable никогда не была определена.
'environment' если переменная variable была унаследована из окружения, предоставленного для make.
'environment override' если переменная variable была унаследована из окружения, предоставленного для make, и была переназначена установкой переменной в makefile как результат опции '-e' (см. 9.8. Сводка по опциям make).
'file' если переменная variable была определена в makefile.
'command line' если переменная variable была определена в командной строке.
'override' если переменная variable была определена в makefile с помощью директивы override (см. 6.7. Директива override).
'automatic' если переменная variable это автоматическая переменная, определенная для выполнения рецепта для каждого правила (см. 10.5.3. Автоматические переменные make).
Эта информация в первую очередь полезна (кроме вашего любопытства), чтобы определить, хотите ли вы верить значению переменной. Например предположим, что у вас есть makefile-файл foo, который подключает другой makefile-файл bar. Вы хотите, чтобы переменная bletch была определена в bar, если запускаете команду 'make -f bar', даже если окружение содержит определение переменной bletch. Однако если foo определил bletch перед подключением bar, то вы не хотите переопределять это определение. Это можно сделать, используя директиву override в foo, что даст этому определению приоритет над более поздним определением в bar; к сожалению, директива override также переопределит любые определения командной строки. Таким образом, bar может включать в себя:
ifdef bletch
ifeq "$(origin bletch)" "environment"
bletch = barf, gag, etc.
endif
endif
Если переменная bletch была определена в окружении, то это переопределить её.
Если вы хотите переопределить предыдущее определение bletch, если оно пришло из окружения, даже при опции '-e', то вместо этого следует написать:
ifneq "$(findstring environment,$(origin bletch))" ""
bletch = barf, gag, etc.
endif
Здесь переопределение произойдет, если '$(origin bletch)' возвратит либо 'environment', либо 'environment override'. См. 8.2. Функции для подстановки и анализа строк.
8.12. Функция flavor
Функция flavor, наподобие функции origin, не оперирует значениями переменных, и вместо этого сообщает что-то о переменной. А именно: она говорит вам, какой flavor у переменной (см. 6.2. Две разновидности (flavor) переменных).
Синтаксис функции flavor следующий:
$(flavor variable)
Обратите внимание, что variable это имя запрашиваемой переменной, а не ссылка на эту переменную. Поэтому вам не следует использовать '$' или круглые скобки при написании (однако вы можете использовать ссылку на переменную, если хотите, чтобы имя не было константой).
Результат этой функции - строка, идентифицирующая flavor переменной variable:
'undefined' если переменная variable не была определена.
'recursive' если variable это рекурсивно расширяемая переменная (recursively expanded variable).
'simple' если variable это это просто расширяемая переменная (simply expanded variable).
8.13. Функции, управляющие поведением make
Эти функции оправляют тем, как работает make. Обычно они используются для предоставления информации пользователю makefile, или чтобы заставить make остановиться, если была обнаружена некоторая ошибка в окружении.
$(error text...)
Генерирует фатальную (неустранимую) ошибку с выводом сообщения text. Обратите внимание, что ошибка генерируется при каждом вычислении этой функции. Таким образом, если вы поместите эту функцию внутрь рецепта или на правой стороне присваивания рекурсивной переменной, то она не будет вычислена позже. Значение text будет расширено перед тем, как сгенерируется ошибка.
Например,
ifdef ERROR1
$(error error is $(ERROR1))
endif
.. сгенерирует фатальную ошибку во время чтения makefile, если была определена make-переменная ERROR1. Или,
ERR = $(error found an error!)
.PHONY: err
err: ; $(ERR)
.. сгенерирует фатальную ошибку во время работы make, если вовлечена цель err.
$(warning text...)
Эта функция работает почти так же, как функция error, за исключением того, что warning не прекращает работу make. Вместо этого text расширяется, и отобразится результирующее сообщение, но обработка makefile продолжится.
Результатом расширения этой функции будет пустая строка.
$(info text...)
Эта функция ничего не делает, кроме как выводит свое (расширенное) значение аргумента (аргументов) в стандартный вывод. К выводу не добавляется имя файла makefile или номер строки. Результатом расширения этой функции будет пустая строка.
8.14. Функция shell
Функция shell, в отличие от любой другой функции, кроме функции wildcard (см. 4.4.3. Функция wildcard), в том смысле, что она коммуницирует с внешним миром make.
Функция shell предоставляет для make то же самое средство, что и обратные кавычки (backquotes ‘`'), предоставляемое большинством программ шелла: она выполняет расширение команды операционной системы. Это означает, что shell в качестве аргумента берет команду шелла, и расширяется в вывод этой команды. Единственная обработка, которую make производит над результатом shell, это преобразование каждого символа новой строки newline (или пары carriage-return / newline) в одиночный символ пробела. Если это завершающий символ newline (или завершающая последовательность carriage-return и newline), то он просто удаляется.
Команды, запускаемые вызовами функции shell, выполняются, когда вызовы функции расширены (см. 3.7. Как make читает Makefile). Из-за того, что эта функция порождает новый шелл, вы должны тщательно рассмотреть последствия деградации производительности, когда функция shell используется внутри рекурсивно расширяемых переменных по сравнению с просто расширяемыми переменными (см. 6.2. Две разновидности (flavor) переменных).
Альтернативой функции shell является оператор присваивания '!='; он предоставляет подобное поведение, но имеет тонкие отличия (см. 6.5. Установка переменных). Оператор присваивания '!=' включен в более новые стандарты POSIX.
После того, как была использована функция shell или оператор присваивания '!=', их статус выхода помещается в переменную .SHELLSTATUS.
Вот некоторые примеры использования функции shell:
contents := $(shell cat foo)
.. установит содержимое переменной contents в файл foo, с пробелом (вместо символа newline), разделяющим строки файла.
files := $(shell echo *.c)
.. установит переменную files в расширение '*.c'. За исключением случаев, когда make использует очень странный шелл, это даст такой же результат, что и '$(wildcard *.c)' (пока в текущей директории существует как минимум один файл '.c').
Все переменные, которые помечены как экспортируемые, будут также переданы в шелл, запущенный функцией shell. Есть возможность создать цикл расширения переменной, рассмотрим этот makefile:
export HI = $(shell echo hi)
all: ; @echo $$HI
Когда make захочет запустить рецепт, она должна добавить в окружение переменную HI; для этого её необходимо расширить. Значение этой переменной требует вовлечения функции shell, и для её привлечения мы должны создать её окружение. Поскольку HI экспортируется, нам нужно расширить её, чтобы создать её окружение. И так далее. В этом неясном случае make будет использовать значение переменной из окружения, предоставленного make, или иначе пустую строку, если её не было, вместо зацикливания или выдачи ошибки. Это часто то, что вам нужно; например:
export PATH = $(shell echo /usr/local/bin:$$PATH)
Однако было бы проще и намного эффективнее использовать здесь просто расширяемую переменную (':=') в первом месте.
8.15. Функция guile
Если GNU make собрана с поддержкой GNU Guile как встроенное расширение языка, то будет доступна функция guile. Она принимает один аргумент, который сначала расширяется утилитой make обычным образом, затем передается вычислителю GNU Guile evaluator. Результат evaluator преобразуется в строку и используется как расширение функции guile в makefile. См. 12.1. Интеграция GNU Guile для подробностей по написанию расширений для make в Guile.
Вы можете определить, доступна ли поддержка GNU Guile путем проверки переменной .FEATURES на наличие в ней слова guile.
[9. Как запускать make]
Файл Makefile с набором инструкций для утилиты make можно использовать несколькими способами. Самое простое использование - перекомпилировать каждый файл, который устарел. Обычно файлы makefile пишутся так, что если вы запускаете make без аргументов, он делает именно это (запуск make или make all).
Однако возможно вы захотите обновить только некоторые файлы; вы можете захотеть использовать другой компилятор или другие опции компилятора; также возможно вы захотите обнаружить, какие файлы устарели, без их обновления (без перекомпиляции).
С помощью аргументов, передаваемых в командную строку make, вы все это сможете сделать, а также многое другое.
Утилита make при выходе всегда возвращает одно из трех значений статуса:
0 Говорит об успешном завершении работы make.
2 В работе make произошли ошибки. Будут напечатаны соответствующие сообщения с описанием этих ошибок.
1 Статус выхода, если вы использовали флаг -q, и утилита make определила, что какая-то target еще не обновлена. См. 9.3. Вместо выполнения recipes.
9.1. Аргументы, указывающие файл Makefile
Опцией -f или --file вы можете указать для make, какой файл makefile она должна обрабатывать (также работает опция --makefile). Например, -f altmake говорит использовать файл altmake в качестве makefile.
Если вы используете флаг -f несколько раз, и за каждым -f указываете аргумент, то все используемые файлы обрабатываются совместно как файлы makefile.
Если вы не используете флаг -f или --file, то по умолчанию утилита make пытается обнаружить и обработать файлы инструкций в следующем порядке: GNUmakefile, makefile и Makefile, и будет использовать первый попавшийся из них (см. 3. Написание файлов Makefile).
9.2. Аргументы, указывающие goals
Goals это цели компиляции (target-ы), которые запуск make должен стремиться в конечном итоге обновить. Другие target-ы также обновляются, если они появляются в качестве предпосылок целей (prerequisites) целей или предпосылок предпосылок целей и т. д.
По умолчанию goal это первая target в makefile (не считая target-ы, начинающиеся с точки, см. [2]). Поэтому обычно файлы makefile пишутся так, что первой целью является компиляция всей программы или программ, которые makefile описывают. Если первое правило (rule) в makefile имеет несколько target-ов, то только первое правило становится goal по умолчанию, а не весь список. Вы можете управлять выбором goal по умолчанию из своего makefile, используя переменную .DEFAULT_GOAL (см. 6.14. Другие специальные переменные).
Вы также можете указать другую goal или несколько goal в командной строке аргументов make. Используйте имя goal в качестве аргумента. Если вы укажете несколько goal, то make обработает каждую из них по очереди, в том порядке указания их имен.
Любая target в makefile может быть указана в качестве goal (за исключением случаев, когда она начинается с '-' или содержит '=', тогда это соответственно парсится как оператор switch или определение переменной). Даже могут быть указаны target-ы, не находящиеся в makefile, если make может найти неявные правила (implicit rules), которые говорят, как их обработать.
Make установит специальную переменную MAKECMDGOALS для списка goals, указанного в командной строке. Если в командной строке не были указаны goals, то эта переменная будет пустая. Имейте в виду, что эта переменная должна использоваться только в специальных случаях.
Пример подходящего использования MAKECMDGOALS - чтобы избежать подключения .d файлов во время обработки правил очистки (clean rules, см. 4.14. Автоматическая генерация prerequisites), поэтому make не будет создавать их заново только для немедленного удаления:
sources = foo.c bar.c
ifeq (,$(filter clean,$(MAKECMDGOALS))
include $(sources:.c=.d)
endif
Одно из использований указания goal - если вы хотите скомпилировать только часть своей программы, или только одну (или некоторые по выбору) из нескольких программ. Укажите в качестве goal каждый файл, который вы хотите пересоздать. Для примера рассмотрим директорию, содержащую несколько программ, с файлом makefile, начинающимся примерно так:
.PHONY: all
all: size nm ld ar as
Если вы работаете с программой size, то можете запустить команду make size, чтобы были скомпилированы только файлы этой программы.
Другой вариант применения указания goal - когда нужно создать файлы, которые обычно не создаются. Например, это может быть файл вывода отладки или версия программы, которая скомпилирована специально для тестирования, которая имеет соответствующее правило в makefile, но не является prerequisite для default goal.
Еще один вариант применения указания goal - запуск recipe, связанного с phony target (см. 4.6. Фальшивые цели (Phony Targets)) или с empty target (см. 4.8. Пустые target-файлы для записи событий). Многие makefile содержат phony target с именем clean, которая удаляет все, кроме исходных файлов. Естественно, это делается только в том случае, если вы явно запрашиваете это действие запуском make clean. Ниже приведен список имен типичных phony target и empty target. Подробный список всех стандартных целевых имен, используемых программными пакетами GNU, см. в разделе 16.6. Стандартные целевые объекты для пользователей.
all
Выполнит сборку всех target-ов верхнего уровня, прописанных в makefile.
clean
Удалит все файлы, которые обычно создаются при запуске make.
mostlyclean
Работает подобно 'clean', но может воздержаться от удаления нескольких файлов, которые люди обычно не хотят перекомпилировать. Например, 'mostlyclean' target для GCC не удаляет libgcc.a, потому что перекомпиляция требуется редко, и занимает некоторое время.
distclean realclean clobber
Любая из этих target-ов может быть определена, чтобы удалять большее количество файлов, чем 'clean'. Например, это может удалять конфигурационные файлы или линки, которые вы нормально создаете как подготовку к компиляции, даже если сам makefile не может создать эти файлы.
install
Копирует исполняемый файл в директорию, которую обычно используют для команд; копирует любые дополнительные файлы в директории, в которые исполняемые файлы их ищут.
print
Напечатает листинги измененных исходных файлов.
tar
Создаст tar-файл исходных файлов.
shar
Создаст shell-архив (файл shar) исходных файлов.
dist
Создаст файл дистрибутива исходных файлов. Это может быть tar-файл, или shar-файл, или их сжатая версия, или даже больше одного из перечисленного выше.
TAGS
Обновит таблицу тегов для этой программы.
check
test
Выполнит тесты самопроверки на программе, которую собирает этот makefile.
9.3. Вместо выполнения recipes
Файл makefile сообщает для make как определить, является ли target актуальной (up to date), и как обновить каждую target. Однако обновление target-ов это не всегда то, что вам нужно. Некоторые опции указывают для make другие действия.
-n --just-print --dry-run --recon
Это опции (флаги) "бездействия" (No-op). Они заставляют make напечатать те recipe, которые make считает необходимо обновить, чтобы их target-ы были актуальными, но без реального их выполнения. Обратите внимание, что некоторые recipe все еще выполнятся, даже с этим флагом (см. 5.7.1. Как работает переменная MAKE). Также выполнятся любые recipe, которые должны быть обновлены подключаемыми makefile (см. 3.5. Как заново создаются файлы Makefile).
-t --touch
"Touch". Просто пометит target-ы как обновленные, без фактического их изменения. Другими словами, make сделает вид, что обновила target-ы, но на самом деле не поменяет их содержимое; вместо этого только лишь поменяется метка времени файлов.
-q --question
"Вопрос". По-тихому проверяет, обновлены ли targets, но не выполняет recipes; код выхода покажет, нужно ли что-то обновлять.
-W file --what-if=file --assume-new=file --new-file=file
"Что если". За каждым флагом -W идет имя файла. Время модификации данных файлов записывается make как текущее время, хотя актуальные времена модификации остаются прежними. Вы можете использовать флаг -W вместе с флагом -n, чтобы посмотреть, что произойдет, если вы измените определенные файлы.
С флагом -n утилита make напечатает recipe, которое обычно выполняет, но без его выполнения.
С флагом -t утилита make игнорирует recipe в правилах и использует (по сути) команду touch для каждой target, которая должна быть пересоздана. Команда touch также печатается, если не используется опция -s или .SILENT. Для ускорения работы make на самом деле не использует запуск touch. Она выполняет действия напрямую.
С флагом -q утилита make ничего не напечатает и не будет выполнять никакие recipe, однако при выходе код статуса будет нулевой, если и только если target-ы, которые будут рассмотрены, уже обновлены. Если статус выхода 1, то должны быть выполнены некоторые обновления. Если make обнаружит ошибку, то статус выхода будет 2, так вы можете отличить ошибку от ситуации, когда target не обновлена.
Будет ошибкой использовать больше одного из этих флагов для одного и того же запуска make.
Опции -n, -t и -q не влияют на строки recipe, которые начинаются с символов '+', или содержат строки '$(MAKE)' или '${MAKE}'. Обратите внимание, что независимо от этих опций будут выполнены только строки, содержащие символ '+', либо строки '$(MAKE)' или '${MAKE}'. Другие строки в том же правиле не запустятся если они тоже не начинаются с '+', либо не содержат '$(MAKE)' или '${MAKE}' (см. 5.7.1. Как работает переменная MAKE).
Флаг -t предотвращает обновление phony targets (см. 4.6. Фальшивые цели (Phony Targets)), за исключением ситуации, когда нет строк recipe, начинающихся на '+', либо содержащих '$(MAKE)' или '${MAKE}'.
Флаг -W предоставляет 2 фичи:
• Если вы также используете флаг -n или -q, то вы можете увидеть что будет делать make, если вы измените некоторые файлы. • Без флага -n или -q, когда make реально выполнит recipes, флаг -W может указать make действовать таким образом, как если бы некоторые файлы были изменены, без реального запуска recipes для этих файлов.
Обратите внимание, что опции -p и -v позволяют вам получить другую информацию про make или про используемые makefiles (см. далее врезку "Сводка по опциям").
9.4. Как избежать перекомпиляции некоторых файлов
Иногда вы поменяли исходный файл, но не хотите перекомпилировать все файлы, которые от него зависят. Для примера предположим, что вы добавили в заголовок макрос, или декларацию, и от этого заголовка зависит множество других файлов. Будучи консервативной, утилита make предполагает, что любое изменение в заголовочном файле требует перекомпиляции всех зависимых файлов, однако вы знаете, что их не нужно перекомпилировать, и предпочли бы не тратить время на ожидание их компиляции.
Если вы предвидите проблему перед изменением заголовочного файла, то можете использовать флаг -t. Этот флаг укажет make не запускать recipes в правилах, но вместо этого пометит target обновленным путем изменения его даты последней модификации. Необходимо выполнить следующую процедуру:
1. Используйте команду make для перекомпиляции исходных файлов, которые на самом деле нуждаются в перекомпиляции, для гарантии, что объектные файлы будут обновлены перед тем, как вы начнете дальнейшие действия.
2. Сделайте изменения в заголовочных файлах.
3. Используйте команду make -t, чтобы пометить все объектные файлы обновленными. В следующий раз, когда вы запустите make, изменения в заголовочных файлах не приведут к перекомпиляции.
Если вы уже изменили заголовочный файл, когда некоторые файлы исходного кода требуют перекомпиляции, то поздно пользоваться опцией -t. Вместо этого вы можете использовать флаг -o file, который пометит указанный файл как "старый" (см. далее врезку "Сводка по опциям"). Это означает, что сам файл не будет переделан, и ничто не будет с его учетом переделано. Выполните следующую процедуру:
1. Перекомпилируйте исходные файлы, которые требуют перекомпиляции по причинам, не зависящим от определенного файла заголовка, с помощью make -o headerfile. Если в это вовлечено несколько заголовочных файлов, то используйте отдельную опцию -o для каждого из них.
2. Выполните "Touch" для всех объектных файлов с помощью make -t.
9.5. Переназначение переменных
Аргумент командной строки, который содержит '=', задает значение переменной. Например, v=x установит значение x для переменной v. Если вы таким способом укажете значение, то все обычные присваивания той же самой переменной в makefile игнорируются; мы говорим, что значение переменной в этом случае переназначено аргументом командной строки.
Чаще всего эта возможность используется для передачи компилятору дополнительных флагов. Например, в правильно написанном makefile переменная CFLAGS включена в каждый recipe, который запускает компилятор C, так что файл foo.c компилируется чем-то наподобие следующей команды:
$ cc -c $(CFLAGS) foo.c
Таким образом, любое значение, которое вы установите для CFLAGS, будет влиять на каждую компиляцию. Файл makefile вероятно указывает обычное значение для CFLAGS, примерно так:
CFLAGS=-g
Каждый раз, когда запускаете make, вы можете при желании поменять это значение. Например, если вы запустите make CFLAGS='-g -O', то каждая компиляция C будет осуществляться командой cc -c -g -O (это также иллюстрирует, как вы можете обрамить кавычками значения переменной в шелл, чтобы туда попали пробелы и другие специальные символы, когда меняете переменную).
Переменная CFLAGS это всего лишь одна из многих общепринятых стандартных переменных, специально существующих для того, чтобы вы могли поменять их таким способом. Для полного списка см. 10.3. Переменные, используемые неявными правилами.
Также вы можете запрограммировать makefile для просмотра дополнительных ваших переменных, дающих пользователю управление над другими аспектами работы makefile путем изменения этих переменных.
Когда переназначаете переменную через аргумент командной строки, вы можете определить либо рекурсивно расширяемую (recursively-expanded) переменную, либо переменную, расширяемую обычным способом (simply-expanded). Примеры, приведенные выше, делают recursively-expanded переменную; чтобы сделать simply-expanded переменную, записывайте её присваивание через ':=' или '::=' вместо '='. Однако если вы не хотите включить ссылку на переменную или вызов функции в указанное вами значение, то не имеет значения, какой тип переменной вы создаете.
Существует единственный способ, которым makefile может поменять переменную, которую вы переназначили. Этот способ использует директиву override, строка которой выглядит примерно так: 'override variable = value' (см.6.7. Директива override).
9.6. Тестирование компиляции программы
Обычно, когда происходит ошибка при выполнении команды шелла, утилита make немедленно сдается, возвращая ненулевой статус. В таком случае больше не запустятся никакие recipe ни для каких target. Ошибка подразумевает, что goal не может быть корректно пересобрана, и make сообщит об этом сразу, как только обнаружит ошибку.
Когда вы компилируете программу, которую только что изменили, это поведение не то, что вам нужно. Место этого вы бы предпочли попробовать сделать компиляцию каждого файла, чтобы сразу показать как можно больше ошибок компиляции, насколько это возможно. Тогда вы могли бы увидеть и исправить их все без дополнительного запуска make [3] (что может быть важно, когда компилируется большой проект, на что тратится значительное время).
Для таких случаев вы должны использовать флаг -k или --keep-going. Это укажет make продолжить компиляцию для других prerequisites ожидающих обновления target, пересобирая их при необходимости, перед тем как сдаться и вернуть ненулевой статус. Например, после ошибки в компиляции одного объектного файла make -k продолжит компилировать другие объектные файлы, хотя уже известно, что конечная цель процесса недостижима. В дополнение к продолжению после ошибочных команд shell, make -k будет продолжать работу как можно дальше после того, как обнаружит, что не знает как создать файл target или prerequisite. Это всегда приводит к сообщению об ошибке, однако без использования -k такая ошибка фатальна (см. далее врезку "Сводка по опциям").
Обычное поведение make предполагает, что ваша цель состоит в том, чтобы обновить goals; как только make обнаружит, что это невозможно, она сообщит об этом отказе немедленно. Опция -k указывает, что реальная цел состоит в проверке как можно большего количества изменений в программе, чтобы возможно найти несколько независимых проблем, которые вы могли бы исправить перед новой попыткой компиляции. Как раз по этой причине команда компиляции Emacs передает по умолчанию флаг -k.
9.7. Временные файлы
В некоторых ситуациях для make потребуется создавать свои собственные временные файлы. Эти файлы не должны нарушаться во время работы make, включая все рекурсивно вызываемые экземпляры make.
Если установлена переменная окружения MAKE_TMPDIR, то все временные файлы, создаваемые make, будут помещены в директорию, указанную этой переменной.
Если MAKE_TMPDIR не установлена, то используется стандартное размещение временных файлов текущей операционной системы. Для POSIX-систем это будет место, указанное переменной окружения TMPDIR, или иначе используется системное умолчание (например папка /tmp). На Windows сначала будет проверена переменная TMP, затем TEMP, затем TMPDIR, и наконец будет использоваться системное место по умолчанию для временного файла.
Имейте в виду, что эта директория уже должна существовать, иначе make потерпит сбой: make не будет пытаться создать директорию для временных файлов.
Эти переменные не могут быть установлены внутри makefile: GNU make должна иметь доступ к месту временного хранения файлов до момента, когда начнет чтение файлов makefile.
9.8. Сводка по опциям make
-b -m
Эти опции игнорируются для совместимости с другими версиями make.
-B --always-make
Считает все target-ы устаревшими. GNU make продолжает рассматривать targets и их prerequisites, используя обычные алгоритмы; однако все цели, рассматриваемые таким образом, всегда перестраиваются заново независимо от статуса их prerequisites. Во избежание бесконечной рекурсии, если установлено MAKE_RESTARTS (см. 6.14. Другие специальные переменные) в значение больше 0, то эта опция запрещается при рассмотрении вопроса о переделке файлов makefile (см. 3.5. Как заново создаются файлы Makefile).
-C dir --directory=dir
Меняет директорию на dir перед чтением файлов makefile. Если указано несколько опций -C, то каждая из них интерпретируется относительно предыдущей: '-C / -C etc' эквивалентно '-C /etc'. Это обычно используется вместе с рекурсивными вызовами make (см. 5.7. Рекурсивное использование make).
-d
Печатает отладочную информацию в дополнение к обычной обработке. Отладочная информация говорит, какие файлы рассмотрены для перестроения, какие времена файлов сравниваются и с какими результатами, какие файлы на самом деле необходимо перестроить, какие неявные правила (implicit rules) рассматриваются и какие применяются - все интересное о том, как make решает, что делать. Опция -d эквивалентна --debug=a (см. далее).
--debug[=options]
Печатает отладочную информацию в дополнение к обычной обработке, с указанием уровня отладочных сообщений. Могут быть выбраны различные уровни и типы вывода. Без аргументов печатает отладочную информацию "базового" уровня (basic). Ниже приведены возможные аргументы этой опции; рассматривается только их первый символ, и значения должны отделяться друг от друга запятой или пробелом.
a (all)
Разрешены все типы отладочного вывода. Это эквивалентно использованию -d.
b (basic)
Базовая отладочная информация - выводится на печать каждая target, которая была найдена как устаревшая (out-of-date), и была ли сборка успешной или нет.
v (verbose)
Уровень выше 'basic'; включает сообщения о том, какие файлы makefile были разобраны, prerequisites которые не нужно было перестраивать, и т. д. Эта опция также разрешает сообщения уровня 'basic'.
i (implicit)
Печатает сообщения, описывающие неявный поиск правил для каждой цели. Эта опция также разрешает сообщения уровня 'basic'.
j (jobs)
Печатает сообщения, содержащие подробные сведения о вызове определенных подкоманд.
m (makefile)
По умолчанию показанные выше сообщения не разрешены при попытке перестроить (remake) файлы makefile. Эта опция разрешает сообщения также и при перестроении файлов makefile. Обратите внимание, что опция 'all' разрешает эту опцию. Эта опция также разрешает сообщения уровня 'basic'.
p (print)
Печатает выполняемый recipe, даже когда recipe обычно молчит (из-за .SILENT или '@'). Также печатает имя makefile и его строку, где был определен recipe.
w (why)
Объясняет, почему каждая target должна быть пересоздана, показывая, какие prerequisites более актуальны, чем target.
n (none)
Запретит всю разрешенную в настоящий момент отладочную информацию. Если после этого обнаружатся дополнительные флаги отладки, они все равно вступят в силу.
-e --environment-overrides
Присваивает приоритет переменным, взятым из окружения, перед переменным из файлов makefile. См. 6.10. Переменные из окружения.
-E string --eval=string
Обработает string как синтаксис makefile. Это версия командной строки функции eval (см. 8.10. Функция eval). Вычисление выполняется после того, как определены правила и переменные по умолчанию, но до чтения любых файлов makefile.
-f file --file=file --makefile=file
Читает файл с именем file как makefile. См. 3. Написание файлов Makefile.
-h --help
Напомнит вам об опциях, которые понимает make, и завершит работу make.
-i --ignore-errors
Игнорирует все ошибки в recipe, выполняемых для пересборки файлов. См. [3].
-I dir --include-dir=dir
Укажет директорию dir для поиска подключаемых файлов makefile. См. 3.3. Подключение других файлов Makefile. Если используется несколько опций -I для указания нескольких директорий, то директории просматриваются в указанном порядке. Если директория dir это одиночное тире (-), то все уже указанные директории до этого момента (включая пути директории по умолчанию) будут отброшены. Вы можете просмотреть текущий список директорий для поиска через переменную .INCLUDE_DIRS.
-j [jobs] --jobs[=jobs]
Указывает количество одновременно запускаемых обработок recipe (jobs). Без аргумента make запустит одновременно столько recipe, сколько возможно. Если указано более одной опции -j, то вступит в действие последняя из них. Для дополнительной информации о том, как запускаются recipes, см. 5.4. Параллельное выполнение. Имейте в виду, что на MS-DOS эта опция игнорируется.
--jobserver-style=[style]
Выбирает стиль используемого сервера заданий. Эта опция дает эффект только если разрешены параллельные сборки (см. 5.4. Параллельное выполнение). На POSIX-системах style может быть fifo (умолчание) или pipe. На Windows допускается только стиль sem (умолчание). Эта опция полезна, если вам нужно использовать более старые версии GNU make, или другой инструмент, требующий определенного стиля jobserver.
-k --keep-going
Продолжит работу после возникновения ошибки, насколько это возможно. Хотя не может быть собрана target, потерпевшая неудачу и все то, что от неё зависит, все же могут быть обработаны другие prerequisites этих target. См. выше врезку "Тестирование компиляции программы".
-l [load] --load-average[=load] --max-load[=load]
Указывает, что новые recipe не должны запускаться, если выполняются другие recipe, и среднее значение нагрузки процессора составляет как минимум load (число с плавающей запятой). Без аргумента удалит предыдущий лимит нагрузки. См. 5.4. Параллельное выполнение.
-L --check-symlink-times
На системах, поддерживающих символические ссылки, эта опция заставляет make учитывать метки времени любых символических ссылок в дополнение к метке времени файла, на который ссылаются эти ссылки. Когда предоставлена эта опция, то в качестве времени изменения используется самая свежая метка времени модификации между файлом и ссылкой.
-n --just-print --dry-run --recon
Распечатает recipe, который будет выполнен, но без его выполнения (за исключением определенных обстоятельств). См. выше врезку "Вместо выполнения Recipes".
-o file --old-file=file --assume-old=file
Не пересоздавать файл file, даже если он более старый, чем его prerequisites, и не пересоздавать ничего из-за учета изменений в файле. По сути файл рассматривается как очень старый, и его правила игнорируются. См. выше врезку "Как избежать перекомпиляции некоторых файлов".
-O[type] --output-sync[=type]
Гарантирует, что все выходные данные каждого recipe печатаются в одной непрерывной последовательности. Эта опция полезна только когда используется опция --jobs для запуска нескольких recipe одновременно (см. 5.4. Параллельное выполнение). Без этой опции вывод будет отображаться как есть, как он генерируется командами нескольких recipe.
Когда тип type не указан, или тип 'target', данные вывода из всего recipe каждой target группируются вместе. С типом 'line' вывод каждой строки в recipe группируется вместе. С типом 'recurse' вывод из всех рекурсий make группируется вместе. С типом 'none' никакая синхронизация вывода не производится. См. 5.4.2. Вывод при параллельном выполнении.
-p --print-data-base
Напечатает базу данных (правила и значения переменных), полученную из чтения файлов makefile; затем выполнит все как обычно, если не указано что-то другое. Это также напечатает информацию версии, которую выдает опция -v (см. далее). Для печати базы данных без пересборки файлов используйте make -qp. Для печати базы данных предварительно заданных правил и переменных используйте make -p -f /dev/null. Вывод базы данных содержит информацию имени файла и номера строки для определений recipe и переменной, так что это может быть полезно как инструмент отладки в сложных окружениях.
-q --question
"Режим вопроса". Не запускает никакие recipe, или ничего не напечатает; просто возвратит статус 0 выхода, если указанные target уже обновлены, статус 1 если требуется любая пересборка, или статус 2 если произошла ошибка. См. выше врезку "Вместо выполнения Recipes".
-r --no-builtin-rules
Исключит использование встроенных неявных правил (built-in implicit rules, см. 10. Использование неявных правил). Вы все еще можете определить свои собственные написанные правила шаблона (см. 10.5. Определение и переопределение правил шаблона). Опция -r также очистит список суффиксов по умолчанию для правил суффиксов (см. 10.7. Старомодные правила суффиксов). Однако вы все еще можете определить свои собственные суффиксы вместе с правилом для .SUFFIXES, и затем определить свои собственные правила суффиксов. Имейте в виду, что опция -r затрагивает только правила; переменные по умолчанию остаются в силе (см. 10.3. Переменные, используемые неявными правилами); см. далее описание опции -R.
-R --no-builtin-variables
Исключит использование встроенных относящихся к правилу переменных (built-in rule-specific variables, см. 10.3. Переменные, используемые неявными правилами). Конечно, вы все еще можете определить свои собственные. Опция -R также автоматически разрешит опцию -r (см. выше её описание), поскольку в таком случае нет смысла в неявных правилах без каких-либо определений для переменных, которые они используют.
-s --silent --quiet
"Тихое" функционирование; не печатает никакие выполняемые recipe. См. 5.2. Эхо в рецепте.
-S --no-keep-going --stop
Отменяет действие опции -k. В этом нет необходимости, за исключением рекурсивного make, где -k может наследоваться от make верхнего уровня через MAKEFLAGS (см. 5.7. Рекурсивное использование make), или если вы установили -k в MAKEFLAGS вашего окружения.
--shuffle[=mode]
Эта опция разрешает форму fuzz-тестирования взаимоотношений prerequisite. Когда разрешен параллелизм (-j), порядок сборки target-ов становится менее определенным. Если prerequisites не полностью декларированы в makefile, то это может привести к периодическим и трудно поддающимся отслеживанию сбоям сборки.
Опция --shuffle принуждает make направленно переупорядочить цели goal и prerequisites таким образом, чтобы взаимоотношения target/prerequisite все еще сохранялись, однако упорядочивание prerequisites указанной target меняется, как описано ниже.
Порядок перечисления prerequisites в автоматических переменных этой опцией не изменяется.
Псевдо-target .NOTPARALLEL запрещает тасование для этого makefile. Кроме того, любой список prerequisite, содержащий .WAIT, не будет перетасован. См. 5.4.1. Отключение параллельного выполнения.
Опция --shuffle= принимает следующие значения:
random
Выберет случайное начальное значение (random seed) для перетасовки. Это используемое умолчание, если режим тасования не выбран. Выбранное seed также предоставляется для команд sub-makes. Это seed включается в сообщения об ошибках, чтобы его можно было повторно использовать в будущих прогонах для воспроизведения проблемы или проверки того, что проблема была решена.
reverse
Меняет на обратный упорядочивание goals и prerequisites вместо случайного тасования (random shuffle).
seed
Используется 'random' тасование, инициализированное указанным начальным значением seed. Здесь seed это целое число.
none
Запрещает тасование. Это отменит любые предыдущие опции --shuffle.
-t --touch
Применяет "Touch" к файлам (пометит их как обновленные без каких-либо их изменений) вместо запуска их recipe. Это используется, чтобы сделать вид исполнения recipes, чтобы обмануть будущие запуски make. См. выше врезку "Вместо выполнения Recipes".
--trace
Покажет информацию трассировки для выполнения make. Использование --trace это сокращение для --debug=print,why.
-v --version
Напечатает версию программы make плюс копирайт, список авторов и замечание об отсутствии гарантий, и затем завершит работу make.
-w --print-directory
Напечатает сообщение, содержащее рабочую директорию до и после выполнения makefile. Это может быть полезно для отслеживания ошибок из сложных вложений рекурсивных команд make. См. 5.7. Рекурсивное использование make. На практике эта опция редко когда нужна, поскольку make делает это за вас. См. 5.7.4. Опция '--print-directory'.
--no-print-directory
Запретит печать рабочей директории при использовании -w. Эта опция полезна, когда автоматически включена -w, но вы не хотите видеть лишних сообщений. См. 5.7.4. Опция '--print-directory'.
-W file --what-if=file --new-file=file --assume-new=file
Сделать вид, что целевой файл (target) был только что изменен. При использовании с флагом -n это показывает, что произойдет, если вы измените этот файл. Без -n это почти то же самое, что запуск команды touch над данным файлом перед запуском make, за исключением того, что время модификации изменяется только в воображении make. См. выше врезку "Вместо выполнения Recipes".
--warn-undefined-variables
Выдает предупреждающее сообщение всякий раз, когда make видит ссылку на не определенную переменную. Это может быть полезно, когда вы пытаетесь отладить файлы makefile, которые сложным образом используют переменные.
[Ссылки]
1. GNU make. 2. Руководство GNU make: главы 1-3. |