来自一个配方和并行执行的多个目标 [英] multiple targets from one recipe and parallel execution

查看:21
本文介绍了来自一个配方和并行执行的多个目标的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个项目,其中包含一个代码生成器,该项目只需调用一次代码生成器即可从一个输入文件生成多个 .c 和 .h 文件.我有一个规则,将 .c 和 .h 文件作为多个目标,输入文件作为先决条件,配方是代码生成器的调用.然后我有进一步的规则来编译和链接生成的 .c 文件.

这在 -j 因子为 1 时工作正常,但是如果我增加 j 因子,我发现我会多次调用代码生成器,最多调用 -j 因子或预期目标文件的数量,以最小者为准.这很糟糕,因为代码生成器的多次调用可能会由于生成的代码被多次编写而导致失败.

我不会在这里发布我的实际(大)代码,但我已经能够构建一个小示例来演示相同的行为.

Makefile 如下所示:

<前>output.concat: output5 output4 output3 output2 output1猫 $^ > $@输出1 输出2 输出3 输出4 输出5:输入./frob 输入干净的:rm -rf 输出*

在这个例子中,我编写了一个简单的 shell 脚本,而不是代码生成器,frob 它从一个输入文件生成多个输出文件:

<前>#!/bin/bash对于 {1..5} 中的 i;做{echo "这是输出 ${i},从 ${1} 生成.输入是:"猫 ${1}} > 输出${i}完毕

当我使用非 unity -j 因子运行这个 Makefile 时,我得到以下输出:

<前>$ make -j2./frob 输入./frob 输入cat output5 output4 output3 output2 output1 > output.concat$

我们看到 ./frob 在这里被调用了两次,这很糟糕.有什么方法可以构建这个规则,即使使用非统一的 -j 因子,配方也只会被调用一次?

我已经考虑过更改规则,以便只有一个预期的输出文件是目标,然后添加另一个没有配方的规则,使其目标是剩余的预期输出文件,而先决条件是第一个预期的输出文件.但我不确定这是否可行,因为我不知道我是否可以保证生成文件的顺序,因此最终可能会出现循环依赖.

解决方案

这就是 make 定义的工作方式.这样的规则:

foo bar baz : boz ;$(建造)

完全等同于编写这三个规则:

foo : boz ;$(建造)酒吧 : boz ;$(建造)巴兹 : 博兹 ;$(建造)

没有办法(在 GNU make 中)定义具有您想要的特征的显式规则;也就是说,对配方的一次调用将构建所有三个目标.

但是,如果您的输出文件和输入文件共享一个共同的基础,您可以编写这样的模式规则:

%.foo %.bar %.baz : %.boz ;$(建造)

奇怪的是,对于具有多个目标的隐式规则,GNU make 假设对配方的单次调用将构建所有目标,并且它的行为将完全符合您的要求.

I have a project which includes a code generator which generates several .c and .h files from one input file with just one invocation of the code generator. I have a rule which has the .c and .h files as multiple targets, the input file as the prerequisite, and the recipe is the invocation of the code generator. I then have further rules to compile and link the generated .c files.

This works fine with a -j factor of 1, but if I increase the j factor, I find I get multiple invocations of the code generator, up to the -j factor or the number of expected target files, whichever is smallest. This is bad because multiple invocations of the code generator can cause failures due to the generated code being written multiple times.

I'm not going to post my actual (large) code here, but I have been able to construct a small example which appears to demonstrate the same behavior.

The Makefile looks like this:

output.concat: output5 output4 output3 output2 output1
    cat $^ > $@

output1 output2 output3 output4 output5: input
    ./frob input

clean:
    rm -rf output*

Instead of a code generator, for this example I have written a simple shell script, frob which generates multiple output files from one input file:

#!/bin/bash

for i in {1..5}; do
    {
    echo "This is output${i}, generated from ${1}. input was:"
    cat ${1}
    } > output${i}
done

When I run this Makefile with non-unity -j factors, I get the following output:

$ make -j2 
./frob input
./frob input
cat output5 output4 output3 output2 output1 > output.concat
$

We see ./frob here gets invoked twice, which is bad. Is there some way I can construct this rule such that the recipe only gets invoked once, even with a non-unity -j factor?

I have considered changing the rule so that just one of the expected output files is the target, then adding another rule with no recipe such that its targets are the remaining expected output files, and the prerequisite is the first expected output file. But I'm not sure this would work, because I don't know if I can guarantee the order in which the files are generated, and thus may end up with circular dependencies.

解决方案

This is how make is defined to work. A rule like this:

foo bar baz : boz ; $(BUILDIT)

is exactly equivalent, to make, to writing these three rules:

foo : boz ; $(BUILDIT)
bar : boz ; $(BUILDIT)
baz : boz ; $(BUILDIT)

There is no way (in GNU make) to define an explicit rule with the characteristics you want; that is that one invocation of the recipe will build all three targets.

However, if your output files and your input file share a common base, you CAN write a pattern rule like this:

%.foo %.bar %.baz : %.boz ; $(BUILDIT)

Strangely, for implicit rules with multiple targets GNU make assumes that a single invocation of the recipe WILL build all the targets, and it will behave exactly as you want.

这篇关于来自一个配方和并行执行的多个目标的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