当使用多个作业时,Makefile会两次执行同一个配方。

问题描述 投票:0回答:1

我正在看下面的玩具Makefile来追踪一个bug。

all: hey bye

hey bye: hi
    cat hi
    touch hey bye

在这种情况下,我创建了 hi 文件。

然后我运行 make -j 2 all 并得到以下输出。

cat hi
cat hi
hey
touch hey bye
hey
touch hey bye

而如果我用 make -j 1 all这些命令只被执行一次。调试输出相当啰嗦,但据我所知,它执行了两次,因为它试图满足了 heybye 有两个不同的工作。

如何防止这种情况的发生?这种行为正确吗?为什么它认为一次运行一个命令两次会使它完成得更快?

makefile gnu
1个回答
3
投票

行为是正确的,因为你误解了你告诉make的内容。

你可以在 GNU make手册.

这条规则:

hey bye: hi
        ...

是否 告诉make,调用一次配方就能建立两个目标。 相反,make的解释方式与你写的完全一样。

hey: hi
        ...
bye: hi
        ...

也就是说,你已经声明了两个完全不同的目标,每个目标都将由一个单独的调用来创建 ....

当你运行使没有 -j 它认为 hey 是过时的,并运行配方。 然后它查看 bye,现在(因为之前的配方刚刚更新了)它是最新的,所以它似乎可以工作。

但如果你用 -j2,使看到 hey 是过时的,并开始该工作,然后寻找更多的工作。 现在当它检查 bye的配方 hey 还没有更新它,所以make认为它仍然是过时的,并启动另一个配方的实例。

解决这个问题的最好方法取决于你实际使用的细节,你还没有给出。

如果你的输入和输出是通过目标和前提条件的名称相关联的,你可以写一个模式规则。 与显式规则不同,多目标模式告诉使一次调用配方就能构建所有的目标。

%.x %.y : %.z
        ...

如果这行不通,而且你愿意限制你的编译工作使用GNU make 4.3或更高版本,你可以利用 "分组目标 "的特性。

hey bye &: hi
        ...

如果不可行的话,你就得使用一个哨兵目标,比如:

all: hey bye

hey bye: .sentinel ;

.sentinel: hi
        ...
        @touch $@
© www.soinside.com 2019 - 2024. All rights reserved.