Ответы:
По умолчанию цели Makefile являются «файловыми целями» - они используются для создания файлов из других файлов. Make предполагает, что его целью является файл, и это делает написание Makefiles относительно простым:
foo: bar
create_one_from_the_other foo bar
Однако иногда вы хотите, чтобы ваш Makefile запускал команды, которые не представляют физические файлы в файловой системе. Хорошими примерами этого являются общие цели «чистый» и «все». Скорее всего, это не тот случай, но у вас может быть файл с именем clean
в вашем основном каталоге. В таком случае Make будет сбит с толку, потому что по умолчанию clean
цель будет связана с этим файлом, и Make будет запускать его только тогда, когда файл не обновлен по отношению к его зависимостям.
Эти специальные цели называются фальшивыми, и вы можете явно указать Make, что они не связаны с файлами, например:
.PHONY: clean
clean:
rm -rf *.o
Теперь make clean
будет работать, как ожидается, даже если у вас есть файл с именем clean
.
В терминах Make поддельная цель - это просто цель, которая всегда устарела, поэтому всякий раз, когда вы спрашиваете make <phony_target>
, она запускается независимо от состояния файловой системы. Некоторые общие make
цели, которые часто фальшиво являются: all
, install
, clean
, distclean
, TAGS
, info
, check
.
Предположим, у вас есть install
цель, что очень часто встречается в make-файлах. Если вы не используете .PHONY
, и файл с именем install
существует в том же каталоге, что и Makefile, то make install
ничего не будет делать . Это потому, что Make интерпретирует правило как «выполнить такой-то рецепт для создания файла с именем install
». Поскольку файл уже существует и его зависимости не изменились, ничего не будет сделано.
Однако, если вы install
создадите целевой PHONY, он сообщит инструменту make, что цель вымышленная, и что make не должна ожидать, что он создаст фактический файл. Следовательно, он не будет проверять, install
существует ли файл, а это означает, что: a) его поведение не будет изменено, если файл существует, и b) extra stat()
не будет вызываться.
Обычно все цели в вашем Makefile, которые не создают выходной файл с тем же именем, что и имя цели, должны быть PHONY. Это , как правило , включает в себя all
, install
, clean
, distclean
, и так далее.
.sh
или .bash
для «программ», которые работают так, как будто они имеют основную функцию, и оставляют за собой добавление расширения для включаемых вами библиотек ( source mylib.sh
). На самом деле, я добрался до этого ТАКОГО вопроса, потому что у меня был скрипт в той же директории, что и мой Makefile, под названиемinstall
.PHONY
все время ...
.PHONY
версия.
ПРИМЕЧАНИЕ . Инструмент make считывает make-файл и проверяет метки времени изменения файлов по обе стороны от символа «:» в правиле.
В каталоге «test» присутствуют следующие файлы:
prerit@vvdn105:~/test$ ls
hello hello.c makefile
В makefile правило определяется следующим образом:
hello:hello.c
cc hello.c -o hello
Теперь предположим, что файл 'hello' представляет собой текстовый файл, содержащий некоторые данные, которые были созданы после файла 'hello.c'. Таким образом, отметка времени модификации (или создания) 'hello' будет новее, чем у 'hello.c'. Поэтому, когда мы вызовем команду 'make hello' из командной строки, она напечатает как:
make: `hello' is up to date.
Теперь откройте файл hello.c и вставьте в него пробелы, которые не влияют на синтаксис или логику кода, затем сохраните и закройте. Теперь отметка времени модификации hello.c новее, чем у 'hello'. Теперь, если вы вызовете 'make hello', он выполнит команды следующим образом:
cc hello.c -o hello
И файл 'hello' (текстовый файл) будет перезаписан новым двоичным файлом 'hello' (результат вышеуказанной команды компиляции).
Если мы используем .PHONY в make-файле следующим образом:
.PHONY:hello
hello:hello.c
cc hello.c -o hello
и затем вызывает 'make hello', он игнорирует любой файл, присутствующий в pwd 'test', и выполняет команду каждый раз.
Теперь предположим, что у цели 'hello' нет объявленных зависимостей:
hello:
cc hello.c -o hello
и файл 'hello' уже присутствует в pwd 'test', тогда 'make hello' всегда будет отображаться как:
make: `hello' is up to date.
make
делает смысл в целом, это все о файлах! Спасибо за этот ответ.
.PHONY: install
Лучшим объяснением является само руководство по GNU make: 4.6 раздел Phony Targets .
.PHONY
является одним из специальных встроенных целевых имен make . Есть и другие цели, которые могут вас заинтересовать, поэтому стоит просмотреть эти ссылки.
Когда пришло время рассмотреть цель .PHONY, make запустит свой рецепт безоговорочно, независимо от того, существует ли файл с таким именем или каково его время последней модификации.
Вы также можете быть заинтересованы в стандартных целях марки, таких как all
и clean
.
Есть также один важный хитрый прием «.PHONY» - когда физическая цель зависит от фальшивой цели, которая зависит от другой физической цели:
TARGET1 -> PHONY_FORWARDER1 -> PHONY_FORWARDER2 -> TARGET2
Вы просто ожидаете, что если вы обновили TARGET2, то TARGET1 следует считать устаревшим по сравнению с TARGET1, поэтому TARGET1 следует перестроить. И это действительно работает таким образом .
Самое сложное, когда TARGET2 не устарел против TARGET1 - в этом случае следует ожидать, что TARGET1 не следует перестраивать.
Это на удивление не работает, потому что: фальшивая цель была запущена в любом случае (как фальшивые цели обычно делают) , что означает, что фальшивая цель считалась обновленной . И из-за этого TARGET1 считается несвежим против фальшивой цели .
Рассматривать:
all: fileall
fileall: file2 filefwd
echo file2 file1 >fileall
file2: file2.src
echo file2.src >file2
file1: file1.src
echo file1.src >file1
echo file1.src >>file1
.PHONY: filefwd
.PHONY: filefwd2
filefwd: filefwd2
filefwd2: file1
@echo "Produced target file1"
prepare:
echo "Some text 1" >> file1.src
echo "Some text 2" >> file2.src
Вы можете поиграть с этим:
Вы можете видеть, что fileall зависит от file1 косвенно через фальшивую цель - но он всегда перестраивается из-за этой зависимости. Если вы измените зависимость в fileall
с filefwd
на file
, то теперь fileall
не будет перестраиваться каждый раз, а только тогда, когда какая-либо из зависимых целей устарела как файл.
Специальная цель .PHONY:
позволяет объявлять фиктивные цели, поэтому make
они не будут проверяться как настоящие имена файлов: она будет работать постоянно, даже если такие файлы еще существуют.
Вы можете поместить несколько .PHONY:
в свой Makefile
:
.PHONY: all
all : prog1 prog2
...
.PHONY: clean distclean
clean :
...
distclean :
...
Есть еще один способ объявить фиктивные цели: просто введите '::'
all :: prog1 prog2
...
clean ::
...
distclean ::
...
'::' имеет особое значение: цели являются фальшивыми, и они могут появляться несколько раз:
clean ::
rm file1
...
clean ::
rm file2
Командные блоки будут вызываться один за другим.
Я часто использую их, чтобы сказать, что цель по умолчанию не стрелять.
superclean: clean andsomethingelse
blah: superclean
clean:
@echo clean
%:
@echo catcher $@
.PHONY: superclean
Без фальшиво, make superclean
будет стрелять clean
, andsomethingelse
и catcher superclean
; но с PHONY, make superclean
не уволитcatcher superclean
.
Нам не нужно беспокоиться о том, чтобы сказать, что clean
цель - это ФОНИ, потому что она не совсем фальшивая. Хотя он никогда не производит чистый файл, у него есть команды для запуска, поэтому make будет думать, что это конечная цель.
Тем не менее, superclean
цель на самом деле является фальшивой, поэтому make попытается объединить ее с чем-то еще, что обеспечивает superclean
цели для цели - это включает в себя другие superclean
цели и %
цель.
Обратите внимание, что мы ничего не говорим о andsomethingelse
или blah
, поэтому они явно идут в ловушку.
Вывод выглядит примерно так:
$ make clean
clean
$ make superclean
clean
catcher andsomethingelse
$ make blah
clean
catcher andsomethingelse
catcher blah