Пересвязать цель Makefile при изменении списка зависимостей - PullRequest
2 голосов
/ 26 июля 2011

Общая проблема, с которой я сталкивался в Makefiles, заключается в том, что исполняемые файлы (и библиотеки в этом отношении) не обязательно пересвязываются при изменении списка зависимостей.Например:

SRCS=$(wildcard *.c)
CPPFLAGS=-MMD -MP
target: $(SRCS:.c=.o)
        $(CC) $(LDFLAGS) $^ -o $@
-include $(SRCS:.c=.d)

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

Как мне заставить make (в частности, gmake) справиться с этой ситуацией?

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

Я имеюпридумать два решения, ни одно из которых не является идеальным.Во-первых, если мы сделаем список источников явным, а не подстановочным символом, мы можем сделать цель зависимой от файла Makefile.Изменение файла Makefile для удаления исходного файла приводит к повторной привязке цели.Это имеет две проблемы.Во-первых, вы должны удалить Makefile из $ ^ перед компоновкой, что немного уродливо (но выполнимо с помощью filter-out).Во-вторых, этот Makefile предназначен для использования в качестве шаблона, включенного в другие Make-файлы (которые указывают источники и цель) - вместо этого мы должны сделать цель зависимой от , что Makefile.Тьфу.

Второе решение состоит в том, чтобы включить некоторую логику, подобную следующей:

SRCS=$(wildcard *.c)
CPPFLAGS=-MMD -MP
target: $(SRCS:.c=.o)
        $(CC) $(LDFLAGS) $^ -o $@
        @echo '$$(if $$(filter-out $$(SRCS:.c=.o), $(SRCS:.c=.o)), .PHONY:target)' > target.d
-include $(SRCS:.c=.d)
-include target.d

Это создает файл target.d, который отслеживает список зависимостей и заставляет цель перестраиваться, есливсе удаленоЭто работает, но это некрасиво.Он также не может учитывать любые дополнительные не исходные зависимости, указанные включающим Makefile.

Есть ли официальный способ сделать это или, по крайней мере, лучший способ?

(КакКроме того, я бы также хотел очистить связанный объект и файлы зависимостей при удалении исходного файла, если это возможно. Это могло бы быть возможно, расширив мое второе решение и сделав его еще более уродливым.)

Ответы [ 3 ]

3 голосов
/ 17 ноября 2011

Чтобы сделать это правильно, вам, вероятно, придется прибегнуть к Расширенному поколению автоматических зависимостей Пола Смита . Пол в настоящее время поддерживает GNU make и описал все распространенные проблемы (и их решения!), Касающиеся генерации зависимостей.

Рекомендуется также другие официальные документы на его веб-сайте.

Я пользуюсь его советами и приемами уже несколько лет, и - даже если это иногда становится немного сложным - изучение их стоит каждую секунду.

0 голосов
/ 29 июля 2011

В идеале, должно быть только одно правило make pattern для выполнения всех связей (хорошо, одно для исполняемых файлов, одно для разделяемых библиотек и одно для архивов). Что-то вроде:

# rules.mk
$(BUILD_DIR}/exe/% : rules.mk
    g++ -o $@ $(filter-out %.mk,$^)

Далее, когда вы определяете цели сборки, они зависят от собственного make-файла:

# project_a.mk
$(BUILD_DIR}/exe/a : project_a.mk ${a_obj}

Обычно эта зависимость будет заключена в макрос:

define EXE_TARGET
  $(BUILD_DIR}/exe/${1} : ${2}
  $(BUILD_DIR}/exe/${1} : $(lastword $(MAKEFILE_LIST))
endef

так в project_a.mk это будет делать:

# project_a.mk
$(eval $(call EXE_TARGET,a,${a_obj}))
0 голосов
/ 29 июля 2011

Вам нужна более умная версия gmake. ElectricMake - это совместимая с gmake замена, включающая в себя функцию ledger , которая в основном делает актуальную проверку более сложной, чем просто проверка того, что выход новее, чем входы. В частности, бухгалтерская книга будет хэшировать список входных данных для цели, и если этот список изменится, это приведет к перестройке выходных данных:

# cat Makefile
out: a b c
        @echo out from $^
        @touch out
# emake --emake-ledger=timestamp
out from a b c
# emake --emake-ledger=timestamp
make: `out' is up to date.
# vi Makefile ;# Remove 'c' from the prereq list.
# cat Makefile
out: a b
        @echo out from $^
        @touch out
# emake --emake-ledger=timestamp
out from a b

Если вы хотите попробовать, вы можете получить пробную копию .

...