我正在看下面的玩具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
这些命令只被执行一次。调试输出相当啰嗦,但据我所知,它执行了两次,因为它试图满足了 hey
和 bye
有两个不同的工作。
如何防止这种情况的发生?这种行为正确吗?为什么它认为一次运行一个命令两次会使它完成得更快?
行为是正确的,因为你误解了你告诉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 $@