使用递归Make时如何阻止自动执行的最终rm命令?
解决GNU Make递归构建时自动删除中间头文件的问题
核心原因
GNU Make的自动中间文件清理机制在起作用:当一个文件是规则的输出,但既不是顶层目标,也没有被其他显式规则列为依赖时,Make会将其标记为中间文件,构建完成后自动删除。递归调用中子模块生成的头文件刚好符合这个条件,所以被自动清理了。
具体解决方案
1. 在子模块Makefile中标记文件为“珍贵文件”
在子模块的Makefile里,给生成的头文件添加.PRECIOUS特殊目标,直接告诉Make不要删除它:
.PRECIOUS: panic/panic.h # 替换成你的子模块头文件实际路径
如果有多个子模块头文件,可以用变量统一管理:
MODULE_HEADERS := panic/panic.h utils/log.h .PRECIOUS: $(MODULE_HEADERS)
2. 顶层Makefile显式声明子模块头文件为依赖
在顶层Makefile的headers目标里,把每个子模块的原始头文件显式列为依赖,让Make明确知道这些文件是需要保留的:
# 最终输出的头文件列表 TARGET_HEADERS := include/panic.h include/log.h # 子模块内的原始头文件 SOURCE_HEADERS := panic/panic.h utils/log.h headers: $(TARGET_HEADERS) # 定义从子模块到include目录的复制规则 $(TARGET_HEADERS): include/%.h: %/%.h @$(MAKE) -C $(dir $<) headers cp $< $@
这样子模块的原始头文件被顶层规则列为依赖,Make不会把它们当成可删除的中间文件。
3. 全局禁用中间文件自动清理(仅调试用)
如果只是临时调试需要,可以在顶层Makefile添加SECONDARY特殊目标,让所有文件都不被视为中间文件,但可能导致大量临时文件残留,不建议长期使用:
.SECONDARY:
4. 调整子模块的目标定义
在子模块Makefile里,把生成头文件的目标和头文件本身绑定,明确标记头文件是目标产物:
.PHONY: headers headers: panic.h # 直接将头文件作为headers目标的依赖
递归调用make -C panic headers时,Make会明确识别panic.h是需要保留的输出文件。
验证方法
修改子模块的头文件内容后,执行make headers,检查子模块内的原始头文件是否还存在,再查看include目录下的对应文件是否同步更新。如果子模块文件未被删除,且include文件正常更新,说明问题解决。
内容的提问来源于stack exchange,提问作者Martijn van Wely
相关产品推荐
相关产品推荐

