【问题标题】:Unexplainable behavior in GNU makeGNU make 中无法解释的行为
【发布时间】:2016-01-06 10:56:12
【问题描述】:

我有以下 Makefile:

SHELLS   = $(call adjust, profile bash zsh)
adjust = $(foreach arg, $(1), $(DIR)/$(DOT)$(arg))

sys:
    $(eval DIR  = /etc)
    $(eval DOT  = )
usr:
    $(eval DIR  = $(wildcard ~))
    $(eval DOT  = .)

# Installation Recipes {{{1
shell-sys: $(SHELLS) | sys
    @echo $(SHELLS)
shell-usr: $(SHELLS) | usr
    @echo $(SHELLS)

$(SHELLS): $(DIR)/$(DOT)%: $(wildcard %/*)
    @echo $(SHELLS)

现在我运行make shell-sys 并期望得到以下结果:

$ make shell-sys
/etc/profile /etc/bash /etc/zsh
/etc/profile /etc/bash /etc/zsh
/etc/profile /etc/bash /etc/zsh
/etc/profile /etc/bash /etc/zsh

但是我得到的是以下内容:

$ make shell-sys
/profile /bash /zsh
/profile /bash /zsh
/profile /bash /zsh
/etc/profile /etc/bash /etc/zsh

内部静态模式规则$(DIR)$(DOT) 无法扩展,但是在普通规则中它们似乎可以正常扩展。我究竟做错了什么?有没有更好的方法来实现sysusr 目标的功能?

【问题讨论】:

    标签: macos bash makefile gnu-make


    【解决方案1】:

    在运行 any 配方(shell 命令)之前, make 将读取整个 Makefile。 当它这样做时,它扩展了依赖线。 配方本身只是作为递归扩展变量存储起来。 在这个阶段结束时,make 有一个依赖图。

    在你的情况下,make 扩展

    shell-sys: $(SHELLS) | sys
    

    鉴于$DIR$DOT 为空,$(SHELLS) 变为/profile /bash /zsh。 通过为 make 提供 --warn 命令行参数,您可以获得一些关于 make 扩展这些空变量的提示。 这样就好像你写了:

    shell-sys: /profile /bash /zsh | sys
        @echo $(SHELLS)
    
    /profile /bash /zsh: /%:
        @echo $(SHELLS)
    

    (我怀疑您的磁盘上有一个名为 % 的文件夹,所以我假设 $(wildcard ...) 扩展为空。)

    一旦它的小手有了依赖图, make 可以走路了, 执行配方。 你要求它构建shell-sys, 所以它首先尝试构建/profile。 [大概。 Makefiles 依赖于这种隐式的依赖顺序被破坏了恕我直言。]

    Make 现在构建 /profile。 它知道怎么做,你之前告诉过它。 它扩展了配方。 @echo $(SHELLS) 变为 @echo /profile /bash /zshMakeecho /profile /bash /zsh 传递给shell,但由于@ 前缀,它没有告诉你它已经这样做了。 echo 尽职尽责地打印/profile /bash /zsh

    目标/bash/zsh 也是如此。

    接下来我们开始构建sysMake 扩展了sys 的配方。 扩展中的每一行都被传递给 shell 的新调用。 然而扩展是空的, 所以外壳没有被调用。 作为副作用DIR 变为 /etc

    最后是shell-sys 的配方。 希望您现在可以看到它扩展到 @echo /etc/profile /etc/bash /etc/zsh

    你的配方有很多不喜欢的地方, 但我能给出的最大建议是不要让$(eval ...) 在配方执行时扩展。

    【讨论】:

    • 谢谢,我了解到关于仅订购先决条件的错误想法,但我想我现在明白了。我尝试用仅限目标的变量来做,让我们看看结果是否更好......
    猜你喜欢
    • 2011-05-06
    • 1970-01-01
    • 1970-01-01
    • 2015-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-06
    • 1970-01-01
    相关资源
    最近更新 更多