Makefile Gnu 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文件?基本上,我想我正在寻找一种方法,将

我使用Make来管理数据工作流(而不是构建软件项目)。我有这样的模式规则:

%.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