请考虑以下{{1}的MCVE: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
。
这对我来说不方便,因为我必须先准备一些文件(从构建的另一部分开始导入文件)。
有解决方案吗?也许有一些方法可以根据当前存在的文件对规则进行(重新)评估?
答案 0 :(得分:2)
makefile存在许多问题。但是,根据您的评论,我倾向于假定此处的MCVE只是太“ M”,而且已被简化得如此之多,以至于存在许多基本问题。因此,除非您希望我参加,否则我不会讨论它们。
这里的问题是,您正在创建重要文件,而没有表明要这样做。由于性能原因,Make在内部保留其使用的目录内容的缓存,并且仅当make调用它认为可以修改的规则时才更新该缓存。
这里的目标是prepare
,但配方实际上创建了一个完全不同的文件test.dat
。因此,make不会修改其内部目录内容的高速缓存,并且当它检查高速缓存以查看文件test.dat
是否存在时,它不会。
您需要确保编写的makefile不会欺骗make:如果配方创建文件foo
,则目标名称应为foo
,而不是{{1} }。
答案 1 :(得分:0)
这种情况适用于通配符目标,例如%.bin
。他们在第一遍得到评估。您可以添加一个明确的目标 test.bin 。或者,遵循tkausl的建议,并使 test.dat 依赖于准备(一个伪造的目标)。在这种情况下,您不再需要双重依赖:
my_target: test.bin
答案 2 :(得分:0)
你必须写
test.dat: prepare
或(当您想使用通配符时)
%.dat: prepare
@:
通常,您可能要创建并使用.stamp
文件而不是prepare
目标。