Разница между удалением и изменением времени модификации файла в контексте команды make.

Вопрос или проблема

blah: blah.o
    cc blah.o -o blah # Выполняется третьим

blah.o: blah.c
    cc -c blah.c -o blah.o # Выполняется вторым

blah.c:
    echo "int main() { return 0; }" > blah.c # Выполняется первым

Когда я запускаю команду make, она выдает ожидаемый результат. Теперь, если я выполню touch на файле blah.c, вывод будет cc -c blah.c -o blah.o cc blah.o -o blah, но когда я удаляю файл blah.c, он создаёт его, и вывод был echo "int main() {return 0; }" > blah.c cc -c blah.c -o blah.o cc blah.o -o blah.

Теперь, что я не могу понять, как ‘blah’ узнал о том, что blah.c недоступен. Он просто проверил blah.o, отметка времени которого не изменилась. Разве blah.o сам не проверяет blah.c на обновления, когда ‘blah’ его проверяет? В любом случае, почему два вывода разные. Разве touch файла blah.c не удалил его, и blah.o это знает, поэтому просто обновил его отметку времени. Что на самом деле происходит?

Ваша строка зависимости для blah.c не указывает никаких зависимостей, поэтому make не имеет файла для сравнения, чтобы принять решение о пересборке. Он пересоберёт его только в случае, если он не существует.

Так как всё для создания blah.c уже есть в самом makefile, я бы предложил сделать makefile зависимостью.

blah.c: Makefile

И тогда каждый раз, когда вы редактируете (или выполняете touch) Makefile, он будет пересоздавать blah.c.

Для дополнительной изысканности, вместо записи непосредственно в blah.c, запишите в blah.c.new и если они различны, замените blah.c, а если одинаковы, удалите blah.c.new.

Ответ или решение

Разберем разницу между командами delete и touch файла в контексте работы с командой make, опираясь на приведенный пример и теорию работы системы сборки, которой управляет makefile.

Теория

Make — это инструмент, который автоматизирует сборку приложений, используя makefile, где содержатся правила зависимостей и инструкции по сборке различных компонентов проекта. Makefile интерпретирует зависимости между файлами и решает, какие из них необходимо перекомпилировать, используя временные метки файлов.

Пример

Ваш makefile содержит следующее:

blah: blah.o
    cc blah.o -o blah # Выполняется третьим

blah.o: blah.c
    cc -c blah.c -o blah.o # Выполняется вторым

blah.c:
    echo "int main() { return 0; }" > blah.c # Выполняется первым

Когда вы запускаете команду make, она выполняет как раз те шаги, которые необходимы, чтобы прийти к актуальной версии файла blah. Давайте разберемся, что происходит при touch и delete.

Example

  1. touch blah.c:

    Команда touch обновляет временную метку файла blah.c, что делает его "свежим" без фактического изменения его содержимого. Когда вы запускаете make, он видит, что временная метка blah.c новее, чем у зависимого от него blah.o, и это вызывает пересборку blah.o. После пересборки blah.o, обновляется и целевой файл blah, потому что blah.o, от которого он зависит, также обновился.

  2. Удаление blah.c:

    Если вы удаляете файл blah.c, make обнаруживает, что файл, от которого зависит blah.o, отсутствует. Согласно makefile, если указанный в правилах исходный файл отсутствует, make пытается его сгенерировать. В вашем случае, make запускает комманду echo, чтобы создать blah.c со свежим содержимым. Затем файл blah.o перекомпилируется, за ним обновляется и blah.

Приложение

Теперь рассмотрим, почему выходные данные отличаются в обоих случаях:

  • Touch: Обновление временной метки файла blah.c сигнализирует make, что его нужно перекомпилировать. Так как blah.o зависит от blah.c, его временная метка также обновляется, что влечет за собой обновление файла blah.

  • Delete: Удаление файла инициирует процесс его пересоздания, так как make предусматривает восстановление отсутствующих файлов. Процесс начинается с выполнения команды из связанного с blah.c рецепта. Только после этого подходят к шагам компиляции.

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

Чтобы улучшить управление зависимостями, можно добавить makefile в зависимости для blah.c, что в данном случае обеспечит обновление blah.c при изменении самого makefile:

blah.c: Makefile

Подобное изменение обеспечит, что при любом изменении makefile файл blah.c будет пересоздаваться, даже если сам файл и не изменился. Это полезно для более точного управления зависимостями, особенно в случае, если makefile влияет на построение blah.c.

Заключение

Таким образом, touch и удаление файла вызывают различные сценарии реагирования make из-за разной природы операций. Touch просто обновляет временную метку, тогда как удаление провоцирует восстановление файла. Понимание таких различий имеет ключевое значение для эффективного управления проектами средствами make и надежного контроля версий в процессе сборки.

Оцените материал
Добавить комментарий

Капча загружается...