如何让Makefile的my-rule仅在sub-dir变更时重建且等待其完成?
解决Makefile中my-rule重复重建的问题
你的问题根源在于sub-dir被标记为.PHONY目标——Make会把伪目标认定为总是需要重新构建,所以不管子目录实际有没有变更,依赖它的my-rule每次都会被触发执行。要实现"等待sub-dir完成且仅在其变更时重建my-rule",我们需要给子目录的构建状态一个可追踪的实体标记,具体修改如下:
修改后的Makefile
# 定义一个标记文件,用来记录子目录的构建完成时间 SUB_DIR_MARK := .sub-dir-built all: my-rule # 让my-rule依赖标记文件,而非直接依赖伪目标 my-rule: $(SUB_DIR_MARK) g++ main.cpp -o my-rule # 子目录构建完成后更新标记文件 $(SUB_DIR_MARK): $(MAKE) -C sub-dir touch $@ # 伪目标用于手动触发子目录清理/重建 .PHONY: sub-dir clean-sub-dir sub-dir: $(SUB_DIR_MARK) clean-sub-dir: $(MAKE) -C sub-dir clean rm -f $(SUB_DIR_MARK)
关键改动说明
- 引入标记文件
.sub-dir-built:这个文件的修改时间会记录子目录最后一次构建完成的时间,Make可以通过对比它和my-rule的时间戳来决定是否重建my-rule。 - 调整依赖关系:让
my-rule直接依赖标记文件,而非原来的伪目标sub-dir,这样只有当标记文件更新(即子目录确实发生了构建)时,my-rule才会重新编译。 - 保留伪目标的便利性:保留
.PHONY: sub-dir,但让它依赖标记文件,这样你依然可以通过make sub-dir手动触发子目录构建,同时不会影响自动依赖判断。 - 添加清理规则:新增
clean-sub-dir规则,用于清理子目录产物和标记文件,确保下次构建能重新触发完整流程。
验证效果
- 第一次执行
make:会先构建子目录,生成标记文件,再编译my-rule。 - 子目录无变更时再次执行
make:Make发现标记文件比my-rule新(或者两者时间一致),会跳过my-rule的编译。 - 修改子目录中的文件后执行
make:子目录会重新构建,标记文件被更新,my-rule随之重新编译。
内容的提问来源于stack exchange,提问作者Mahashi
相关产品推荐
相关产品推荐

