Почему "сделать все" работает, как ожидалось, без добавления "всех" к цели.PHONY?
Я знаю, что делает .PHONY.
Если в папке, где находится мой Makefile, я добавлю пустой файл с именем clean, и после запуска make clean все чистые цели не будут выполнены, так как в файле не было никаких изменений, поэтому цель не будет работать, и это правильный. Если я добавлю .PHONY: clean, тогда clean будет рассматриваться как команда, и это тоже правильно.
Мой вопрос заключается в том, почему это поведение не происходит одинаково для всех целей, так как я добавил файл all в папку. Так что в основном цель all все еще выполняется так, как если бы это был файл.PHONY: all
У меня есть следующий код makefile.
all: test1 test2
test1: test1.o
test1.o: test1.c
test2: test2.o
test2.o: test2.c
clean:
rm -rf *.o test1 test2
3 ответа
Откуда ты знаешь, что all
Правило "все еще выполняется"? У этого правила нет рецепта, поэтому его нельзя "исполнить".
Если вы имеете в виду, что, хотя all
файл существует в локальном каталоге, make
все еще строит цели test1
а также test2
Вот как работает make (это не имеет ничего общего с фальшивыми и не фальшивыми целями). Когда make решает, стоит ли сначала создавать конкретную цель или нет, она пытается создать все предпосылки для этой цели, а также все предпосылки для этих целей и т. Д. Только после того, как все это выполнено, может make
знать, стоит ли строить первую цель (all
в этом случае).
make clean
здесь нет никаких зависимостей, поэтому поместите файл с именем clean
их достаточно, чтобы цель считалась построенной.
make all
с другой стороны, есть зависимости. Даже если вы поместите файл с именемall
там, Make должен проверить, all
файл новее, чем test1
а также test2
. Этот процесс запускает сборкуtest1
а также test2
, и это имеет такой же эффект, как если бы all
была фальшивой целью.
Основа в том, что all: test1 test2
это рецепт создания файла с именемall
, это зависит от файлов test1
а также test2
.
Если ты бежишь make all
, Make будет делать что-то вроде этого:
- Проанализировать
Makefile
. - Узнай, что
all
зависит отtest1
а такжеtest2
. - Проверьте отметку времени
all
и посмотрите, "актуальна ли она".- Он считается "актуальным", если ни одна из зависимостей не новее, чем она сама.
- Другими словами, Make может пропустить создание файла, если он новее, чем все его зависимости.
- Он считается "актуальным", если ни одна из зависимостей не новее, чем она сама.
- Создавайте устаревшие или отсутствующие файлы.
Теперь, если вы хотите, чтобы Make не рассматривал цели как файлы, вы можете указать их как фальшивые цели. Это лучшая практика для нефайловых целей, таких какall
.
(Этот ответ не противоречит ни одному из существующих ответов, но предлагает другой способ думать об этом).
Когда у вас есть такое правило, как
dst: src
action
вы говорите две вещи (как вы знаете):
- если не существует или старше
src
, тогда сделайте; а также - когда
action
завершается, файлdst
будет существовать.
В отношении таких целей, как или, второе утверждение, конечно, неверно. Make не заставляет вас выполнять обещание в (2), поэтому, когда вы говорите
make all
, он вычислит и сгенерирует необходимые зависимости и не будет жаловаться на отсутствие файла после этого. Вы врете Make, но он не против (с этим все в порядке ...). То есть это в основном взлом make-файла .
Конечно, это происходит не так, если по какой-то причине существует файл с именем или
clean
. Затем Make примет во внимание дату модификации файла при вычислении зависимостей и, возможно, придет к выводу, которого вы не ожидали.
И что
.PHONY: all
делает, это узаконивает взлом и сообщает Make, даже если файл
all
существует, сделайте вид, что его нет »; вы фактически отменяете обещание (2).
Поэтому, как утверждают другие ответы, упоминание
.PHONY
не нужно. Он просто предупреждает ошибку - легко сделать, но легко пропустить - когда файл, соответствующий фальшивой цели, создается случайно.