Какова цель .PHONY в make-файле? - PullRequest
1426 голосов
/ 27 января 2010

Что означает .PHONY в Makefile? Я прошел через это , но это слишком сложно.

Может кто-нибудь объяснить мне это простыми словами?

Ответы [ 8 ]

1626 голосов
/ 27 января 2010

По умолчанию цели Makefile являются «файловыми целями» - они используются для создания файлов из других файлов. Make предполагает, что его целью является файл, и это делает написание Makefiles относительно простым:

foo: bar
  create_one_from_the_other foo bar

Однако иногда вы хотите, чтобы ваш Makefile запускал команды, которые не представляют физические файлы в файловой системе. Хорошими примерами этого являются общие цели «чистый» и «все». Скорее всего, это не так, но у вас может потенциально есть файл с именем clean в вашем основном каталоге. В таком случае Make будет сбит с толку, потому что по умолчанию цель clean будет связана с этим файлом, и Make будет запускать его, только если файл не обновлен по отношению к его зависимостям.

Эти специальные цели называются phony , и вы можете явно указать Make, что они не связаны с файлами, например ::

.PHONY: clean
clean:
  rm -rf *.o

Теперь make clean будет работать как положено, даже если у вас есть файл с именем clean.

С точки зрения Make, поддельная цель - это просто цель, которая всегда устарела, поэтому всякий раз, когда вы спрашиваете make <phony_target>, она запускается независимо от состояния файловой системы. Некоторые общие make цели, которые часто являются фальшивыми: all, install, clean, distclean, TAGS, info, check.

687 голосов
/ 26 августа 2010

Предположим, у вас есть цель install, что очень часто встречается в make-файлах. Если вы не используете .PHONY, а файл с именем install существует в том же каталоге, что и Makefile, то make install ничего не сделает . Это связано с тем, что Make интерпретирует правило как «выполнить такой-то рецепт для создания файла с именем install». Поскольку файл уже существует и его зависимости не изменились, ничего не будет сделано.

Однако, если вы сделаете целевую PHONY install, она сообщит инструменту make, что цель вымышленная, и что make не должна ожидать, что она создаст фактический файл. Следовательно, он не будет проверять, существует ли файл install, а это означает: а) его поведение не изменится, если файл существует, и б) дополнительный stat() не будет вызван.

Обычно все цели в вашем Makefile, которые не создают выходной файл с тем же именем, что и имя цели, должны быть PHONY. Обычно это all, install, clean, distclean и т. Д.

96 голосов
/ 30 сентября 2013

ПРИМЕЧАНИЕ : Инструмент make читает make-файл и проверяет метки времени изменения файлов по обе стороны от символа ':' в правиле.

Пример

В каталоге 'test' присутствуют следующие файлы:

prerit@vvdn105:~/test$ ls
hello  hello.c  makefile

В make-файле правило определяется следующим образом:

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.
70 голосов
/ 26 августа 2012
.PHONY: install
  • означает, что слово «установить» не представляет имя файла в этом Makefile;
  • означает, что Makefile не имеет ничего общего с файлом "install" в том же каталоге.
38 голосов
/ 27 января 2010

Это цель сборки, которая не является именем файла.

27 голосов
/ 04 апреля 2014

Лучшим объяснением является само руководство по сборке GNU: 4.6 Раздел Phony Targets .

.PHONY является одним из специальных встроенных целевых имен производителя . Есть и другие цели, которые могут вас заинтересовать, поэтому стоит просмотреть эти ссылки.

Когда пришло время рассмотреть цель .PHONY, make запустит свой рецепт безусловно, независимо от того, существует ли файл с таким именем или каково его время последней модификации.

Вас также могут заинтересовать стандартные цели , такие как all и clean.

11 голосов
/ 11 февраля 2015

Есть также один важный хитрый прием «.PHONY» - когда физическая цель зависит от фальшивой цели, которая зависит от другой физической цели:

TARGET1 -> PHONY_FORWARDER1 -> PHONY_FORWARDER2 -> TARGET2

Вы просто ожидаете, что если вы обновили TARGET2, то TARGET1 следует считать устаревшим по сравнению с TARGET1, поэтому TARGET1 следует перестроить. И это действительно работает так .

Сложная часть - это когда TARGET2 не устарел против TARGET1 - в этом случае следует ожидать, что TARGET1 не должен бытьrebuild.

Это на удивление не работает, потому что: фальшивая цель все равно запускалась (как обычно фальшивые цели) , что означает, что фальшивая цель считалась обновленной .И из-за этого 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

Вы можете поиграть с этим:

  • сначала сделайте 'make prepare', чтобы подготовить "исходные файлы"
  • поэкспериментируйте с этим, коснувшись определенных файлов, чтобы увидеть их обновленные

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

1 голос
/ 08 июля 2018

Я часто использую их для указания цели по умолчанию не стрелять.

superclean: clean andsomethingelse

blah: superclean

clean:
   @echo clean

%:
   @echo catcher $@

.PHONY: superclean

Без PHONY make superclean будет запускать clean, andsomethingelse и catcher superclean; но с PHONY make superclean не выстрелит catcher superclean.

Нам не нужно беспокоиться о том, чтобы цель clean была PHONY, потому что она не полностью фальшивая. Хотя он никогда не производит чистый файл, у него есть команды для запуска, поэтому make подумает, что это конечная цель.

Тем не менее, цель superclean на самом деле является фальшивой, поэтому make попытается объединить ее с чем-то еще, что обеспечивает deps для цели superclean - это включает в себя другие цели superclean и цель %.

Обратите внимание, что мы ничего не говорим о andsomethingelse или blah, поэтому они явно идут в ловушку.

Вывод выглядит примерно так:

$ make clean
clean

$ make superclean
clean
catcher andsomethingelse

$ make blah 
clean
catcher andsomethingelse
catcher blah
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...