You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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 $@

观察到的行为

  1. 运行程序输出:

初始消息

  1. 将MRE.tpp中的"初始消息"改为"最终消息"后,执行make输出:

make: “TestMRE”已是最新。

  1. 再次运行程序仍输出:

初始消息

解决方案

方法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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 13:28:10