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