Mac下Makefile依赖异常:all_2未重建,all_1正常,绝对路径可用吗?
问题根源:绝对路径目标与模式规则的匹配逻辑冲突
你遇到的问题核心在于Make的模式规则对相对路径和绝对路径目标的匹配逻辑不同,导致all_2无法正确关联绝对路径的.out文件和当前目录的.src源文件。
具体分析
我们拆解all_1和all_2的差异:
1. all_1为什么正常工作?
all_1的目标是相对路径dir1/a1.out,你的模式规则*/%.out : $(notdir %.src)会这样匹配:
- 模式
*/%.out匹配相对路径的子目录文件,%会被解析为a1(即文件名部分) - 依赖
$(notdir %.src)展开为a1.src,正好是当前目录下的源文件 - Make会自动对比
dir1/a1.out和a1.src的时间戳,发现a1.src更新时就触发重建
2. all_2为什么不触发重建?
all_2的目标是绝对路径$(DIR)/dir1/a1.out,此时你的模式规则*/%.out无法正确匹配:
*/%.out是相对路径模式,而绝对路径目标以/开头,Make不会将这个规则应用到绝对路径的目标上- Make找不到针对绝对路径
.out文件的构建规则,只会检查目标文件是否存在。因为$(DIR)/dir1/a1.out已经存在,Make就默认它是最新的,完全不会去关联当前目录的a1.src
另外,你的Makefile里还有一个小问题:ls -l $(outputs)是顶层命令,不管目标是否重建,每次运行make都会执行,建议把它放到all_2的规则体内,这样只在目标完成后才打印。
解决方案
我们可以调整模式规则,让它同时支持相对和绝对路径的目标,这里提供两种常用方案:
方案1:使用静态模式规则(推荐,更清晰)
直接将绝对路径目标与对应的源文件绑定:
DIR = ${HOME}/tmp outputs = $(DIR)/dir1/a1.out $(DIR)/dir2/a2.out all_1 : dir1/a1.out dir2/a2.out all_2 : $(outputs) ls -l $(outputs) # debug print # 静态模式规则:为每个绝对路径目标指定对应的源文件 $(outputs): $(DIR)/dir%/a%.out : a%.src @touch $@ @echo 'Build $@ from $<' # 保留原有的相对路径规则支持all_1 */%.out : $(notdir %.src) @touch $@ @echo 'Build $@ from $(notdir $*.src)'
方案2:通用模式规则(适配任意路径的.out文件)
如果需要更通用的规则,让任何路径(相对/绝对)的.out文件都依赖当前目录的同名.src文件:
DIR = ${HOME}/tmp outputs = $(DIR)/dir1/a1.out $(DIR)/dir2/a2.out all_1 : dir1/a1.out dir2/a2.out all_2 : $(outputs) ls -l $(outputs) # debug print # 通用规则:匹配所有.out文件,依赖当前目录的同名.src文件 %.out : $(CURDIR)/$(notdir %.src) @touch $@ @echo 'Build $@ from $(notdir $<)'
这里$(CURDIR)是Make内置变量,表示当前工作目录的绝对路径,确保能正确找到当前目录下的.src文件。
验证效果
修改后,再运行touch a1.src && make all_2,你会看到$(DIR)/dir1/a1.out被正常重建,debug打印也会显示更新后的文件时间戳。
内容的提问来源于stack exchange,提问作者Fredrik Johansson
相关产品推荐
相关产品推荐

