GNU make:一个规则中有多个目标

33
如果我有一个这样的Makefile规则:

可能的重复:
从单个源文件生成几个目标的GNU Makefile规则

如下所示:

a b c:
    echo "Creating a b c"
    touch a b c

output: a b c
    cat a b c > output

我执行 make -j9 output

make看到有三个依赖项(a,b,c),查找如何生成它们:(即上面的"a b c"规则), 但接下来会发生什么呢? 它难道不应该意识到只需要运行一次"a b c"规则就可以创建所有3个目标吗?

这实际上是make的工作方式:

[pavel@orianna test]$ make -j9 output -n
echo "Creating a b c"
touch a b c
echo "Creating a b c"
touch a b c
echo "Creating a b c"
touch a b c                                                                                                                                                                                                                                                                    
cat a b c > output                                                                                                                                                                                                                                                             
[pavel@orianna test]$

同样的配方会运行3次,每个依赖项都会运行一次,以规则"output"为例!

有人知道为什么会这样吗?


相关链接:https://dev59.com/xHA75IYBdhLWcg3w8-BJ 和 https://dev59.com/83A85IYBdhLWcg3wCe5Z - krlmlr
从GNU make 4.3版本开始,这已经被分组目标支持。您只需要将:更改为&:即可。https://www.gnu.org/software/make/manual/make.html#Multiple-Targets - jonas-schulze
2个回答

33

您的a b c:规则告诉Make如何构建任何一个这些目标,而不是如何构建所有它们。Make无法聪明到分析命令并推断运行一次规则将构建所有三个目标。Make从output规则中知道必须重新构建abc,因此它运行第一条规则一次用于a,一次用于b,以及一次用于c

如果要单独重建它们,请执行以下操作:

a b c:
    echo "Creating $@"
    touch $@

如果您想一次性重建它们所有,请执行以下操作:

.PHONY: things
things:
    echo "Creating a b c"
    touch a b c

output: things
    cat a b c > output

或者更好的选择:

THINGS = a b c
.PHONY: things
things:
    echo "Creating $(THINGS)"
    touch $(THINGS)

output: things
    cat $(THINGS) > output

3
很棒的回答!谢谢。创建一个虚假目标是唯一的方式吗?还是有更简洁的方法来表示“通过此规则构建a和b和c”? - Pavel
@Pavel,我不知道有更好的方法(而且我可能会选择第一种选项)。但是我仍然在努力理解AUZKamath的答案。 - Beta
13
请参阅http://www.cmcrossroads.com/ask-mr-make/12908-rules-with-multiple-outputs-in-gnu-make,了解处理此场景的各种方法,包括在gmake中指定具有多个输出的规则的唯一“正确”方法(当然是模式规则!)。 - Eric Melski

10

a b c是三个不带前置条件的不同目标/目标。也就是说,只要请求,它就会构建该目标。

a b c:
    echo "Creating a b c"
    touch a b c
你正在请求make构建名为output的目标,并将a、b、c作为前提条件。因此,目标a、b、c会依次构建,最后构建输出。
在你的情况下,只要调用其中一个目标,所有目标都不可避免地被构建。为了避免冗余构建,您需要将前提条件添加到目标a、b、c中。仅在不存在“a”时才构建目标“a”。对于b和c同样如此。
a b c: $@
    echo "Creating a b c"
    touch a b c

然而,这并不可取。理想情况下,Makefile的目标应该非常具体。


2
这个可以运行,但我不知道为什么。是杰克·凯利让你来的吗? - Beta
1
然而,当使用 make -j3 a b c 运行时,会创建三个作业。 - krlmlr
2
有人能解释一下这是如何工作的吗?我无法通过阅读https://www.gnu.org/software/make/manual/make.html#index-_0024_0040来解释它。 - Xiphias
1
@krmlr @Xiphias 的诀窍在于,当 make 考虑 a 时,它看到规则 a: a。只有当目标比其任何先决条件旧或其任何先决条件不存在时,才需要重建目标。这里第一个情况永远不成立,第二个情况仅在 a 尚不存在时为真。在 touch 之后,b: bc: c 不需要被重建。(至于 -j3,三个进程看到了 a: ab: bc: c,并在任何 touch 之前对它们进行了处理。) - Kirill Bulygin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接