No description
Find a file
2026-05-29 14:27:19 +02:00
.gitignore initial commit: enable_import_std.cmake helper 2026-05-29 14:27:19 +02:00
enable_import_std.cmake add MIT license, copyright header, temporal qualifiers in why-comments 2026-05-29 14:27:19 +02:00
LICENSE add MIT license, copyright header, temporal qualifiers in why-comments 2026-05-29 14:27:19 +02:00
README.md add MIT license, copyright header, temporal qualifiers in why-comments 2026-05-29 14:27:19 +02:00

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_STD is 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 with target_compile_options so they propagate to the std module build.
  • Ninja Multi-Config is supported.