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.out
和file-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'.