GNU make 中 ifdef 为什么读不到目标专属变量?
数据阿明
结论
ifdef VAR2 没有生效,因为 GNU make 读取 Makefile 时就会判断 ifdef。这时,目标专属变量 VAR2 还不在 target 的变量作用域中。等到执行 target 的配方时,VAR2 才有值,因此输出中会出现 value2,而 VAR3 仍只包含 value。
原写法为何得到这个输出
GNU make 读取到:
VAR=value
target: VAR2=value2
全局变量 VAR 已经定义,所以第一个 ifdef VAR 成立。VAR2 是 target 的目标专属变量,只在构建该目标及执行其配方时可用。因此,读取 Makefile 并判断第二个 ifdef VAR2 时,条件不成立。
于是,VAR3+=$(VAR) 会被加入,VAR3+=$(VAR2) 则不会。执行配方时,$(VAR2) 展开为 value2,$(VAR3) 展开为 value,最终输出为 value value2 value。
让 VAR2 参与 VAR3 的展开
如果希望 VAR3 在 target 的上下文中包含这两个变量,可以把 VAR3 定义为目标专属的递归变量:
VAR=value
target: VAR2=value2
target: VAR3 = $(VAR) $(VAR2)
target:
@echo $(VAR) $(VAR2) $(VAR3)
这里使用递归赋值 =,右侧会等到变量被使用时才展开。执行配方时,VAR 和目标专属变量 VAR2 都可用,因此输出为:
value value2 value value2
如果确实需要按条件选择内容
GNU make 的 ifdef 指令不会在构建目标时重新判断。如果需要等到变量展开时再检查条件,可以用递归变量配合 $(if ...) 函数,例如:
VAR=value
target: VAR2=value2
VAR3 = $(if $(VAR),$(VAR)) $(if $(VAR2),$(VAR2))
target:
@echo $(VAR) $(VAR2) $(VAR3)
$(if ...) 会在展开 VAR3 时求值,因此能读取配方上下文中的 VAR2。如果只需组合这些变量,前面的目标专属 VAR3 = $(VAR) $(VAR2) 写法更直接。
备注:内容仅供参考。
