GNU Makefile规则从单个源文件生成一些目标

我正在尝试做以下事情。 有一个程序叫做foo-bin ,它接受一个input文件并生成两个输出文件。 一个愚蠢的Makefile规则是这样的:

 file-a.out file-b.out: input.in foo-bin input.in file-a.out file-b.out 

但是,这并不能说明两个目标是同时产生的。 在串口运行make时很好,但如果尝试make -j16或类似的东西,可能会造成麻烦。

问题是,是否存在一种为这种情况编写适当的Makefile规则的方法? 很明显,它会生成一个DAG,但是不知怎的,GNU make手册并没有说明如何处理这个案例。

运行相同的代码两次,只生成一个结果是不可能的,因为计算需要时间(思考:小时)。 只输出一个文件也是相当困难的,因为它经常用作GNUPLOT的input,它不知道如何处理一小部分数据文件。

我会解决它如下:

 file-a.out: input.in foo-bin input.in file-a.out file-b.out file-b.out: file-a.out #do nothing noop 

在这种情况下,并行make将“序列化”创builda和b,但是由于创buildb没有做任何事情,所以没有时间。

诀窍是使用具有多个目标的模式规则。 在这种情况下,make会假设这两个目标都是通过单一的命令调用创build的。

 all:file-a.out file-b.out
 file -a%out file -b%out:input.in
     foo-bin input.in file -a $ * out file-b $ * out

这种模式规则和正常规则之间的解释差异并不完全合理,但对于这样的情况很有用,而且在手册中有logging。

这个技巧可以用于任何数量的输出文件,只要它们的名字有一些用于匹配的公共子string即可。 (在这种情况下,公共子string是“。”)

Make没有任何直观的方式来做到这一点,但有两个体面的解决方法。

首先,如果涉及的目标有一个共同的词干,那么可以使用前缀规则(使用GNU make)。 也就是说,如果你想修改以下规则:

 object.out1 object.out2: object.input foo-bin object.input object.out1 object.out2 

你可以这样写:

 %.out1 %.out2: %.input foo-bin $*.input $*.out1 $*.out2 

(使用模式规则variables$ *代表模式的匹配部分)

如果您想要移植到非GNU Make实现,或者您的文件不能被命名为匹配模式规则,还有另一种方法:

 file-a.out file-b.out: input.in.intermediate .INTERMEDIATE: input.in.intermediate input.in.intermediate: input.in foo-bin input.in file-a.out file-b.out 

这就告诉make input.in.intermediate在make运行之前不会存在,所以它的缺席(或者它的时间戳)不会导致foo-bin被虚假地运行。 无论file-a.out还是file-b.out或两者都过时(相对于input.in),foo-bin将只运行一次。 您可以使用.SECONDARY而不是.INTERMEDIATE,它将指示不要删除假设的文件名input.in.intermediate。 这种方法对于平行构build也是安全的。

这是我如何做到的。 首先,我总是把食谱的预先要求分开。 然后在这种情况下,做一个新的目标食谱。

 all: file-a.out file-b.out #first rule file-a.out file-b.out: input.in file-a.out file-b.out: dummy-a-and-b.out .SECONDARY:dummy-a-and-b.out dummy-a-and-b.out: echo creating: file-a.out file-b.out touch file-a.out file-b.out 

第一次:
1.我们尝试构buildfile-a.out,但是dummy-a-and-b.out需要先完成,然后运行dummy-a-and-b.out配方。
2.我们尝试构buildfile-b.out,而且,dummy-a-and-b.out是最新的。

第二次及以后的时间:
1.我们尝试构buildfile-a.out:make先决条件,正常先决条件是最新的,二级先决条件缺失,因此被忽略。
2.我们尝试构build文件b.out:make先决条件,正常的先决条件是最新的,二级先决条件丢失,所以忽略。

这是基于@ deemer的第二个答案,它不依赖于模式规则,它解决了我遇到的嵌套使用变通办法的问题。

 file-a.out file-b.out: input.in.intermediate @# Empty recipe to propagate "newness" from the intermediate to final targets .INTERMEDIATE: input.in.intermediate input.in.intermediate: input.in foo-bin input.in file-a.out file-b.out 

我将这个评论添加到@ deemer的回答中,但是我不能,因为我刚刚创build了这个帐户,没有任何声望。

说明:为了允许Make做适当的簿记,将file-a.outfile-b.out为已被重build,需要使用空配方。 如果你还有另外一个依赖于file-a.out中间目标,Make将会select不build立外部中间体,声称:

 No recipe for 'file-a.out' and no prerequisites actually changed. No need to remake target 'file-a.out'.