- CMake 100%
| .gitignore | ||
| enable_import_std.cmake | ||
| LICENSE | ||
| README.md | ||
cmake-import-std
A single CMake helper module that enables C++ standard library modules
(import std;) and named modules in CMake projects.
Why
At the time of this commit, CMake's import std; support is still gated
behind a version-specific experimental UUID, and several settings have to be
in place before, during and after the project() call. Doing this by hand is
error-prone -- the UUID rotates with each CMake release and the order of
statements matters. This module wraps the dance behind two macros. Once the
feature ships as non-experimental in a future CMake release, the UUID step
will drop away and this module's role will shrink accordingly.
Requirements
The table below reflects the toolchain matrix at the time of this commit;
expect floors to drift upward as import std; support stabilises.
| Component | Minimum |
|---|---|
| CMake | 3.30 (3.31.8+ recommended) |
| Generator | Ninja >= 1.11, or Visual Studio 2022 >= 17.4 |
| Clang | 18 (19+ recommended; 22+ for C++26) |
| GCC | 14 (15+ recommended) |
| MSVC | 19.40 (Visual Studio 17.10) |
The Unix Makefiles generator does not support C++ modules.
On these compiler versions, CMake's dyndep scanner injects the required
module flags (-fmodules and friends, MSVC /experimental:module, etc.)
automatically once CMAKE_CXX_SCAN_FOR_MODULES and CMAKE_CXX_MODULE_STD
are set. No manual flag plumbing is needed here.
Usage
Drop enable_import_std.cmake into a cmake/ directory in your project
(or pull it in as a submodule / FetchContent), then:
cmake_minimum_required(VERSION 3.30 FATAL_ERROR)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
include(enable_import_std)
# MUST come before project() -- sets the experimental UUID consumed during
# project initialization.
enable_experimental_std()
project(my_project LANGUAGES CXX)
# MUST come after project() and before any target that uses modules.
# Sets CMAKE_CXX_STANDARD, CMAKE_CXX_MODULE_STD, CMAKE_CXX_SCAN_FOR_MODULES, ...
enable_cxx_modules(STANDARD 23)
add_executable(app main.cpp)
Then in main.cpp:
import std;
int main() {
std::println("hello from import std;");
}
Build with Ninja:
cmake -S . -B build -G Ninja
cmake --build build
What the macros do
enable_experimental_std() -- before project()
Sets CMAKE_EXPERIMENTAL_CXX_IMPORT_STD to the UUID expected by the running
CMake version. CMake refuses to enable the feature without the right UUID and
the UUID changes between releases, so the macro maps CMake versions to UUIDs.
enable_cxx_modules([STANDARD <23|26>]) -- after project()
Configures the rest of the module pipeline:
| Variable | Value | Why |
|---|---|---|
CMAKE_CXX_STANDARD |
23 |
import std; requires C++23 or newer |
CMAKE_CXX_STANDARD_REQUIRED |
ON |
Fail rather than silently fall back |
CMAKE_CXX_EXTENSIONS |
OFF |
Conforming front-end -- avoids BMI/consumer mismatch |
CMAKE_CXX_MODULE_STD |
ON |
Opt into the std module |
CMAKE_CXX_SCAN_FOR_MODULES |
ON |
Enable the P1689 dyndep scanner |
It also warns if the generator is not module-capable.
Order of statements
The two macros split because CMAKE_EXPERIMENTAL_CXX_IMPORT_STD is consumed
during project() and the rest of the settings have to be applied after the
CXX language has been enabled. The required order is:
cmake_minimum_required(...)
include(enable_import_std)
enable_experimental_std() # <-- before project()
project(...)
enable_cxx_modules(...) # <-- after project(), before any target
add_library/add_executable(...)
Notes
CMAKE_CXX_MODULE_STDis treated as a target property; setting it globally (as this module does) applies it to every target created afterwards.- The std module BMI is built with the same flags as your targets. Inconsistent
flags between the BMI and a consumer (RTTI, exceptions, sanitizers) cause
link failures. Set such flags before
enable_cxx_modules()-- or per-target withtarget_compile_optionsso they propagate to the std module build. Ninja Multi-Configis supported.