CMake中直接使用OBJECT库输出构建Clang C++20模块的问题
Clang + CMake 配置C++20模块的可行方案
优先使用CMake原生模块支持(最可靠,无路径维护成本)
CMake 3.26及以上版本已经原生支持Clang工具链下的C++20模块全流程构建,不需要手动处理pcm生成、编译顺序、编译参数传递问题,是首选方案:
- 基础配置开启模块扫描:
cmake_minimum_required(VERSION 3.26) project(demo CXX) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_SCAN_FOR_MODULES ON)
- 用
FILE_SET标记模块接口文件,CMake会自动识别并优先编译模块接口,自动给所有依赖该目标的源码传递正确的-fmodule-file参数:
add_library(my_module) # 标记模块接口源文件 target_sources(my_module PUBLIC FILE_SET CXX_MODULES FILES module-def.cpp ) # 添加实现文件、使用模块的业务源码 target_sources(my_module PRIVATE module-impl.cpp main.cpp )
该方案下不需要手动获取pcm路径,CMake会自动处理所有路径拼接、编译标志同步、依赖顺序问题,不会出现参数不一致或者编译顺序错误的问题。
低版本CMake手动配置方案
如果必须使用3.26以下的CMake版本,不要依赖生成器表达式获取OBJECT库的输出路径,从根源上规避路径获取问题:
- 单独配置模块接口编译目标,手动固定pcm输出路径,不要让CMake自动生成输出路径:
# 提前定义pcm的固定输出路径,放在当前编译目录下 set(MOD_PCM ${CMAKE_CURRENT_BINARY_DIR}/module-def.pcm) add_library(mod_interface OBJECT module-def.cpp) # 配置模块接口编译参数,明确指定输出为pcm文件 target_compile_options(mod_interface PRIVATE -std=c++20 -fmodules --precompile -o ${MOD_PCM} ) # 禁止该目标参与自动链接,避免触发链接逻辑破坏pcm文件 set_target_properties(mod_interface PROPERTIES EXCLUDE_FROM_ALL ON LINKER_LANGUAGE NONE )
- 配置实现文件、业务目标的编译参数,直接引用提前定义的固定pcm路径,同时添加显式依赖保证编译顺序:
add_library(my_module module-impl.cpp) # 传入模块编译参数,直接引用固定pcm路径 target_compile_options(my_module PRIVATE -std=c++20 -fmodules -fmodule-file=${MOD_PCM} ) # 强制模块接口优先编译 add_dependencies(my_module mod_interface)
踩坑说明:不要尝试通过
$<TARGET_OBJECTS>之类的生成器表达式获取OBJECT库的输出作为pcm路径——默认情况下OBJECT库会把源码编译为.o目标文件,而非.pcm预编译模块文件,这也是之前用OBJECT库出现链接异常、路径无法获取的核心原因。手动指定pcm输出路径后,就完全不需要依赖生成器表达式解析路径,同时可以把公共编译选项抽成全局变量复用到所有目标,保证编译标志完全一致,不需要用add_custom_command重复维护编译参数。
内容的提问来源于stack exchange,提问作者Martijn Otto
相关产品推荐
相关产品推荐

