Вопрос или проблема
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
-
touch blah.c
:Команда
touch
обновляет временную метку файлаblah.c
, что делает его "свежим" без фактического изменения его содержимого. Когда вы запускаетеmake
, он видит, что временная меткаblah.c
новее, чем у зависимого от негоblah.o
, и это вызывает пересборкуblah.o
. После пересборкиblah.o
, обновляется и целевой файлblah
, потому чтоblah.o
, от которого он зависит, также обновился. -
Удаление
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
и надежного контроля версий в процессе сборки.