makefile函数中的变量是否未正确扩展?

时间:2016-12-13 04:43:43

标签: makefile

这是一个玩具Makefile。 我想创建文件“a”,“b”,“c”以及“a.out”,“b.out”,“c.out”。

LIST=a b c
all: $(addsuffix .out,$(LIST))

define FUN
  in := $(1)
  out := $(1).out
  $$(in) :
        echo $(1) > $$(in)
  $$(out) : $$(in)
        echo $$(in) > $$(out)
endef
$(foreach p,$(LIST),\
  $(eval $(call FUN,$(p))))

当我使用“make -n”测试运行它时,版本GNU Make 4.1, 执行的实际命令是:

echo a > c
echo c > c.out
echo b > c
echo c > c.out
echo c > c
echo c > c.out

然而,预期的结果是:

echo a > a
echo a > a.out
echo b > b
echo b > b.out
echo c > c
echo c > c.out

有人可以帮助解释Makefile的行为或如何修复此脚本吗?感谢。

2 个答案:

答案 0 :(得分:3)

为什么不在任何地方使用$1变量而不是创建新变量?没有规则说你必须在扩展中使用变量。你可以把它写成:

define FUN
  $1 :
        echo $1 > $1
  $1.out : $1
        echo $1 > $1.out
endef

如果您不想这样做,可以像这样使用automatic variables

define FUN
  $1 :
        echo $$@ > $$@
  $1.out : $1
        echo $$< > $$@
endef

修改

如果没有看到某种现实的例子,很难判断。对你的问题的简短回答是否定的,没有什么神奇的方法来创造&#34;变量范围&#34;在makefile中。

您应始终使用$@$<和其他自动变量。这就是他们的目标。如果您有其他需要的变量赋值,并且您希望将它们设置为变量而不是直接使用调用参数,则只有两个选择:特定于目标的变量或constructed macro names

但我并没有真正看到&#34;特定目标变量列表的问题&#34;。为什么还要全局设置变量然后再将它们设置为特定目标?如果您只是将它们直接设置为特定于目标的变量,则只需编写一次。它并不清楚你到底发现了什么&#34;尴尬&#34;关于它们的使用,所以我不能说这是否足够。

此外,您应该在主目标上设置特定于目标的变量,而不是先决条件,因为特定于目标的变量是&#34;继承&#34;通过先决条件清单。

所以,就像这样:

define FUN
  $1.out : FOO = $(some complex thing)

  $1 :
        echo $$(FOO) > $$@
  $1.out : $1
        echo $$(FOO) from $$< > $$@
endef

答案 1 :(得分:1)

这是我尝试回答这个问题,它附带了对代码的繁琐修复。我在这里发布的原因是等待更好的答案。

从GNU Make手册(https://www.gnu.org/software/make/manual/make.html#Reading-Makefiles),立即评估目标和先决条件,并延迟配方部分。

在我的示例中,立即评估$$(out) : $$(in)。这就是我的预期。但echo $$(in) > $$(out)稍后会扩展。那时,$$(in)变为c$$(out)变为c.out。但那不是我想要的。

在我看来,一个尴尬的解决方法是使用特定于目标的变量(https://www.gnu.org/software/make/manual/make.html#Target_002dspecific)。现在Makefile如下所示:

LIST=a b c
all: $(addsuffix .out,$(LIST))

define FUN
  in := $(1)
  out := $(1).out
  $$(in) : in=$(1)
  $$(in) :
    echo $(1) > $$(in)
  $$(out) : $$(in)
    echo $$(in) > $$(out)
endef
$(foreach p,$(LIST),\
  $(eval $(call FUN,$(p))))

特定于目标的变量在$$(in) : in=$(1)中指定。 但是,如果配方部件中有多个变量,则必须添加多个特定于目标的变量,这看起来不太好。