Makefile 规则仅在文件在调用 make 之前存在时才有效

Makefile rule only works if file exists before make is invoked

考虑以下(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

似乎发生的事情是,从 *.dat 生成 *.bin 的规则只承认它知道如何生成 test.bin if test.dat在执行任何内容之前就存在 ,即使根据输出它在尝试创建 test.bin.

之前已经创建了 test.dat

这对我来说很不方便,因为我必须先准备一些文件(从不同的、较早的构建部分导入它们)。

有解决办法吗?也许有某种方法允许根据现在存在的文件(重新)评估规则?

通配符目标会发生这种情况,例如 %.bin。他们在第一次通过时得到评估。您可以添加 test.bin 的显式目标。或者,遵循 tkausl 的建议并让 test.dat 依赖于 prepare(虚假目标)。在这种情况下,您不再需要双重依赖:

my_target: test.bin

你的 makefile 有很多问题。但是,根据您的评论,我倾向于假设这里的 MCVE 只是 "M" 了一点点,而且它已经减少了很多,以至于它有一些基本问题。所以我不会讨论它们,除非你想让我讨论。

这里的问题是您正在创建重要文件,但没有指明您正在做什么。出于性能原因,Make 在内部保留了它使用的目录内容的缓存,并且该缓存仅在 make 调用它理解将修改它的规则时更新。

此处您的目标是 prepare,但配方实际上创建了一个完全不同的文件 test.dat。因此,make 不会修改目录内容的内部缓存,当它检查缓存以查看文件 test.dat 是否存在时,它不存在。

您需要确保编写的 makefile 不会欺骗 make:如果配方创建文件 foo,则目标名称应该是 foo,而不是 bar.

你必须写

test.dat:  prepare

或(当您想保留通配符时)

%.dat: prepare
    @:

通常,您可能希望创建和使用 .stamp 文件而不是 prepare 目标。