GNU Make中目标特定变量在ifdef中不生效的原因及解决方法
GNU Make目标特定变量在ifdef中不生效的问题分析与解决
问题重现
以下是存在问题的Makefile代码:
VAR=value target: VAR2=value2 ifdef VAR VAR3+=$(VAR) endif ifdef VAR2 VAR3+=$(VAR2) endif target: @echo $(VAR) $(VAR2) $(VAR3)
执行make target时,实际输出为value value2 value,但预期输出应为value value2 value value2。
问题原因
GNU Make的执行分为两个明确的阶段:
- 解析阶段:Make会先完整读取并解析整个Makefile,处理所有全局变量定义、条件判断(
ifdef/ifndef这类指令)、规则结构。此时目标特定变量(如绑定到target的VAR2)尚未关联到目标,Make在解析阶段无法感知该变量的存在,因此第二个ifdef VAR2条件不成立,VAR3仅被追加了全局变量VAR的值。 - 执行阶段:解析完成后,Make才会执行目标的命令逻辑,此时目标特定变量
VAR2才会生效,所以echo能输出VAR2的值,但VAR3的内容已经在解析阶段确定,不会再被更新。
解决方法
方法1:将变量逻辑移至目标命令(Shell层面处理)
把VAR3的判断和赋值放到目标的Shell命令中,利用执行阶段能获取目标特定变量的特性完成赋值:
VAR=value target: VAR2=value2 target: @VAR3="$(VAR)" ; \ if [ -n "$(VAR2)" ]; then VAR3="$VAR3 $(VAR2)"; fi ; \ echo $(VAR) $(VAR2) $$VAR3
方法2:使用递归展开变量结合$(if)函数
递归展开变量会在被使用时才完成展开,而非解析阶段。用$(if)函数替代ifdef指令,让变量判断延迟到执行阶段:
VAR=value target: VAR2=value2 VAR3 = $(VAR)$(if $(VAR2), $(VAR2)) target: @echo $(VAR) $(VAR2) $(VAR3)
方法3:通过$(eval)在执行阶段动态赋值
$(eval)指令会在执行阶段执行Makefile代码,此时能获取目标特定变量,从而动态修改VAR3:
VAR=value target: VAR2=value2 target: $(eval VAR3 := $(VAR)) $(eval ifdef VAR2 ; VAR3 += $(VAR2) ; endif) @echo $(VAR) $(VAR2) $(VAR3)
以上三种方法执行make target后,均会输出预期的value value2 value value2。
内容的提问来源于stack exchange,提问作者user377486
相关产品推荐
相关产品推荐

