Makefile Gnu Make:缺少中间文件时重建
我使用Make来管理数据工作流(而不是构建软件项目)。我有这样的模式规则:Makefile Gnu Make:缺少中间文件时重建,makefile,gnu-make,Makefile,Gnu Make,我使用Make来管理数据工作流(而不是构建软件项目)。我有这样的模式规则: %.B: %.A foo $^ > $@ %.C: %.B bar $^ > $@ .SECONDARY: 现在,如果我注意到一些.B文件有问题(例如foo中的一个bug),我会删除特定的.B文件并再次执行make,但当然相应的.C文件仍然存在,并且比它们的.a文件更新,因此不会发生任何事情 当文件的依赖项丢失时,是否有一种很好的方法来强制重建.C文件?基本上,我想我正在寻找一种方法,将
%.B: %.A
foo $^ > $@
%.C: %.B
bar $^ > $@
.SECONDARY:
现在,如果我注意到一些.B
文件有问题(例如foo
中的一个bug),我会删除特定的.B
文件并再次执行make
,但当然相应的.C
文件仍然存在,并且比它们的.a
文件更新,因此不会发生任何事情
当文件的依赖项丢失时,是否有一种很好的方法来强制重建
.C
文件?基本上,我想我正在寻找一种方法,将.B
文件提升到完整目标,而不是次要或中间目标。我认为您必须将实际的.B
文件列为所有目标(或其他目标,这是在运行期间构建的)的先决条件如果要确保它们在生成完成后存在。我不确定是否有其他方法可以做到这一点。似乎您添加了.SECONDARY
目标以避免删除%.B文件,这会导致问题。因此,您需要不同的解决方法,而不是。SECONDARY
。
那么以下内容如何:
%.B: %.A; cat $^ > $@ && echo B >> $@
%.C: %.B; cat $^ > $@ && echo C >> $@
$(foreach C,\
$(sort $(filter %.C,$(MAKECMDGOALS))),\
$(eval $C: $(patsubst %.C,%.B,$C))\
$(eval $(patsubst %.C,%.B,$C): $(patsubst %.C,%.A,$C)))
运行上述生成文件:
bash#
$ touch doc.A
bash#
$ make doc.C
cat doc.A > doc.B && echo B >> doc.B
cat doc.B > doc.C && echo C >> doc.C
bash#
$ ls doc.*
doc.A doc.B doc.C
bash#
$ rm doc.B
bash#
$ make doc.C
cat doc.A > doc.B && echo B >> doc.B
cat doc.B > doc.C && echo C >> doc.C
bash#
$ ls doc.*
doc.A doc.B doc.C
bash#
$ touch doc.A
bash#
$ make doc.C
cat doc.A > doc.B && echo B >> doc.B
cat doc.B > doc.C && echo C >> doc.C
bash#
$ touch doc.B
bash#
$ make doc.C
cat doc.B > doc.C && echo C >> doc.C
该变通方法为命令行上指定的所有%.C目标生成显式规则链。GNU Make的非常规使用的非常规解决方案 我从来没有看到过这个问题,尽管我经常这样做。
也许那是因为我从不使用模式规则。
只需获取目标列表并使用静态模式规则。
可能是像使用$(通配符)
获取源代码列表这样简单的事情
导致
$ make all --warn
touch 1.A
touch 1.B
touch 1.C
touch 2.A
touch 2.B
touch 2.C
touch 3.A
touch 3.B
touch 3.C
$ make all --warn
make: Nothing to be done for 'all'.
$ rm 2.B
$ make all --warn
touch 2.B
touch 2.C
这份工作是一个很好的“联合国”。这种用法似乎并不罕见,我已经用数据做了很多年了。=)谢谢你的主意,我试试看。不过,这似乎会很快变得非常笨拙,编写各种虚假的“干净”目标来删除过期的%.C文件,然后再次“生成”可能会更容易。这只有在运行make foo.C
时才有效。如果运行makeall
,而all
目标依赖于一组.C
文件,则它将不起作用(MAKECMDGOALS
将只包含all
)。您没有显示makefile的其余部分,也没有描述您的典型用法,因此不清楚这是否足够。这个答案对我很有帮助——我不知道静态模式规则。进一步挖掘,作者说:“通常,如果在makefile中提到一个文件作为目标或先决条件,那么它就不能是中间文件。”因此,显式地命名所有文件(如本答案中所示),而不是通过模式匹配它们,防止它们被视为中间文件,从而在丢失时忽略它们。另一个好处是它不需要使用.SECONDARY
。
$ make all --warn
touch 1.A
touch 1.B
touch 1.C
touch 2.A
touch 2.B
touch 2.C
touch 3.A
touch 3.B
touch 3.C
$ make all --warn
make: Nothing to be done for 'all'.
$ rm 2.B
$ make all --warn
touch 2.B
touch 2.C