Правило Makefile работает, только если файл существует до вызова make - PullRequest
0 голосов
/ 20 февраля 2019

Рассмотрим следующее ( MCVE of a) Makefile:

my_target: prepare test.bin

prepare:
    echo >test.dat

%.bin: %.dat
    cp $? $@

Если вы запустите make в чистом каталоге, произойдет сбой:

echo >test.dat
make: *** No rule to make target 'test.bin', needed by 'my_target'. Stop.

Запустите его еще раз, и он завершится успешно:

echo >test.dat
cp test.dat test.bin

Кажется, что происходит то, что правило создания *.bin из *.dat только признает, что знает, как сделать test.bin если test.dat существует до того, как что-либо выполнено , даже если в соответствии с выводом, которое он уже создал test.dat до того, как попытается создать test.bin.

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

Есть ли решение?Возможно, какой-то способ разрешить (пере) оценить правила в свете файлов, которые сейчас присутствуют?

Ответы [ 3 ]

0 голосов
/ 21 февраля 2019

Существует ряд проблем с вашим make-файлом.Однако, основываясь на ваших комментариях, я склонен предположить, что MCVE здесь просто немного слишком"M", и он настолько уменьшен, что у него есть ряд основных проблем.Поэтому я не буду их обсуждать, если только вы не захотите, чтобы я.

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

Здесь ваша цель prepareно рецепт фактически создает совершенно другой файл, test.dat.Таким образом, make не изменяет свой внутренний кэш содержимого каталога, и когда он проверяет кэш, чтобы увидеть, существует ли файл test.dat, он не существует.

Вы должны быть уверены, что ваш make-файл являетсянаписано так, что это не обманывает make: если рецепт создает файл foo, тогда целевое имя должно быть foo, а не bar.

0 голосов
/ 21 февраля 2019

вам нужно написать

test.dat:  prepare

или (когда вы хотите использовать групповые символы)

%.dat: prepare
    @:

Обычно вместо этого вы можете создавать и использовать файлы .stampцели prepare.

0 голосов
/ 20 февраля 2019

Это случается с подстановочными символами, например %.bin.Они оцениваются с первого прохода.Вы можете добавить явную цель test.bin .Или следуйте советам tkausl и имейте test.dat в зависимости от prepare (фиктивная цель).В этом случае вам больше не нужна двойная зависимость:

my_target: test.bin
...