其他
在编写、构建或迁移 C++20 modules 时…
适用于使用 C++20 模块的现代 C++ 项目,需要处理命名模块、module partitions、header units、CMake MODULE_SOURCES、Clang/GCC 编译与 BMI 缓存问题。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 48/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 85/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 57/100 ×0.15
适用场景
在编写、构建或迁移 C++20 modu通用
解决思路
- 先区分 C++20 module 类型:命名模块接口单元(.cppm/.ixx)导出声明;模块实现单元(.cpp)定义模块成员;模块分区(.cppm)做内部分割;头文件单元(任意头文件)把旧头文件当模块导入。以命名模块为主,头文件单元作为旧代码桥接,除非需要宏访问,否则避免 Global Module Fragment。
- 编写最小命名模块:在 math.cppm 中写 export module math; 导出 export int add(int a, int b) 和 export double pi;不导出的函数作为模块私有;消费者用 import math;,仍可 #include <iostream>。
- 使用模块分区:在 math-core.cppm 写 export module math:core; 并导出声明;在主接口 math.cppm 写 export module math; export import :core; 重新导出分区;实现单元 math-impl.cpp 写 module math; 属于模块但不导出,可访问所有 math 声明。
- 用头文件单元桥接旧头文件:import <iostream>;、import <vector>; 或 import "myheader.h";;注意头文件单元不向导入者提供宏,需要宏时用 Global Module Fragment:module; #include <cassert> export module mymod;。
- 用 Clang 构建:clang++ -std=c++20 --precompile math.cppm -o math.pcm;clang++ -std=c++20 -fmodule-file=math=math.pcm -c math.cpp -o math.o;clang++ -std=c++20 -fmodule-file=math=math.pcm main.cpp math.o -o prog。
- 用 GCC 构建:g++ -std=c++20 -fmodules-ts math.cppm -c -o math.o 生成 .gcm 到 gcm.cache/;g++ -std=c++20 -fmodules-ts main.cpp math.o -o prog,编译器自动发现 gcm.cache/ 中的 .gcm。
- 用 CMake ≥3.28 集成:cmake_minimum_required(VERSION 3.28)、project(myproject LANGUAGES CXX)、set(CMAKE_CXX_STANDARD 20);add_library(math) 后用 target_sources(math PUBLIC FILE_SET CXX_MODULES FILES src/math.cppm src/math-core.cppm PRIVATE src/math-impl.cpp) 指定模块接口与实现单元;add_executable(myapp main.cpp) 和 target_link_libraries(myapp PRIVATE math)。
- CMake 构建需使用支持 modules 的生成器:cmake -S . -B build -G Ninja(Ninja ≥1.11)或 MSBuild;然后 cmake --build build。
- 对 CMake 3.25–3.27 实验支持:cmake_minimum_required(VERSION 3.25),设置 CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API 为 "3c375311-a3c9-4396-a187-3227ef642046",并设置 CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP ON。
- 遇到 module 'math' not found:先编译接口单元,检查 -fmodule-file= 等 BMI 搜索路径。
- 遇到 cannot import header in module:不要在模块范围内(module purview)中 #include;把 #include 移到 Global Module Fragment,或改用 import <>。
- 遇到 redefinition of module 'math':每个模块只保留一个 primary interface,不要两个 .cppm 声明同一模块。
- 遇到 macro not available after import:宏不跨模块边界;把依赖宏的代码移到 GMF,或使用 #include。
- 遇到 ODR violation:每个名字只从一个分区导出,避免多个分区导出同名实体。
- 遇到 BMI cache stale:.pcm/.gcm 在改动后未重建时,做 clean build 或确保依赖跟踪有效。
- 与旧 C 头文件互操作:在 export module cjson; 后用 module; #include <cjson/cJSON.h> export module cjson; 把 C 头放进 GMF,再用 export using ::cJSON;、export using ::cJSON_Parse; 重新导出关键类型/函数。
- 若需要 CMake 模块支持细节,查阅 references/modules-cmake-support.md。
适用边界 · 注意事项
- 项目或工具链不支持 C++20 modules(如编译器过旧、CMake 生成器不支持 modules)时,不要强行迁移。
- 只需要预编译头(PCH)做构建加速、且迁移成本过高时,优先使用 PCH 而不是 modules。
- 需要把宏跨模块边界提供时,不能只靠 import,必须改用 Global Module Fragment 或 #include。