通过$(shell...)动态定义多个GNU Makefile变量失败,求排查?
问题描述
我有一个包含变量定义的文件(如iostruct.def),内容示例如下:
VARIABLE_A=/some/path VARIABLE_B=/another/path ...
我希望在GNU Makefile中读取该文件,为所有路径添加前缀(如/tmp),并将其作为常规Make变量使用。我的尝试代码如下,但未能成功:
vars := $(shell sed -r "s|=(\/.*)|=/tmp\1|" iostruct.def) $(eval $(foreach v,$(vars),$(v))) all: @echo $(VARIABLE_A) @echo $(VARIABLE_B)
结果VARIABLE_A的值变为/tmp/some/path VARIABLE_B=/tmp/another/path,而VARIABLE_B为空。请问我哪里出错了?
注:重点在于通过$(shell...)动态定义多个Make变量,路径添加/tmp前缀仅为示例。
问题原因与解决方法
错误原因
$(shell ...)命令返回的结果是单行字符串(所有行用空格连接),而非多行列表。因此$(foreach v,$(vars),$(v))中的vars是一整串包含所有变量定义的文本,foreach只会循环一次,把整串内容当作单个变量定义执行,导致VARIABLE_A被赋值为全部内容,后续变量未被正确解析。
解决方法
方法1:拆分shell输出为列表
将shell返回的多行内容拆分为Make可识别的列表,用tr命令把换行符替换成空格(Make的列表分隔符):
# 处理文件内容并转为空格分隔的变量定义列表 vars := $(shell sed -r "s|=(\/.*)|=/tmp\1|" iostruct.def | tr '\n' ' ') # 逐个解析并定义变量 $(foreach v,$(vars),$(eval $(v))) all: @echo $(VARIABLE_A) @echo $(VARIABLE_B)
方法2:利用include加载临时文件
更符合Make原生逻辑的方式,先生成处理后的临时文件,再通过include加载变量:
# 生成处理后的临时变量定义文件 .tmp.def: iostruct.def sed -r "s|=(\/.*)|=/tmp\1|" $< > $@ # 加载临时文件中的变量 include .tmp.def all: @echo $(VARIABLE_A) @echo $(VARIABLE_B) # 清理临时文件 clean: rm -f .tmp.def
关键说明
- 方法1的核心是将多行输出转为空格分隔的列表,让
foreach能遍历每个独立的变量定义。 - 方法2避免了
eval和shell的复杂嵌套,可读性更强,是Make处理外部变量文件的常规做法。
内容的提问来源于stack exchange,提问作者wojas
相关产品推荐
相关产品推荐

