Makefile中变量赋值失效、取值为空如何解决
问题根因
核心问题是混淆了Makefile变量和Shell变量的解析时机,两者是完全独立的两套体系:
Make会在执行任何Shell命令之前,先把整个target下所有代码里的Make语法(包括$(shell)、$(subst)这类函数、$(XXX)格式的变量引用)全部提前展开完成,之后才会把展开后的整段代码丢给Bash执行。你写在while循环里的逻辑是Shell运行时才会跑的,循环里读到的CURRENT_LINE是Shell变量,解析阶段的Make根本看不到这个变量,自然拿不到值。
逐个说明几种错误写法的问题:
LINE=$(shell echo "$$CURRENT_LINE"):$(shell ...)是Make解析阶段就执行的函数,这时候循环还没跑,Shell里根本没有CURRENT_LINE这个变量,执行echo $CURRENT_LINE只能拿到空字符串,最终赋值给Make变量LINE的自然是空值。LINE=$$(CURRENT_LINE):这里写的是Shell的命令替换语法,相当于让Bash去执行名为CURRENT_LINE的命令拿输出,但CURRENT_LINE本身是变量不是可执行命令;更关键的是后面输出用的$(LINE)是Make变量引用,Make在解析阶段就会把它替换成空,根本等不到Shell运行时赋值。y=$(subst :, ,$$CURRENT_LINE):$(subst)是Make自带的字符串替换函数,解析阶段执行时拿到的输入只是字面量$CURRENT_LINE,根本不是循环读到的文件行内容,后续$(y)同样是Make变量,解析阶段就被展开为空。
解决方法
只要是Shell运行时(比如循环、条件判断内)生成的变量,所有处理逻辑全部用Shell语法实现,不要掺杂Make函数、Make变量引用,记住两个规则即可:
- 所有Shell变量的引用,在Makefile的命令段里都要写双美元符
$$转义,单个$开头的$(XXX)Make会默认当成自己的变量提前展开。 - 字符串处理、赋值等操作如果依赖运行时的Shell变量,直接用Shell原生语法实现,不要调用Make的内置函数。
修正后的可运行代码如下:
SHELL = bash target: while read -r CURRENT_LINE; do \ echo "$$CURRENT_LINE" ; \ # 直接用Shell语法给Shell变量LINE赋值 LINE="$$CURRENT_LINE" ; \ # 引用Shell变量必须用$$转义 echo "line:-$$LINE" ; \ # 字符串替换用Shell自带的替换语法,不用Make的subst y=$${CURRENT_LINE//:/ } ; \ echo "y:- $$y"; \ done < sample_file.txt ;
如果确实需要把Shell运行时拿到的值存为Make变量供后续其他target使用,不能直接在Shell代码里赋值,需要借助eval做延迟展开或者临时文件转存,但这类场景非常少见,绝大多数情况直接用Shell变量完成段内逻辑即可。
内容的提问来源于stack exchange,提问作者piyush-balwani
相关产品推荐
相关产品推荐

