为什么我需要 eval 来设置 makefile 函数中的变量?
Why do I need eval to set variable in makefile function?
如果我在 gnu makefile 的顶部有以下内容:
$(if _,a:=1)
$(info a=$a)
编译失败(make-3.81: *** No rule to make target '=1', needed by 'a'. Stop.
,或者 *** missing separator. Stop.
如果我排除了冒号)。我知道我可以通过使用 eval
来解决这个问题,但我不明白为什么需要它。这不应该扩展为 a:=1
,被解析,并将 a
设置为 1
吗?
在您的例子中,if
函数作为它的第二个参数 (a:=1
) 求值,但这不会作为 make 变量赋值依次求值。使用您的 make 版本,它成为规则。这可能是由于 make 在语法上解析 makefile 的方式。它不认为此 if
语句可以是变量赋值,因为(在扩展之前)它看起来像有效的 make 变量赋值的 none。所以 if
语句得到了扩展,但是 make 将结果视为变量赋值已经太迟了...
您可以使用:
a := $(if _,1)
或:
ifneq (_,)
a := 1
endif
或:
$(if _,$(eval a := 1))
或:
$(eval $(if _,a := 1))
最后两种形式之所以有效,是因为根据定义,eval
函数参数扩展的结果被处理为普通的 make 语句。
I'm not understanding why it's required
嗯,就是这样的设计。
评估程序总是执行(递归)扩展(除了 "the initial evaluation",后续扩展可以被 =
有效停止,即 "lazy assignment"),但扩展程序从不评估, 除非明确告知(基本上, $(eval ...)
就是这样一个从扩展切换到评估的命令)。
考虑一下:
x := 0
y := 1
# z is set to "y<space><equal><space><dollar>x"
z = y = $x
# [0] [1] [y = $x]
$(info [$x] [$y] [$(value z)])
# error as "y = $x" will not be re-evaluated
#$z
# effectively sets y to "0"
$(eval $z)
# [0] [0] [y = $x]
$(info [$x] [$y] [$(value z)])
从 make 的角度来看 $(if cond,x=y)
与 $z
没有太大区别 --- 它已扩展但未评估。无论站在哪里。只需将 $(...)
形式的任何内容视为 "data",而不是 "code"。
如果我在 gnu makefile 的顶部有以下内容:
$(if _,a:=1)
$(info a=$a)
编译失败(make-3.81: *** No rule to make target '=1', needed by 'a'. Stop.
,或者 *** missing separator. Stop.
如果我排除了冒号)。我知道我可以通过使用 eval
来解决这个问题,但我不明白为什么需要它。这不应该扩展为 a:=1
,被解析,并将 a
设置为 1
吗?
在您的例子中,if
函数作为它的第二个参数 (a:=1
) 求值,但这不会作为 make 变量赋值依次求值。使用您的 make 版本,它成为规则。这可能是由于 make 在语法上解析 makefile 的方式。它不认为此 if
语句可以是变量赋值,因为(在扩展之前)它看起来像有效的 make 变量赋值的 none。所以 if
语句得到了扩展,但是 make 将结果视为变量赋值已经太迟了...
您可以使用:
a := $(if _,1)
或:
ifneq (_,)
a := 1
endif
或:
$(if _,$(eval a := 1))
或:
$(eval $(if _,a := 1))
最后两种形式之所以有效,是因为根据定义,eval
函数参数扩展的结果被处理为普通的 make 语句。
I'm not understanding why it's required
嗯,就是这样的设计。
评估程序总是执行(递归)扩展(除了 "the initial evaluation",后续扩展可以被 =
有效停止,即 "lazy assignment"),但扩展程序从不评估, 除非明确告知(基本上, $(eval ...)
就是这样一个从扩展切换到评估的命令)。
考虑一下:
x := 0
y := 1
# z is set to "y<space><equal><space><dollar>x"
z = y = $x
# [0] [1] [y = $x]
$(info [$x] [$y] [$(value z)])
# error as "y = $x" will not be re-evaluated
#$z
# effectively sets y to "0"
$(eval $z)
# [0] [0] [y = $x]
$(info [$x] [$y] [$(value z)])
从 make 的角度来看 $(if cond,x=y)
与 $z
没有太大区别 --- 它已扩展但未评估。无论站在哪里。只需将 $(...)
形式的任何内容视为 "data",而不是 "code"。