如何将Makefile子规则的变量变更信息传递至父规则(上游依赖)
问题
我需要在Makefile的规则中修改变量,让新值全局可用——具体是把子规则触发的信息传递给父规则,让父规则能调整行为。
目标特定变量满足不了需求,因为它只能在依赖图下游生效:变量新值仅作用于该目标的脚本及其所有前置条件的脚本,没法传递到父规则的脚本里。
目前我用文件系统记录全局信息,父规则读取文件来获取值,示例Makefile如下:
opt = '' all: b @echo global opt = ${opt} @echo file opt = $(shell cat opt) echo '' >opt b: opt = 'b' b: a @echo b-specific opt = ${opt} cat a >b echo 'b' >opt a: touch a clean: -rm -f a b opt
执行make clean; make; make的输出符合预期:
rm -f a b opt touch a b-specific opt = b cat a >b echo 'b' >opt global opt = file opt = b echo '' >opt global opt = file opt = echo '' >opt
现在想不用文件读写,实现依赖图上游的信息更新与传递,需要适配GNU Make 4.3,标准Make的方案也可参考。
解决方案
方法1:递归调用Make(GNU Make兼容)
利用递归make的特性,在子规则执行完成后,通过命令行参数将结果传递给上层的make实例,避免文件读写。
示例Makefile:
ifeq ($(OPT_FROM_B),) all: @# 首次调用先执行b规则,获取值后重新触发make $(MAKE) b OPT_FROM_B='b' @echo global opt = $(OPT_FROM_B) else all: b @echo global opt = $(OPT_FROM_B) b: a @echo b-specific opt = 'b' cat a >b a: touch a endif clean: -rm -f a b
执行make clean; make; make的输出:
rm -f a b touch a b-specific opt = 'b' cat a >b global opt = b global opt =
方法2:eval+二次展开(GNU Make 4.3+专属)
借助GNU Make的$(eval)函数直接在规则脚本中修改全局变量,配合.SECONDEXPANSION确保变量在规则执行阶段重新展开。
示例Makefile:
opt = '' .SECONDEXPANSION: all: b @echo global opt = $(opt) @# 重置全局变量 $(eval opt = '') b: a @echo b-specific opt = 'b' cat a >b @# 直接修改全局变量 $(eval opt = 'b') a: touch a clean: -rm -f a b
执行make clean; make; make的输出:
rm -f a b touch a b-specific opt = 'b' cat a >b global opt = b global opt =
方法3:标准Make兼容方案(轻量文件依赖)
标准Make没有扩展特性,可通过生成临时Makefile片段的方式传递变量,本质是利用Make的include机制,比通用数据文件更贴合Make的工作逻辑:
示例Makefile:
opt = '' -include opt.mk all: b @echo global opt = $(opt) @# 清理临时片段 -rm -f opt.mk b: a @echo b-specific opt = 'b' cat a >b @# 生成变量定义的Makefile片段 @echo 'opt = ''b''' > opt.mk a: touch a clean: -rm -f a b opt.mk
内容的提问来源于stack exchange,提问作者0mid
相关产品推荐
相关产品推荐

