为何依赖无变更时Makefile的.bin配方仍会重复执行?
Make重复执行配方的原因及解决方法
问题场景
配置文件如下:
$ ls base.mk file.ext Makefile $ cat Makefile include base.mk algorithm = another-alg $ cat base.mk source = file.ext binary = $(algorithm) algorithm = the-alg .bin: $(binary) touch .bin $(binary): $(source) echo "compiling..." > $(binary)
执行make .bin首次能正常编译,但再次执行时,配方会重复运行,预期应该提示.bin无需更新。实际运行输出:
$ make .bin echo "compiling..." > another-alg touch .bin $ make .bin echo "compiling..." > another-alg touch .bin
若不在Makefile中重新赋值algorithm,则能得到预期行为,但需求是通过引入base.mk并调整变量来复用通用逻辑,创建多个相似项目。
问题原因
核心问题是Make解析规则时的变量展开时机:
- Make在解析规则的目标和依赖时,会立即展开变量,而非延迟到执行阶段。
- 当前配置中,
Makefile先include base.mk,此时base.mk内的执行顺序是:先定义binary = $(algorithm),再设置algorithm = the-alg,接着解析.bin: $(binary)规则——此时$(binary)会立即展开为当前的algorithm值the-alg,因此.bin的依赖被固定为the-alg。 - 之后
Makefile重新赋值algorithm = another-alg,虽然编译的目标变成了another-alg,但.bin的依赖依然是不存在的the-alg。每次运行make .bin时,Make都会认为.bin的依赖缺失,从而重复触发编译流程。
解决方法
最直接的解决方案是调整变量赋值顺序,先在Makefile中设置algorithm,再引入base.mk:
# 修改后的Makefile algorithm = another-alg include base.mk
这样,当include base.mk时,algorithm已经是another-alg,解析.bin: $(binary)规则时,$(binary)会立即展开为another-alg,.bin的依赖变为实际存在的编译产物,后续运行时Make就能正确识别文件时间戳,避免重复执行。
如果无法调整赋值顺序,也可以在base.mk中使用eval延迟解析规则,确保变量在最终赋值后再生成规则:
# 修改后的base.mk source = file.ext algorithm = the-alg # 定义规则模板 define BIN_RULE .bin: $(binary) touch .bin $(binary): $(source) echo "compiling..." > $(binary) endef # 延迟展开规则,确保使用最新的algorithm值 binary = $(algorithm) $(eval $(BIN_RULE))
内容的提问来源于stack exchange,提问作者onlycparra
相关产品推荐
相关产品推荐

