GNU Make:在依赖列表中结合匹配模式使用文本函数的问题
问题根源
Makefile在解析阶段就会处理模式规则的依赖列表,此时$*还没有绑定具体的目标(比如build/x里的x),所以$(filter %/$*,$(list_of_files))中的$*是空字符串,筛选结果为空,自然不会触发任何依赖。
解决方案
有两种常用的解决方式:
方式一:使用二次展开(.SECONDEXPANSION)
通过.SECONDEXPANSION告诉Makefile,将规则的依赖延迟到匹配到具体目标后再展开,此时$*会被替换为目标对应的模式匹配部分。
修改后的Makefile:
list_of_files=a/x b/x a/y b/y c/z %: echo 0 $@ touch $@ # 启用二次展开 .SECONDEXPANSION: # 用$$*转义,二次展开时会替换为实际的$*值 build/%: $$(filter %/$$*,$(list_of_files)) echo 1 target $@ echo 1 prereq $? touch $@ .PHONY: all all: build/x echo
运行make all时,Makefile会先匹配到build/x,此时$$*展开为x,$(filter %/x,$(list_of_files))会筛选出a/x和b/x,触发这两个依赖的构建,再执行build/x的规则。
方式二:使用静态模式规则
如果能提前确定所有需要构建的build/%目标,可以用静态模式规则,明确列出目标集合,让$*在解析阶段就能绑定到具体的文件名。
修改后的Makefile:
list_of_files=a/x b/x a/y b/y c/z # 从list_of_files中提取唯一的文件名,生成build/xxx目标集合 build_targets := $(addprefix build/,$(sort $(notdir $(list_of_files)))) %: echo 0 $@ touch $@ # 静态模式规则:针对每个build_targets,匹配%为文件名部分 $(build_targets): build/%: $(filter %/$*,$(list_of_files)) echo 1 target $@ echo 1 prereq $? touch $@ .PHONY: all all: build/x echo
这里build_targets会生成build/x build/y build/z,静态模式规则中的$*会对应每个目标的文件名部分(比如build/x对应x),解析阶段就能正确筛选出对应的依赖文件。
验证效果
运行make all后,会先执行a/x和b/x的构建(触发第一个%规则),然后执行build/x的规则,输出类似:
echo 0 a/x 0 a/x touch a/x echo 0 b/x 0 b/x touch b/x echo 1 target build/x 1 target build/x echo 1 prereq a/x b/x 1 prereq a/x b/x touch build/x echo
内容的提问来源于stack exchange,提问作者111111
相关产品推荐
相关产品推荐

