Если вы хотите сделать это с помощью механизма FORCE, правильное решение будет выглядеть следующим образом:
version.o: FORCE
.PHONY: FORCE
FORCE:
Явно объявив FORCE
фальшивым, мы убедимся, что все будет работать правильно, даже если .SECONDARY:
используется (.SECONDARY:
приведет к тому, что FORCE
будет считаться промежуточным файлом, и make не будет перестраивать промежуточные файлы, если они не имеют предварительных условий, более новых, чем конечная цель, и FORCE
не имеет никаких предварительных условий, поэтому .PHONY: FORCE
необходимо).
Другое решение (использующее $(shell touch version.c)
) также имеет проблему: это может заставить ваш редактор думать, что version.c обновлен, и запросить перезагрузку файла, что можетв конечном итоге будет разрушительным, если вы редактировали буфер файла, но еще не сохранили его.Если вы не возражаете против этого, это можно сделать еще проще, заметив, что команда touch
молчит, поэтому присвоение фиктивной переменной hack
не требуется:
$(shell touch version.c) # This is enough, but will likely confuse your editor
.PHONY "трюк", упомянутый в комментариях к вопросу, как правило, не работает.Это может выглядеть так, потому что это приведет к повторной ссылке, если version.o
уже существует, но фактический объектный файл не будет перестроен, если правило файла .o
является неявным правилом (которым оно обычно является).Проблема в том, что make не выполняет неявный поиск правил для явно поддельных целей.Этот make-файл показывает ошибку:
fooprog: test.o
cp $< $@
%.o: %.c
cp $< $@
.PHONY: test.o # WRONG
clean:
rm test.o fooprog
Если вместо неявного правила используется правило статического шаблона, трюк .PHONY: version.o
будет работать.В целом, использование статических шаблонных правил вместо неявных правил избавляет от наиболее запутанного поведения Make.Но большинство файлов make используют неявные правила.