cpp-modules

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

C++20 Modules

C++20 Modules

Purpose

用途

Guide agents through authoring, building, and debugging C++20 modules: named modules vs header units, module partitions, CMake integration, compiler-specific flags, and interoperability with legacy headers.
指导Agent完成C++20模块的编写、构建与调试:包括命名模块与头单元的区别、模块分区、CMake集成、编译器专属标志,以及与传统头文件的互操作性。

Triggers

触发场景

  • "How do I write a C++20 module?"
  • "How do I import a module in CMake?"
  • "What's the difference between a named module and a header unit?"
  • "My module gives 'cannot find module' errors"
  • "How do I use C++20 modules with Clang?"
  • "How do I migrate from headers to modules?"
  • "如何编写C++20模块?"
  • "如何在CMake中导入模块?"
  • "命名模块和头单元有什么区别?"
  • "我的模块报'无法找到模块'错误"
  • "如何在Clang中使用C++20模块?"
  • "如何从头文件迁移到模块?"

Workflow

工作流程

1. Module concepts overview

1. 模块概念概述

C++20 module kinds:
├── Named module interface unit  (.cppm / .ixx)  — exports declarations
├── Module implementation unit   (.cpp)           — defines module members
├── Module partition             (.cppm)          — internal module subdivision
└── Header unit                  (any header)     — import a legacy header as module
Named modules are the primary target. Header units are a bridge for legacy code. Avoid Global Module Fragment unless required for macro access.
C++20 module kinds:
├── Named module interface unit  (.cppm / .ixx)  — exports declarations
├── Module implementation unit   (.cpp)           — defines module members
├── Module partition             (.cppm)          — internal module subdivision
└── Header unit                  (any header)     — import a legacy header as module
命名模块是主要使用目标。头单元是传统代码的过渡方案。除非需要访问宏,否则避免使用全局模块片段。

2. Named module — minimal example

2. 命名模块——最简示例

cpp
// math.cppm — module interface unit
export module math;          // declares the module name

export int add(int a, int b) { return a + b; }
export double pi = 3.14159;

// Non-exported (module-private)
int internal_helper() { return 42; }
cpp
// main.cpp — consumer
import math;                 // import the module
#include <iostream>          // legacy header (still works)

int main() {
    std::cout << add(2, 3) << "\n";  // 5
    std::cout << pi << "\n";
}
cpp
// math.cppm — module interface unit
export module math;          // declares the module name

export int add(int a, int b) { return a + b; }
export double pi = 3.14159;

// Non-exported (module-private)
int internal_helper() { return 42; }
cpp
// main.cpp — consumer
import math;                 // import the module
#include <iostream>          // legacy header (still works)

int main() {
    std::cout << add(2, 3) << "\n";  // 5
    std::cout << pi << "\n";
}

3. Module partitions

3. 模块分区

cpp
// math-core.cppm — partition
export module math:core;     // partition 'core' of module 'math'

export int add(int a, int b) { return a + b; }
cpp
// math.cppm — primary module interface
export module math;
export import :core;         // re-export the partition
cpp
// math-impl.cpp — implementation unit (no export)
module math;                 // belongs to 'math' module, not a partition
// has access to all math declarations, but exports nothing
cpp
// math-core.cppm — partition
export module math:core;     // partition 'core' of module 'math'

export int add(int a, int b) { return a + b; }
cpp
// math.cppm — primary module interface
export module math;
export import :core;         // re-export the partition
cpp
// math-impl.cpp — implementation unit (no export)
module math;                 // belongs to 'math' module, not a partition
// has access to all math declarations, but exports nothing

4. Header units — bridging legacy headers

4. 头单元——衔接传统头文件

cpp
// Import a standard library header as a module unit
import <iostream>;           // header unit (compiler generates BMI)
import <vector>;

// Or import a project header (must be compilable as header unit)
import "myheader.h";
Header units do NOT provide macros to importers. For macro access, use the Global Module Fragment:
cpp
module;                      // Global Module Fragment starts here
#include <cassert>           // macros like assert() are available
export module mymod;
// ... rest of module
cpp
// Import a standard library header as a module unit
import <iostream>;           // header unit (compiler generates BMI)
import <vector>;

// Or import a project header (must be compilable as header unit)
import "myheader.h";
头单元不会向导入者提供宏。若需要访问宏,请使用全局模块片段:
cpp
module;                      // Global Module Fragment starts here
#include <cassert>           // macros like assert() are available
export module mymod;
// ... rest of module

5. Building with Clang

5. 使用Clang构建

bash
undefined
bash
undefined

Compile module interface → produces .pcm (precompiled module)

Compile module interface → produces .pcm (precompiled module)

clang++ -std=c++20 --precompile math.cppm -o math.pcm
clang++ -std=c++20 --precompile math.cppm -o math.pcm

Compile implementation using the .pcm

