Skip to content

Instantly share code, notes, and snippets.

@YanzhaoW
Last active September 3, 2025 01:06
Show Gist options
  • Select an option

  • Save YanzhaoW/ee89c5a61f8dc7d0c7deebcf47e2f589 to your computer and use it in GitHub Desktop.

Select an option

Save YanzhaoW/ee89c5a61f8dc7d0c7deebcf47e2f589 to your computer and use it in GitHub Desktop.
C++ 20/23 modules and import std

Modern C++ with modules

Synopsis

main.cpp:

import std;

auto main() -> int
{
   const auto values = std::vector{1, 2, 3};
   std::println("values: {}", values);
   return 0;
}

output:

values: [1, 2, 3]

The example can be check here: godbolt

Requirements

Versions

  • clang: >= 20.1
  • cmake: >= 3.28
  • ninja: >= 1.11

Build options

  • CMake must use ninja as the generator
  • Use CMake target_sources to specify primary modules and module implementations
  • Clang must use libc++ instead of libstdc++
  • C++ 23 standard is required

CMake configuration

As for now, import std is still the experimental feature for the latest version of CMake (4.1). Thus, using the import std from C++ 23 requires a bit unusual setting, which will be removed in the future versions.

Here is an example of the root CMake file CMakeLists.txt:

cmake_minimum_required(VERSION 3.28)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") # better set from the outside
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "0e5b6991-d74f-4b3d-a41c-cf096e0b2508")

project(test VERSION 1.0)

set(CMAKE_CXX_MODULE_STD ON)
set(CMAKE_CXX_STANDARD 23)

add_executable(run)
target_sources(run PRIVATE main.cpp)

Different from the normal CMake configuration, there are three additional settings:

  1. Set the clang to use libc++. Normally it should be set in the shell environment before running CMake:
export CXXFLAGS="-stdlib=libc++"

If set inside the cmake file, it must be positioned before the project() command.

  1. (Will be removed in the future CMake versions) Specify the experimental feature of CMake. Again, it must be positioned before the project() command.

  2. Enable CMAKE_CXX_MODULE_STD in the project global scope.

Using modules instead of include

Example: godbolt

When creating a module, user must use target_sources to add the primary module file to the target:

add_library(mylib SHARED)

target_sources(mylib PUBLIC FILE_SET CXX_MODULES FILES mylib.cppm)

With the primary module file mylib.cppm:

export module mylib;

import std;

export namespace mylib {
template <typename DataType>
class Vector3 {
   public:
    Vector3(DataType x, DataType y, DataType z) : x_{x}, y_{y}, z_{z} {}
    void print() const { std::println("x: {}, y: {}, z: {}", x_, y_, z_); }

   private:
    DataType x_;
    DataType y_;
    DataType z_;
};

}  // namespace mylib

template <typename Type>
concept VectorType = requires(Type vec) {
    Type{1, 2, 3};
    vec.print();
};

export void print_vector(const VectorType auto& vector) { vector.print(); }

Any file with export module module_name is recognized as the primary module file by the compiler. The module name is independent from the file name. Different entites, such as classes, functions, templates or namespaces, are exported using export keyword. Those which are not exported, are not reachable by name, but still usable and defined.

To import this module, simple use import keyword in the source file:

import mylib;

auto main() -> int {
    const auto vec = mylib::Vector3{1, 2, 3};
    vec.print();
    print_vector(vec);
    return 0;
}

Further resources

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment