我试图做以下事情 . 有一个程序,称之为 foo-bin
,它接收一个输入文件并生成两个输出文件 . 一个愚蠢的Makefile规则是:
file-a.out file-b.out: input.in
foo-bin input.in file-a.out file-b.out
但是,这并不能以任何方式告诉 make
两个目标将同时生成 . 在串行运行 make
时这很好,但如果尝试 make -j16
或同样疯狂的话,可能会造成麻烦 .
The question is whether there exists a way to write a proper Makefile rule for such a case? 显然,它会生成一个DAG,但不知何故GNU make手册没有说明如何处理这种情况 .
两次运行相同的代码并仅生成一个结果是不可能的,因为计算需要时间(想想:小时) . 仅输出一个文件也相当困难,因为它经常用作GNUPLOT的输入,GNUPLOT不知道如何只处理数据文件的一小部分 .
5 回答
我会解决如下:
在这种情况下,并行make将'serialize'创建a和b但是因为创建b不会做任何事情,所以它会花费时间 .
诀窍是使用具有多个目标的模式规则 . 在这种情况下,make将假定两个目标都是通过单个调用命令创建的 .
模式规则和正常规则之间的这种解释差异并不完全有意义,但它对于这样的情况很有用,并且在手册中有记录 .
这个技巧可以用于任意数量的输出文件,只要它们的名称有一些共同的子字符串供
%
匹配 . (在这种情况下,公共子串是".")Make没有任何直观的方法来做到这一点,但有两个不错的解决方法 .
首先,如果涉及的目标具有共同的词干,则可以使用前缀规则(使用GNU make) . 也就是说,如果您想修复以下规则:
你可以这样写:
(使用模式规则变量$ *,它代表模式的匹配部分)
如果您希望可移植到非GNU Make实现,或者如果您的文件无法命名以匹配模式规则,则还有另一种方法:
这告诉make在make运行之前不会存在input.in.intermediate,因此它的缺失(或它的时间戳)不会导致foo-bin虚假运行 . 无论file-a.out还是file-b.out或者两者都是过时的(相对于input.in),foo-bin只会运行一次 . 您可以使用.SECONDARY而不是.INTERMEDIATE,它将指示make NOT删除假设的文件名input.in.intermediate . 此方法对于并行make构建也是安全的 .
第一行的分号很重要 . 它为该规则创建了一个空的配方,因此Make知道我们将真正更新file-a.out和file-b.out(感谢@siulkiulki和其他指出这一点的人)
这是基于@ deemer的第二个答案,它不依赖于模式规则,它修复了我遇到的嵌套使用变通方法时遇到的问题 .
我会在@ deemer的答案中添加这个作为评论,但我不能,因为我刚创建了这个帐户并且没有任何声誉 .
说明:需要空配方才能允许Make执行正确的簿记以将
file-a.out
和file-b.out
标记为已重建 . 如果你有另一个依赖于file-a.out
的中间目标,那么Make将选择不构建外部中间体,声称:我就是这样做的 . 首先,我总是将预先请求与食谱分开 . 然后在这种情况下一个新的目标来做配方 .
第一次:
1.我们尝试构建file-a.out,但是dummy-a-and-b.out需要先做,所以make运行dummy-a-and-b.out配方 .
2.我们尝试构建file-b.out,dummy-a-and-b.out是最新的 .
第二次及以后的时间:
1.我们尝试构建file-a.out:查看先决条件,正常的先决条件是最新的,缺少次要先决条件,因此被忽略 .
2.我们尝试构建file-b.out:查看先决条件,正常的先决条件是最新的,缺少次要先决条件,因此被忽略 .