GNU Make中ifeq对比shell输出值与字面量0不匹配问题
GNU Make中shell输出值与字面量ifeq判断不匹配问题说明
核心原因
你遇到的判断异常本质是两个问题叠加导致的:
- GNU Make两阶段执行逻辑的认知偏差
GNU Make处理Makefile完全分为两个独立阶段:- 第一阶段是全局解析阶段:Make逐行读取整个Makefile,展开所有顶层变量、函数,处理
ifeq/ifneq这类条件判断,完成所有目标、规则的定义,这个阶段不会执行任何目标下写的shell命令。 - 第二阶段是目标执行阶段:Make根据依赖关系确定要构建的目标后,才会逐行执行对应目标下的shell命令。
你代码里的两个ifeq块写在zero-test目标的命令块外部,属于第一阶段就会完成判断的逻辑,但给ZERO_VALUE赋值的$(eval ZERO_VALUE := $(shell echo 0))写在zero-test的命令行里,第一阶段根本不会执行,此时ZERO_VALUE是空值。
- 第一阶段是全局解析阶段:Make逐行读取整个Makefile,展开所有顶层变量、函数,处理
- 代码拼写错误导致第一个判断歪打正着
你第一个ifeq的比较值写的是$(shel echo 0),把内置函数shell拼错成了shel,Make识别不到这个函数,直接把它展开为空值。空值和当时为空的ZERO_VALUE判断相等,才输出了"1st approach Value is zero",完全是巧合,不是真的拿到了正确的变量值。
等Make执行到zero-test目标的命令时,才会跑eval给ZERO_VALUE赋值为0,所以你echo能看到值是0,但这时候两个ifeq的判断早就结束了,不会再重新计算。
让字面量0判断正常生效的方案
方案1:把变量赋值挪到顶层(推荐,符合Makefile常规写法)
把shell调用赋值的逻辑写到目标外部的顶层位置,让Make在全局解析阶段就完成变量求值,同时用strip函数清理掉shell输出可能带的首尾空白、不可见字符,避免脏数据影响判断:
# 全局解析阶段就完成shell调用赋值 ZERO_VALUE := $(shell echo 0) # 清理首尾不可见字符、空白,做保险处理 ZERO_VALUE := $(strip $(ZERO_VALUE)) zero-test: echo "Echo-ed value: ${ZERO_VALUE}" ifeq ($(ZERO_VALUE),0) echo "2nd approach Value is zero" else echo "2nd approach Value is not zero" endif
执行make zero-test就能得到符合预期的判断结果。
方案2:必须在目标执行阶段动态取值时,把判断逻辑放到shell中实现
如果业务逻辑确实需要在执行目标命令时才动态取值(比如依赖其他命令的执行结果),就不要用Make原生的ifeq(它只在解析阶段生效),直接把相等判断写在shell逻辑里:
zero-test: $(eval ZERO_VALUE := $(shell echo 0)) echo "Echo-ed value: ${ZERO_VALUE}" # 用shell语法做判断,注意$符号需要双写转义 if [ "$${ZERO_VALUE}" = "0" ]; then \ echo "Value is zero"; \ else \ echo "Value is not zero"; \ fi
踩坑提示:如果你的业务shell命令是在Windows环境、或者调用的命令可能输出Windows风格的
\r换行符、首尾空格,一定要加$(strip)做清理,否则哪怕肉眼看到值是0,带了不可见字符也会导致和字面量判断不相等。
内容的提问来源于stack exchange,提问作者Bayu
相关产品推荐
相关产品推荐

