如何让Makefile在.tpp模板实现文件变更时触发重编译?
问题
使用.tpp文件存储C++模板实现代码时,修改.tpp文件后无法触发Makefile重编译。原因是Make不会从.tpp源文件生成.o目标文件,但.tpp的变更会影响包含对应.hpp文件的.cpp文件的编译结果。如何配置Makefile,使其在.tpp文件变更时自动触发重编译?
最小复现示例
MRE.hpp
#pragma once #include <iostream> template <typename T> class MRE { T a; public: void write(std::ostream&); }; #include "MRE.tpp"
MRE.tpp
template <typename T> void MRE<T>::write(std::ostream& os) { os << "初始消息"; }
TestMRE.cpp
#include "MRE.hpp" int main() { MRE<int> m; m.write(std::cout); std::cout << std::endl; }
初始Makefile
TestMRE: TestMRE.o $(CXX) $(CXXFLAGS) $^ -o $@ %.o: %.cpp %.hpp $(CXX) $(CXXFLAGS) -c $< -o $@
观察到的行为
- 运行程序输出:
初始消息
- 将MRE.tpp中的
"初始消息"改为"最终消息"后,执行make输出:
make: “TestMRE”已是最新。
- 再次运行程序仍输出:
初始消息
解决方案
方法1:显式声明.hpp对.tpp的依赖
由于.hpp文件直接包含了.tpp,可以在Makefile中添加规则,让对应的.hpp依赖.tpp文件。这样当.tpp修改时,.hpp会被标记为过时,进而触发依赖.hpp的.cpp文件重新编译。
修改后的Makefile(单文件场景):
TestMRE: TestMRE.o $(CXX) $(CXXFLAGS) $^ -o $@ # 显式声明MRE.hpp依赖MRE.tpp MRE.hpp: MRE.tpp %.o: %.cpp %.hpp $(CXX) $(CXXFLAGS) -c $< -o $@
如果存在多组.hpp与.tpp配对的场景,可以用通配符批量处理(适用于所有.hpp都有同名.tpp的情况):
TestMRE: TestMRE.o $(CXX) $(CXXFLAGS) $^ -o $@ # 批量规则:所有.hpp依赖同名的.tpp %.hpp: %.tpp %.o: %.cpp %.hpp $(CXX) $(CXXFLAGS) -c $< -o $@
方法2:自动生成依赖文件(通用方案)
使用编译器的自动依赖生成功能(如GCC的-MM选项),让Makefile自动追踪所有被包含的文件(包括.tpp)。这种方法无需手动维护依赖,适合大型项目。
修改后的Makefile:
# 定义自动生成的依赖文件路径 DEPS := TestMRE.d TestMRE: TestMRE.o $(CXX) $(CXXFLAGS) $^ -o $@ # 编译时同时生成依赖文件 %.o: %.cpp $(CXX) $(CXXFLAGS) -c $< -o $@ -MMD -MP # 导入自动生成的依赖规则 -include $(DEPS)
规则说明:
-MMD:让编译器生成.d格式的依赖文件,记录目标文件对所有头文件(含.tpp)的依赖关系-MP:为每个依赖文件生成空规则,避免删除头文件时Make报错-include $(DEPS):让Make读取自动生成的依赖文件,确保任何被包含的文件修改时,都会触发对应.o文件的重编译
内容的提问来源于stack exchange,提问作者Saint-Martin
相关产品推荐
相关产品推荐

