首页 > 解决方案 > Make:一次调用两个虚假目标时“对目标无事可做”

问题描述

简单的生成文件:

.PHONY:\
gitbranch-foo
gitbranch-foo: dir=./foo
gitbranch-foo: git-spawn-branch

.PHONY:\
gitbranch-bar
gitbranch-bar: dir=./bar
gitbranch-bar: git-spawn-branch

.PHONY:\
git-spawn-branch
git-spawn-branch:
    @$(call  git_branch,$(dir),$(branch))
    @echo > /dev/null

define git_branch
    cd $(1);                                         \
    git checkout -b   $(2)            || true;       \
    git push     -u   origin     $(2) || true;
endef

一次调用两个规则:

make gitbranch-foo gitbranch-bar branch=something/blah/blah  -rRd

如您所见,'foo' repo 切换成功,但 make 甚至没有处理 'bar' repo。为什么?

Switched to a new branch 'something/blah/blah'  <-- 'foo' switches successfully
Total 0 (delta 0), reused 0 (delta 0)
remote: 
remote: Create pull request for something/blah/blah:
remote:   ....
remote:
To xyz.net:foo
 * [new branch]      master -> something/blah/blah
Branch 'something/blah/blah' set up to track remote branch 'something/blah/blah' from 'origin'.

make: Nothing to be done for 'gitbranch-bar'. <-------- 'bar' is not even processed   why?

'make' 的调试输出如下所示:

Branch 'something/blah/blah' set up to track remote branch 'something/blah/blah' from 'origin'.
Everything up-to-date
Reaping winning child 0x563e010f42d0 PID 2092 
Live child 0x563e010f42d0 (git-spawn-branch) PID 2096
Reaping winning child 0x563e010f42d0 PID 2096
Removing child 0x563e010f42d0 PID 2096 from chain.
  Successfully remade target file 'git-spawn-branch'.
 Finished prerequisites of target file 'gitbranch-foo'.
Must remake target 'gitbranch-foo'.
Successfully remade target file 'gitbranch-foo'.
Considering target file 'gitbranch-bar'.
 File 'gitbranch-bar' does not exist.
  Pruning file 'git-spawn-branch'.
 Finished prerequisites of target file 'gitbranch-bar'.
Must remake target 'gitbranch-bar'.
Successfully remade target file 'gitbranch-bar'.
make: Nothing to be done for 'gitbranch-bar'.

但不能从中做出正面或反面。任何关于“make”为何以这种方式表现的见解都值得赞赏。

注意:我知道我可以像下面这样重构 makefile 来让它完成我的竞标 - 我只是想了解为什么原始方法没有按预期工作

.PHONY:\
gitbranch-foo
gitbranch-foo:
    @$(call  git_branch,./foo,$(branch))
    @echo > /dev/null

.PHONY:\
gitbranch-bar
gitbranch-bar:
    @$(call  git_branch,./bar,$(branch))
    @echo > /dev/null

define git_branch
    cd $(1);                                         \
    git checkout -b   $(2)            || true;       \
    git push     -u   origin     $(2) || true;
endef

标签: makefilegnu-make

解决方案


答案完全是由于make的规则,与此处的任何其他标签无关(我将删除所有其他标签)。不起作用的makefile说:

  • 建设gitbranch-foo,我们必须建设git-spawn-branch
  • 建设gitbranch-bar,我们必须建设git-spawn-branch

(当然还有构建git-spawn-branch自身的代码和其他相关的东西,但让我们停在这里)。

然后运行​​make,告诉它同时构建gitbranch-foogitbranch-bar.

Make 选择其中一个来构建——<code>gitbranch-foo,在本例中——并开始构建。 哦,嘿,make 对自己说,这需要git-spawn-branch构建,我们还没有这样做git-spawn-branchOff go make,根据规则构建。现在它已经建成了!使可以回到建筑物gitbranch-foo。这将执行剩余的配方,它是空的。

如果允许并行构建,make现在也可以在构建gitbranch-bar时开始gitbranch-foo构建。如果没有,我们等待gitbranch-foo此时完全建成。无论哪种方式,我们都很快开始构建gitbranch-bar嗯, make 对自己说,这需要git-spawn-branch构建......但幸运的是,我已经做到了!向前!让我们做剩下的gitbranch-bar吧! 这需要执行空的配方,这非常快。

制作完成。它已经构建了所需的一切。

(有效的 makefile$call直接从每个规则中明智地使用,因此$call需要为每个目标运行扩展为的命令,而不是隐藏在可以只构建一次并且永远不需要运行的第三个目标中更远。)

(请注意,gmake 文档提到.PHONY每次都运行一个规则。这意味着每次调用make一次,而不是每次调用该规则一次。)


推荐阅读