CMake使用target_precompile_headers增删.cpp触发全量重编译如何解决
问题根因
你遇到的是CMake早期版本target_precompile_headers功能的原生缺陷:3.20及更低版本的CMake中,预编译头(PCH)的依赖校验逻辑会把目标的源文件列表哈希值作为判定PCH是否需要重新生成的依据。只要你增删目标的.cpp源文件,哪怕PCH本身的内容、编译参数、头文件路径完全没有变化,CMake也会判定PCH过期,触发PCH重新编译。而所有翻译单元都依赖PCH文件,最终就会导致全量重编译,这和你target_precompile_headers的使用方式没有关系。
可行解决方案
- 方案1:升级CMake到3.21及以上版本
这个是成本最低的修复方案,CMake 3.21版本官方已经优化了PCH的依赖判定逻辑,只有PCH关联的编译选项、头文件内容、包含路径等确实会影响PCH生成的配置变更时,才会触发PCH重编,单纯增删源文件不会触发PCH重新生成,也就不会导致全量编译,不需要修改任何项目配置。 - 方案2:拆分独立PCH目标(适配无法升级CMake的场景)
如果受环境限制不能升级CMake,可以把预编译头封装为独立的静态库目标,业务目标依赖该静态库复用PCH,配置示例如下:
cmake_minimum_required(VERSION 3.16) set(CMAKE_CXX_STANDARD 17) project(SuperBasicProject) set(TARGET_NAME ${PROJECT_NAME}) # 定义独立PCH目标,只需要一个空的cpp文件即可编译 add_library(custom_pch STATIC pch_dummy.cpp) target_include_directories(custom_pch PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_precompile_headers(custom_pch PUBLIC my_pch.h) # 业务目标链接PCH目标即可复用预编译头 add_executable(${TARGET_NAME} main.cpp empty_cpp1.cpp empty_cpp2.cpp) target_link_libraries(${TARGET_NAME} PRIVATE custom_pch)
这种配置下,业务目标增删源文件只会触发业务目标本身的增量构建,不会影响独立的PCH目标,不会触发全量重编译。
- 方案3:关闭PCH模板实例化配置
如果不想拆分目标,可以在项目顶层CMake开头添加如下配置:
set(CMAKE_PCH_INSTANTIATE_TEMPLATES OFF CACHE BOOL "" FORCE)
关闭PCH的自动模板实例化功能后,部分版本的CMake就不会把源文件列表纳入PCH的依赖校验逻辑,也能规避该问题,缺点是PCH不会再自动实例化常用模板,可能会略微增加部分编译单元的编译耗时。
内容的提问来源于stack exchange,提问作者baard047
相关产品推荐
相关产品推荐

