GNU Makefile:来自单个规则的多个输出+防止中间文件被删除

mak*_*rus 14 makefile wildcard gnu-make

这里开始,这是一个问题的延续.问题是有一条规则从单个输入生成多个输出,并且命令很耗时,所以我们宁愿避免重新计算.现在还有一个额外的转折,我们希望保持文件不被删除为中间文件,规则涉及通配符以允许参数.


建议的解决方案是我们设置以下规则:

file-a.out: program file.in
    ./program file.in file-a.out file-b.out file-c.out

file-b.out: file-a.out
    @

file-c.out: file-b.out
    @
Run Code Online (Sandbox Code Playgroud)

然后,调用make file-c.out创建两者,我们避免make-jswitch 并行运行的问题.到目前为止都很好.


问题如下.因为上述解决方案在DAG中建立了一个链,所以make考虑它不同; 文件file-a.outfile-b.out被视为中间文件,它们在默认情况下得到尽快删除不必要的file-c.out准备.

这里提到了一种避免这种情况的方法,它包括添加file-a.outfile-b.out作为目标的依赖关系.SECONDARY,这使它们不被删除.不幸的是,这并不能解决我的问题,因为我的规则使用了通配符模式; 具体来说,我的规则看起来更像是这样:

file-a-%.out: program file.in
    ./program $* file.in file-a-$*.out file-b-$*.out file-c-$*.out

file-b-%.out: file-a-%.out
    @

file-c-%.out: file-b-%.out
    @
Run Code Online (Sandbox Code Playgroud)

这样就可以传递一个包含在文件名中的参数,例如通过运行

make file-c-12.out
Run Code Online (Sandbox Code Playgroud)

make文档建议的解决方案是将这些作为隐式规则添加到依赖项列表中.PRECIOUS,从而防止删除这些文件.


有效的解决方案.PRECIOUS,但它也可以防止在规则失败和文件不完整时删除这些文件.有没有其他方法可以使这项工作?

解决这个问题的方法是定义一个.SECONDARY没有先决条件的目标,即:

.SECONDARY:
Run Code Online (Sandbox Code Playgroud)

通知make所有文件都应被视为辅助文件,因此不会被删除,除非make被中断或规则失败.不幸的是,这不允许选择带有通配符的规则子集以这种方式工作,所以我认为这只是一个黑客(即使它很有用).

slo*_*dog 23

最简单的事情

file-a-%.out file-b-%.out file-c-%.out: program file.in
    ./program $* file.in file-a-$*.out file-b-$*.out file-c-$*.out
Run Code Online (Sandbox Code Playgroud)

会做你想要的.

(具有多个目标的模式规则与您在此处询问的具有多个目标的常规规则不同.请参阅制作手册中的bison示例.)


p00*_*0ya 2

如果您的输出不是从单个 file.in 生成的,而是从包含主干的先决条件文件生成的,即

file-a.out: program file-%.in
    ./program file-$*.in file-a-$*.out file-b-$*.out file-c-$*.out
Run Code Online (Sandbox Code Playgroud)

然后您可以构建所有可能的目标匹配的列表:

inputs = $(wildcard file-*.in)
secondaries = $(patsubst file-%.in,file-a-%.out,$(inputs)) \
    $(patsubst file-%.in,file-b-%.out,$(inputs))
Run Code Online (Sandbox Code Playgroud)

类似地,如果词干来自有限集:

batchnos = 17 18 19 20 
batchnos = $(shell seq 17 20)
secondaries = $(patsubst %,file-a-%.out,$(batchnos)) $(patsubst %,file-b-%.out,$(batchnos))
Run Code Online (Sandbox Code Playgroud)

然后只需将这些作为先决条件添加到 .SECONDARY 目标中

.SECONDARY: $(secondaries)
Run Code Online (Sandbox Code Playgroud)