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
clang: >= 20.1cmake: >= 3.28ninja: >= 1.11
- CMake must use ninja as the generator
- Use CMake
target_sourcesto specify primary modules and module implementations - Clang must use libc++ instead of libstdc++
- C++ 23 standard is required
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:
- 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.
-
(Will be removed in the future CMake versions) Specify the experimental feature of CMake. Again, it must be positioned before the
project()command. -
Enable
CMAKE_CXX_MODULE_STDin the project global scope.
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;
}