Makefile规则仅在调用make之前文件存在的情况下才有效

时间:2019-02-20 18:37:19

标签: makefile gnu-make

请考虑以下{{1}的MCVEMakefile

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 :(得分: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目标。