Compile implementation using the .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 -c math.cpp -o math.o

Compile consumer

Compile consumer

clang++ -std=c++20 -fmodule-file=math=math.pcm main.cpp math.o -o prog
undefined
clang++ -std=c++20 -fmodule-file=math=math.pcm main.cpp math.o -o prog
undefined

6. Building with GCC

6. 使用GCC构建

bash
undefined
bash
undefined

GCC ≥11 supports modules (experimental ≥11, better ≥14)

GCC ≥11 supports modules (experimental ≥11, better ≥14)

Compile interface unit → produces .gcm in gcm.cache/

Compile interface unit → produces .gcm in gcm.cache/

g++ -std=c++20 -fmodules-ts math.cppm -c -o math.o
g++ -std=c++20 -fmodules-ts math.cppm -c -o math.o

Compiler auto-discovers .gcm files in gcm.cache/

Compiler auto-discovers .gcm files in gcm.cache/

g++ -std=c++20 -fmodules-ts main.cpp math.o -o prog
undefined
g++ -std=c++20 -fmodules-ts main.cpp math.o -o prog
undefined

7. CMake integration (CMake ≥3.28)

7. CMake集成(CMake ≥3.28)

cmake
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    # module interface units
            src/math.cppm
            src/math-core.cppm
    PRIVATE
        src/math-impl.cpp             # implementation unit
)

add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE math)
bash
undefined
cmake
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    # module interface units
            src/math.cppm
            src/math-core.cppm
    PRIVATE
        src/math-impl.cpp             # implementation unit
)

add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE math)
bash
undefined

Requires a generator that supports modules (Ninja ≥1.11 or MSBuild)

Requires a generator that supports modules (Ninja ≥1.11 or MSBuild)

cmake -S . -B build -G Ninja cmake --build build

For CMake 3.25–3.27 (experimental):

```cmake
cmake_minimum_required(VERSION 3.25)
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "3c375311-a3c9-4396-a187-3227ef642046")
set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP ON)
cmake -S . -B build -G Ninja cmake --build build

对于CMake 3.25–3.27(实验性支持):

```cmake
cmake_minimum_required(VERSION 3.25)
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "3c375311-a3c9-4396-a187-3227ef642046")
set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP ON)

8. Common errors

8. 常见错误

ErrorCauseFix
module 'math' not found
BMI not found in search pathCompile interface unit first; check
-fmodule-file=
flags
cannot import header in module
#include
inside module purview
Move
#include
to Global Module Fragment or use
import <>
redefinition of module 'math'
Two
.cppm
files declare same module
Only one primary interface per module
macro not available after import
Macros don't cross module boundariesMove macro-dependent code to GMF or use
#include
ODR violation
Same name in multiple partitionsEach name exported from exactly one partition
BMI cache stale
.pcm
/
.gcm
not rebuilt after change
Clean build or ensure dependency tracking is working
错误信息原因修复方案
module 'math' not found
搜索路径中未找到BMI先编译接口单元;检查
-fmodule-file=
标志
cannot import header in module
在模块范围内使用
#include
#include
移至全局模块片段,或使用
import <>
redefinition of module 'math'
两个
.cppm
文件声明了同一模块
每个模块只能有一个主接口
macro not available after import
宏无法跨模块边界传递将依赖宏的代码移至全局模块片段,或使用
#include
ODR violation
多个分区中存在同名内容每个导出名称仅来自一个分区
BMI cache stale修改后未重新构建
.pcm
/
.gcm
清理构建产物,或确保依赖跟踪正常工作

9. Interop with legacy headers

9. 与传统头文件的互操作性

cpp
// Wrapping a C library for module use
export module cjson;

module;                       // Global Module Fragment
#include <cjson/cJSON.h>      // C header with macros

export module cjson;          // back to module purview

// Re-export key types (optional)
export using ::cJSON;
export using ::cJSON_Parse;
For CMake module support details, see references/modules-cmake-support.md.
cpp
// Wrapping a C library for module use
export module cjson;

module;                       // Global Module Fragment
#include <cjson/cJSON.h>      // C header with macros

export module cjson;          // back to module purview

// Re-export key types (optional)
export using ::cJSON;
export using ::cJSON_Parse;
关于CMake模块支持的详细信息,请参阅references/modules-cmake-support.md

Related skills

相关技能

  • Use
    skills/build-systems/build-acceleration
    for PCH as a modules alternative
  • Use
    skills/compilers/gcc
    or
    skills/compilers/clang
    for compiler-specific module flags
  • Use
    skills/build-systems/cmake
    for CMake project configuration
  • 若需将PCH作为模块替代方案,请使用
    skills/build-systems/build-acceleration
  • 若需编译器专属模块标志,请使用
    skills/compilers/gcc
    skills/compilers/clang
  • 若需CMake项目配置,请使用
    skills/build-systems/cmake