Make не распознает изменения в косвенных зависимостях
Рассмотрим этот простой make-файл:
all: output.txt
# The actual build command won't be this simple.
# It'll more be like "some-compiler file1.txt",
# which includes file2.txt automatically.
output.txt: file1.txt
cat file1.txt file2.txt > output.txt
file2.txt:
echo "heyo" > file2.txt
file1.txt: file2.txt
При первом запуске Make распознает, что file2.txt
это зависимость file1.txt
и поэтому он должен быть построен для output.txt
быть построенным. Таким образом, он работает echo "heyo" > file2.txt
а потом cat file1.txt file2.txt > output.txt
,
Однако при последующих запусках, если file2.txt
изменено, Make не перестраивается! Если file1.txt
меняется, но не для file2.txt
, Это просто дает страшный make: Nothing to be done for 'all'.
сообщение.
Люди, которые я видел, предлагают одно хакерское решение - сделать следующее:
all: output.txt
output.txt: file1.txt file2.txt
cat file1.txt file2.txt > output.txt
Тем не менее, это не возможно в моем случае, так как мои вторичные зависимости (такие строки, как file1.txt: file2.txt
) динамически генерируются с использованием include
,
Как сделать так, чтобы проверки выполнялись на всех уровнях дерева, если у меня несколько уровней зависимостей?
2 ответа
Я думаю, что проблема в том, что ваш make-файл немного слишком прост.
Позволять a -> b
обозначать a depends on b
, Из вашего make-файла у вас есть...
output.txt -> file1.txt -> file2.txt
когда make
пытается обновить output.txt
он видит, что output.txt
зависит от file1.txt
, Затем он замечает, что file1.txt
зависит от file2.txt
, В этот момент цепочка зависимостей останавливается. Если make видит, что file2.txt
новее чем file1.txt
он выполнит команду (и), связанную с file1.txt: file2.txt
delendency. В этом случае, однако, нет никаких команд - только сама зависимость. Это нормально, как идут дела, но это означает, что даже если file2.txt
обновляется file1.txt
не будет Следовательно, когда make перемещается вверх по цепочке зависимостей к...
output.txt: file1.txt
он видит, что output.txt
все еще новее, чем file1.txt
поэтому нет необходимости запускать какие-либо команды, связанные с этой зависимостью.
Если вы добавите touch
команда...
file1.txt: file2.txt
touch $@
затем file1.txt
будет обновлена, и поэтому цепочка зависимостей будет работать так, как вы ожидаете.
Ваш makefile не генерирует и не обновляет file1.txt
на всех (то есть: file1.txt
должен существовать в момент запуска make
). Он не содержит рецепт для генерации file1.txt
от file2.txt
, У него просто пустое правило (т.е. правило без рецепта):
file1.txt: file2.txt
поскольку file1.txt
обязательное условие output.txt
это пустое правило просто подразумевает, что file2.txt
должен существовать для output.txt
быть построенным, он даже не обновляется file1.txt
когда file2.txt
генерируется.
поскольку file1.txt
является единственным условием output.txt
а также file1.txt
никогда не обновляется make
, один раз output.txt
генерируется, он всегда остается актуальным (при условии file1.txt
внешне не обновляется).
file2.txt
быть измененным никогда не вызывает output.txt
быть восстановленным, потому что:
- это не является обязательным условием
output.txt
, - это не обновляет
file1.txt
(которая является единственной предпосылкойoutput.txt
).
Решение
Учитывая ваш текущий output.txt
правило:
output.txt: file1.txt
cat file1.txt file2.txt > output.txt
Если ты хочешь output.txt
быть построенным каждый раз file2.txt
изменения, то вам нужно file1.txt
быть построенным каждый раз file2.txt
изменения. Это может быть достигнуто с помощью правила, рецепт которого фактически обновляется file1.txt
и имеет file2.txt
в качестве предварительного условия, например:
file1.txt: file2.txt
touch $@