Почему "сделать все" работает, как ожидалось, без добавления "всех" к цели.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 будет делать что-то вроде этого:

  1. Проанализировать Makefile.
  2. Узнай, что all зависит от test1 а также test2.
  3. Проверьте отметку времени all и посмотрите, "актуальна ли она".
    • Он считается "актуальным", если ни одна из зависимостей не новее, чем она сама.
      • Другими словами, Make может пропустить создание файла, если он новее, чем все его зависимости.
  4. Создавайте устаревшие или отсутствующие файлы.

Теперь, если вы хотите, чтобы Make не рассматривал цели как файлы, вы можете указать их как фальшивые цели. Это лучшая практика для нефайловых целей, таких какall.

(Этот ответ не противоречит ни одному из существующих ответов, но предлагает другой способ думать об этом).

Когда у вас есть такое правило, как

      dst: src
    action

вы говорите две вещи (как вы знаете):

  1. если не существует или старше src, тогда сделайте; а также
  2. когда action завершается, файл dst будет существовать.

В отношении таких целей, как или, второе утверждение, конечно, неверно. Make не заставляет вас выполнять обещание в (2), поэтому, когда вы говорите make all, он вычислит и сгенерирует необходимые зависимости и не будет жаловаться на отсутствие файла после этого. Вы врете Make, но он не против (с этим все в порядке ...). То есть это в основном взлом make-файла .

Конечно, это происходит не так, если по какой-то причине существует файл с именем или clean. Затем Make примет во внимание дату модификации файла при вычислении зависимостей и, возможно, придет к выводу, которого вы не ожидали.

И что .PHONY: all делает, это узаконивает взлом и сообщает Make, даже если файл allсуществует, сделайте вид, что его нет »; вы фактически отменяете обещание (2).

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

Другие вопросы по тегам