Какова цель .PHONY в make файле?

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

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

Ответ 1

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

foo: bar
  create_one_from_the_other foo bar

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

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

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

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

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

Для получения дополнительной информации есть хороший учебник, объясняющий это здесь.

Ответ 2

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

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

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

Ответ 3

.PHONY: install
  • означает, что слово "install" не представляет собой имя файла в этом Makefile;
  • означает, что Makefile не имеет никакого отношения к файлу с именем "install" в том же каталоге.

Ответ 4

ПРИМЕЧАНИЕ. Средство make считывает файл makefile и проверяет временные метки изменений файлов в обеих сторонах символа ":" в правиле.

Пример

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

[email protected]:~/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 с именем "hello" и выполнять команду каждый раз.

Теперь предположим, что в make файле нет зависимостей цели:

hello:
    cc hello.c -o hello

и 'hello' файл уже присутствует в pwd 'test', тогда 'make hello' всегда будет отображаться как:

make: `hello' is up to date.

Ответ 5

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

Ответ 6

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

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

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

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

Ответ 7

Там также одно важное хитрое отношение к ".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

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

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

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