如何在CMake构建的C++项目中避免预编译头的强制包含?
问题
我正在尝试理解如何在CMake中生成并引入预编译头。目前我使用CMake的target_precompile_headers指令在C++项目中生成并引入预编译头,该方法能正常工作,但根据CMake文档,该指令会导致预编译头被强制包含:
头文件列表会被用于生成名为cmake_pch.h|xx的头文件,以此生成预编译头文件(.pch、.gch、.pchi)。cmake_pch.h|xx会被强制引入所有源文件(GCC用-include,MSVC用/FI),因此源文件无需添加#include "pch.h"。
我希望在项目中避免这种行为,要求只有实际使用预编译头的源文件必须显式添加#include "pch.h"。请问是否有实现方法?
以下是项目结构及代码:
项目文件
main.cpp
//#include "pch.h" //即使不显式引入头文件,代码仍能正常运行 int main() { std::vector<double> my_vector; std::cout << "Size of vector is "<< my_vector.size() << std::endl; return 0; }
pch.cpp
#include "pch.h"
pch.h
// pch.h #ifndef PCH_H #define PCH_H #include <vector> #include <iostream> #endif // PCH_H
CMakeLists.txt
cmake_minimum_required(VERSION 3.16) project(MyProject) set(CMAKE_CXX_STANDARD 17) add_executable(MyExecutable main.cpp pch.cpp) target_precompile_headers(MyExecutable PRIVATE pch.h) target_sources(MyExecutable PRIVATE pch.cpp)
当前配置下,即使main.cpp未显式引入pch.h,代码仍能正常运行(已测试Clang和GCC编译器)。请问如何避免这种强制包含行为?未显式引入pch.h应被视为错误。
解决方案
要实现仅显式包含pch.h的源文件才能使用预编译头,需放弃target_precompile_headers的自动强制包含逻辑,改为手动配置预编译头的生成与关联:
核心思路
- 手动编译生成预编译头文件,不依赖CMake自动生成的
cmake_pch.h; - 仅为需要使用预编译头的源文件添加编译选项,让编译器在遇到显式的
#include "pch.h"时使用预编译版本,而非强制注入。
修改后的CMake配置
cmake_minimum_required(VERSION 3.16) project(MyProject) set(CMAKE_CXX_STANDARD 17) set(PCH_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/pch.h") set(PCH_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/pch.cpp") # 为GCC/Clang生成预编译头.gch文件 if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/pch.h.gch" COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS} -std=c++17 -x c++-header ${PCH_HEADER} -o "${CMAKE_CURRENT_BINARY_DIR}/pch.h.gch" DEPENDS ${PCH_HEADER} COMMENT "Building precompiled header..." ) # 将预编译头文件加入目标依赖 add_executable(MyExecutable main.cpp pch.cpp "${CMAKE_CURRENT_BINARY_DIR}/pch.h.gch") # 仅为显式包含pch.h的源文件添加关联选项(示例中为main.cpp) target_compile_options(MyExecutable PRIVATE $<$<EQUAL:$<TARGET_PROPERTY:MyExecutable,SOURCES>,main.cpp>:-include "${PCH_HEADER}"> ) endif() # 为MSVC生成预编译头.pch文件 if(MSVC) add_executable(MyExecutable main.cpp pch.cpp) # 标记pch.cpp为预编译头生成源 set_source_files_properties(${PCH_SOURCE} PROPERTIES COMPILE_FLAGS "/Yc\"pch.h\"") # 仅为需要使用预编译头的源文件添加关联选项(示例中为main.cpp) set_source_files_properties(main.cpp PROPERTIES COMPILE_FLAGS "/Yu\"pch.h\"") endif()
验证效果
修改后:
- 若
main.cpp未添加#include "pch.h",编译时会因找不到std::vector、std::cout等符号报错; - 只有显式添加
#include "pch.h"的源文件,才会启用预编译头加速编译。
说明
这种配置完全绕过了CMaketarget_precompile_headers的强制注入逻辑,由开发者精准控制哪些源文件使用预编译头,完全匹配需求。需注意不同编译器的预编译头处理逻辑差异,上述配置已兼容GCC/Clang和MSVC。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

