Makefile通配符规则问题:如何按目标关联对应依赖文件
解决Makefile二次扩展失效与冗余构建问题
问题分析
你原来的写法里有两个关键错误:
- 误用了
$%变量:在静态模式规则%.out: ...中,代表目标前缀(foo/bar/qux)的变量是$*,而不是$%——$%是用于归档文件成员(比如lib.a(foo.o))的变量,这里完全不适用。 - 使用
$<传递依赖不对:$<只会取第一个依赖,而你需要把所有对应的.cooked文件都传给build命令,应该用$^。
另外,冗余构建foo相关文件的核心原因是之前的规则没有限定范围,导致make触发了无关的依赖链。
修正后的Makefile写法
先明确基础定义,再写二次扩展规则:
# 定义要生成的目标文件 OUTFILES := foo.out bar.out qux.out # 保留原有的.cooked生成规则 %.cooked: %.raw # 这里写你的.cooked文件构建命令,比如: cook $< -o $@ # 启用二次扩展 .SECONDEXPANSION: # 修正变量使用,用$*匹配目标前缀,$^传递所有依赖 $(OUTFILES): %.out: $$(patsubst %.raw,%.cooked,$$(wildcard $$*-*.raw)) build $^ --output $@
针对动态生成.raw文件的补充说明
如果你的.raw文件不是预先存在,而是通过其他规则动态生成的,wildcard会因为文件不存在而找不到它们。这时候可以去掉wildcard,直接用模式匹配让自动推导依赖链:
.SECONDEXPANSION: $(OUTFILES): %.out: $$*-*.cooked build $^ --output $@
这种写法下,make会自动识别所有匹配foo-*.cooked的文件(无论是否已存在),并触发对应的.raw文件构建,且只会处理当前目标(比如bar.out)对应的前缀文件,不会冗余构建foo/qux的内容。
冗余构建的额外防范
如果仍然出现无关文件被构建,检查是否存在以下情况:
- 是否有全局的
all目标包含了所有.out文件,且make默认执行all?确保执行make bar.out时明确指定目标,不要触发all。 - 是否有其他隐式规则(比如
%.raw的生成规则)带有全局依赖?可以用.PHONY标记无关的伪目标,或者调整规则的依赖范围。
内容的提问来源于stack exchange,提问作者Aly
相关产品推荐
相关产品推荐

