$npx -y skills add mohitmishra786/low-level-dev-skills --skill cpp-modulesC++20 modules skill for modern C++ projects. Use when working with named modules, module partitions, header units, CMake MODULE_SOURCES, Clang -fmodules-ts, BMI caching issues, or migrating from headers to modules. Activates on queries about C++20 modules, import statements, modu
| 1 | # C++20 Modules |
| 2 | |
| 3 | ## Purpose |
| 4 | |
| 5 | 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. |
| 6 | |
| 7 | ## Triggers |
| 8 | |
| 9 | - "How do I write a C++20 module?" |
| 10 | - "How do I import a module in CMake?" |
| 11 | - "What's the difference between a named module and a header unit?" |
| 12 | - "My module gives 'cannot find module' errors" |
| 13 | - "How do I use C++20 modules with Clang?" |
| 14 | - "How do I migrate from headers to modules?" |
| 15 | |
| 16 | ## Workflow |
| 17 | |
| 18 | ### 1. Module concepts overview |
| 19 | |
| 20 | ``` |
| 21 | C++20 module kinds: |
| 22 | ├── Named module interface unit (.cppm / .ixx) — exports declarations |
| 23 | ├── Module implementation unit (.cpp) — defines module members |
| 24 | ├── Module partition (.cppm) — internal module subdivision |
| 25 | └── Header unit (any header) — import a legacy header as module |
| 26 | ``` |
| 27 | |
| 28 | Named modules are the primary target. Header units are a bridge for legacy code. Avoid Global Module Fragment unless required for macro access. |
| 29 | |
| 30 | ### 2. Named module — minimal example |
| 31 | |
| 32 | ```cpp |
| 33 | // math.cppm — module interface unit |
| 34 | export module math; // declares the module name |
| 35 | |
| 36 | export int add(int a, int b) { return a + b; } |
| 37 | export double pi = 3.14159; |
| 38 | |
| 39 | // Non-exported (module-private) |
| 40 | int internal_helper() { return 42; } |
| 41 | ``` |
| 42 | |
| 43 | ```cpp |
| 44 | // main.cpp — consumer |
| 45 | import math; // import the module |
| 46 | #include <iostream> // legacy header (still works) |
| 47 | |
| 48 | int main() { |
| 49 | std::cout << add(2, 3) << "\n"; // 5 |
| 50 | std::cout << pi << "\n"; |
| 51 | } |
| 52 | ``` |
| 53 | |
| 54 | ### 3. Module partitions |
| 55 | |
| 56 | ```cpp |
| 57 | // math-core.cppm — partition |
| 58 | export module math:core; // partition 'core' of module 'math' |
| 59 | |
| 60 | export int add(int a, int b) { return a + b; } |
| 61 | ``` |
| 62 | |
| 63 | ```cpp |
| 64 | // math.cppm — primary module interface |
| 65 | export module math; |
| 66 | export import :core; // re-export the partition |
| 67 | ``` |
| 68 | |
| 69 | ```cpp |
| 70 | // math-impl.cpp — implementation unit (no export) |
| 71 | module math; // belongs to 'math' module, not a partition |
| 72 | // has access to all math declarations, but exports nothing |
| 73 | ``` |
| 74 | |
| 75 | ### 4. Header units — bridging legacy headers |
| 76 | |
| 77 | ```cpp |
| 78 | // Import a standard library header as a module unit |
| 79 | import <iostream>; // header unit (compiler generates BMI) |
| 80 | import <vector>; |
| 81 | |
| 82 | // Or import a project header (must be compilable as header unit) |
| 83 | import "myheader.h"; |
| 84 | ``` |
| 85 | |
| 86 | Header units do NOT provide macros to importers. For macro access, use the Global Module Fragment: |
| 87 | |
| 88 | ```cpp |
| 89 | module; // Global Module Fragment starts here |
| 90 | #include <cassert> // macros like assert() are available |
| 91 | export module mymod; |
| 92 | // ... rest of module |
| 93 | ``` |
| 94 | |
| 95 | ### 5. Building with Clang |
| 96 | |
| 97 | ```bash |
| 98 | # Compile module interface → produces .pcm (precompiled module) |
| 99 | clang++ -std=c++20 --precompile math.cppm -o math.pcm |
| 100 | |
| 101 | # Compile implementation using the .pcm |
| 102 | clang++ -std=c++20 -fmodule-file=math=math.pcm -c math.cpp -o math.o |
| 103 | |
| 104 | # Compile consumer |
| 105 | clang++ -std=c++20 -fmodule-file=math=math.pcm main.cpp math.o -o prog |
| 106 | ``` |
| 107 | |
| 108 | ### 6. Building with GCC |
| 109 | |
| 110 | ```bash |
| 111 | # GCC ≥11 supports modules (experimental ≥11, better ≥14) |
| 112 | # Compile interface unit → produces .gcm in gcm.cache/ |
| 113 | g++ -std=c++20 -fmodules-ts math.cppm -c -o math.o |
| 114 | |
| 115 | # Compiler auto-discovers .gcm files in gcm.cache/ |
| 116 | g++ -std=c++20 -fmodules-ts main.cpp math.o -o prog |
| 117 | ``` |
| 118 | |
| 119 | ### 7. CMake integration (CMake ≥3.28) |
| 120 | |
| 121 | ```cmake |
| 122 | cmake_minimum_required(VERSION 3.28) |
| 123 | project(myproject LANGUAGES CXX) |
| 124 | set(CMAKE_CXX_STANDARD 20) |
| 125 | |
| 126 | add_library(math) |
| 127 | target_sources(math |
| 128 | PUBLIC |
| 129 | FILE_SET CXX_MODULES FILES # module interface units |
| 130 | src/math.cppm |
| 131 | src/math-core.cppm |
| 132 | PRIVATE |
| 133 | src/math-impl.cpp # implementation unit |
| 134 | ) |
| 135 | |
| 136 | add_executable(myapp main.cpp) |
| 137 | target_link_libraries(myapp PRIVATE math) |
| 138 | ``` |
| 139 | |
| 140 | ```bash |
| 141 | # Requires a generator that supports modules (Ninja ≥1.11 or MSBuild) |
| 142 | cmake -S . -B build -G Ninja |
| 143 | cmake --build build |
| 144 | ``` |
| 145 | |
| 146 | For CMake 3.25–3.27 (experimental): |
| 147 | |
| 148 | ```cmake |
| 149 | cmake_minimum_required(VERSION 3.25) |
| 150 | set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API "3c375311-a3c9-4396-a187-3227ef642046") |
| 151 | set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP ON) |
| 152 | ``` |
| 153 | |
| 154 | ### 8. Common errors |
| 155 | |
| 156 | | Error | Cause | Fix | |
| 157 | |-------|-------|-----| |
| 158 | | `module 'math' not found` | BMI not found in search path | Compile interface unit first; check `-fmodule-file=` flags | |
| 159 | | `cannot import header in module` | `#include` inside module pu |