使用批编译更新可变数量目标的makefile规则

使用批编译更新可变数量目标的makefile规则,makefile,gnu-make,Makefile,Gnu Make,我们有一个专有的编译器,它可以获取多个输入文件并一次处理它们: compiler a.in # produces a.out compiler a.in b.in c.in # produces a.out b.out c.out 这样做的原因是可以节省大量初始化时间。对于数千个文件,批处理版本比单独编译文件快几个数量级。我们还对文件运行后处理器 现在,我在(GNU)makefile中有了这一点,它没有利用批处理功能并逐个更新文件。我想将其更新为使用批编译: .INTERMEDIATE:

我们有一个专有的编译器,它可以获取多个输入文件并一次处理它们:

compiler a.in
# produces a.out

compiler a.in b.in c.in
# produces a.out b.out c.out

这样做的原因是可以节省大量初始化时间。对于数千个文件,批处理版本比单独编译文件快几个数量级。我们还对文件运行后处理器

现在,我在(GNU)makefile中有了这一点,它没有利用批处理功能并逐个更新文件。我想将其更新为使用批编译:

.INTERMEDIATE: $(TMP)
$(TMP):  $(TMPDIR)/%.tmp: $(SRCDIR)/%.in |$(TMPDIR) 
        compiler $< -o $@

$(RESULT): $(RESDIR)/%.out: $(TMPDIR)/%.tmp $(SRCDIR)/%.in
        post-process $< -o $@

.INTERMEDIATE:$(TMP)
$(TMP):$(TMPDIR)/%.TMP:$(SRCDIR)/%.在|$(TMPDIR)中
编译器$<-o$@
$(结果):$(RESDIR)/%输出:$(TMPDIR)/%tmp$(SRCDIR)/%输入
后期处理$<-o$@

我如何重写第一条规则来重新编译使用单个命令修改过的所有文件,可能是使用
$?
?第二条规则需要保持不变。

如果您能够要求GNU make 4.3+,那么您的生活非常简单,您可以像这样利用它(注意
&:
):

如果您不需要最新版本的GNU make,您将被降级为使用“sentinel文件”,如下所示:

a.out b.out c.out : .sentinal ;

.sentinal: a.in b.in c.in
        compiler $^
        @touch $@

(确保在第一条规则中包含尾随的分号…

哇,谢谢,分组目标正是我所需要的。但是,第二部分不会真正起作用:如何确保当x.in发生更改并且重新生成x.tmp时,只有x.tmp得到后处理?不管怎样,我认为他们添加这个功能的事实证明了它以前是不可用的。我不知道你说的“tmp”是什么意思?在我的示例中没有提到“tmp”。我只是提供了一种方法来实现您问题中的初始语句,其中使用许多
.in
文件调用编译器会生成许多
.out
文件。我的第二个例子肯定能做到这一点。如果对某些
tmp
文件有其他要求,您的问题中没有明确说明。第二个选项肯定有效,但有问题。例如,手动删除.out文件不会导致重建它们:您必须删除
.sentinel
文件。这就是为什么增加了分组目标;它简化了编写过程,避免了一些关于“传统”解决方案的烦人事情。我在原始问题的末尾指出,我仍然需要后处理规则才能工作。例如,当我运行
makeresult/foo.out
,并且
src/foo.in
已被修改时,它必须能够确定它需要同时运行编译器(批处理)和后处理器(处理单个文件)。换句话说,我想知道在进行批编译时是否可能有一个完整且正确的依赖关系图,特别是如果批编译的输出文件可以是其他目标的先决条件。听起来,在分组目标之前,答案是“不”不,那不是我的答案。我只是不太清楚完整的依赖性要求。如果您的意思是批量构建需要所有已构建的
tmp
文件,那么您只需告诉make。例如,您可以更改
.sentinel
规则,使其将
tmp
文件列为先决条件,这样它们都是在批处理命令运行之前生成的。使用分组目标当然更好,但也可以对其进行黑客攻击,使其在没有分组目标的情况下或多或少正常工作。
a.out b.out c.out : .sentinal ;

.sentinal: a.in b.in c.in
        compiler $^
        @touch $@