Ложные цели
Ложная цель — это такая, которая не является реальным именем файла; вместо этого она просто имя рецепта, который будет выполнен при явном запросе. Существуют две причины использования ложной цели: избежать конфликта с файлом того же имени и улучшить производительность.
Если вы пишете правило, рецепт которого не создаст целевой файл, рецепт будет выполняться каждый раз, когда целевой файл потребуется перестроить. Вот пример:
clean:
rm *.o temp
Поскольку команда rm не создает файл с именем clean, вероятно, такого файла никогда не будет существовать. Поэтому команда rm будет выполняться каждый раз, когда вы говорите «make clean».
В этом примере цель clean не будет работать должным образом, если в этом каталоге будет создан файл с именем clean. Поскольку у clean нет предшественников, clean всегда будет считаться обновлённым, и его рецепт не будет выполняться. Чтобы избежать этой проблемы, вы можете явно объявить цель ложной, сделав её предшественником специальной цели .PHONY (см. Специальные встроенные имена целей), как показано ниже:
.PHONY: clean
clean:
rm *.o temp
После этого «make clean» выполнит рецепт независимо от того, существует ли файл с именем clean.
Предшественники .PHONY всегда интерпретируются как буквальные имена целей, а никогда как шаблоны (даже если они содержат символы «%»). Чтобы всегда перестраивать правило шаблона, используйте «цель принуждения» (см. Правила без рецептов или предшественников).
Ложные цели также полезны в сочетании с рекурсивными вызовами make (см. Рекурсивное использование make). В этой ситуации makefile часто содержит переменную, которая перечисляет ряд подкаталогов, которые необходимо построить. Простой способ сделать это — определить одно правило с рецептом, который циклически перебирает подкаталоги, как в этом примере:
SUBDIRS = foo bar baz
subdirs:
for dir in $(SUBDIRS); do \
$(MAKE) -C $$dir; \
done
Однако, с этим методом есть проблемы. Во-первых, любая ошибка, обнаруженная в под-make, игнорируется этим правилом, поэтому оно будет продолжать строить остальные каталоги, даже если один из них завершится ошибкой. Это можно преодолеть, добавив команды оболочки для фиксации ошибки и выхода, но тогда это будет происходить даже если make вызывается с опцией -k, что неудобно. Во-вторых, и, возможно, что более важно, вы не можете в полной мере воспользоваться возможностями make по построению целей параллельно (см. Параллельное выполнение), так как существует только одно правило. Цели каждого отдельного makefile будут строиться параллельно, но только один подкаталог будет строиться за раз.
Объявив подкаталоги как .PHONY цели (это необходимо сделать, так как подкаталог, очевидно, всегда существует; в противном случае он не будет построен), вы можете устранить эти проблемы:
SUBDIRS = foo bar baz
.PHONY: subdirs $(SUBDIRS)
subdirs: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $@
foo: baz
Здесь мы также объявили, что подкаталог foo нельзя построить до тех пор, пока не будет завершен подкаталог baz; этот вид объявлений связей особенно важен при попытке параллельного построения.
Поиск неявных правил (см. Неявные правила) пропускается для .PHONY целей. Вот почему объявление цели как .PHONY хорошо сказывается на производительности, даже если вы не беспокоитесь о фактическом существовании файла.
Ложная цель не должна быть предшественником реального целевого файла; если она таковой является, её рецепт будет выполняться каждый раз, когда make рассматривает этот файл. Пока ложная цель никогда не является предшественником реальной цели, рецепт ложной цели будет выполняться только тогда, когда ложная цель является заданной целью (см. Аргументы для указания целей).
Не следует объявлять включённый makefile ложной целью. Ложные цели не предназначены для представления реальных файлов, и поскольку цель всегда считается устаревшей, make всегда будет перестраивать её, а затем повторно выполнять себя (см. Как перестраиваются Makefile). Чтобы избежать этого, make не будет повторно выполнять себя, если включённый файл, помеченный как ложный, перестроен.
Ложные цели могут иметь предшественники. Когда один каталог содержит несколько программ, удобнее описать все программы в одном makefile ./Makefile. Поскольку цель, перестроенная по умолчанию, будет первой в makefile, принято сделать эту цель ложной целью с именем «all» и указать в качестве предшественников все отдельные программы. Например:
all : prog1 prog2 prog3
.PHONY : all
prog1 : prog1.o utils.o
cc -o prog1 prog1.o utils.o
prog2 : prog2.o
cc -o prog2 prog2.o
prog3 : prog3.o sort.o utils.o
cc -o prog3 prog3.o sort.o utils.o
Теперь вы можете просто сказать «make», чтобы перестроить все три программы, или указать в качестве аргументов те, которые нужно перестроить (как в «make prog1 prog3»). Свойство «ложности» не наследуется: предшественники ложной цели сами по себе не являются ложными, если явно не объявлены таковыми.
Когда одна ложная цель является предшественником другой, она служит подпрограммой другой. Например, здесь «make cleanall» удалит объектные файлы, файлы различий и файл program:
.PHONY: cleanall cleanobj cleandiff
cleanall : cleanobj cleandiff
rm program
cleanobj :
rm *.o
cleandiff :
rm *.diff
Copyright © 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022 Free Software Foundation, Inc.
Licensed under the GNU Free Documentation License.
https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html