PAYATHON 2026

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) 写法更直接。

备注:内容仅供参考。