Experimental Modules Support
This reflects the status as of CMake 3.27.
I will keep updating this answer as the situation changes.
Important: CMake's support for C++20 modules is currently functional, but still experimental. Things may work in some cases but break in others. Expect bugs and breaking changes between versions!
See also the relevant issue in the CMake issue tracker.
Note that supporting modules requires far more support from the build system than inserting a new compiler option. It fundamentally changes how dependencies between source files have to be handled during the build: In a pre-modules world all cpp source files can be built independently in any order. With modules that is no longer true, which has implications not only for CMake itself, but also for the downstream build system.
Take a look at the CMake Fortran modules paper for the gory details. From a build system's point of view, Fortran's modules behave very similar to the C++20 modules.
Prerequisites
Proper integration currently only works with the following generators:
- Ninja version 1.10 or newer
- Visual Studio 2022 version 19.34 or newer.
Module dependency scanning is currently supported by the following compilers:
- MSVC compiler version 19.34 or newer
- LLVM/Clang version 16 or newer.
Be sure that both your compiler and build system are sufficiently up-to-date!
Note: Getting Clang to work requires at least Clang version 16 and additionally may at this point still require some fiddling with CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE
. Since this is way too deep into the tool internals, I will not cover that in this answer! Check out CMake's feature guide if you want to try this out. This should get resolved in a future version of CMake though.
Some General Remarks
- Always use the absolute latest CMake, build tool, and compiler versions that you can. This feature is still under heavy development and receives a constant stream of vital bugfixes.
- Read the docs:
- D1483 explains how the build process looks like for modules and why it's considerably more difficult than a non-modules build. This is an essential read.
- CMake Experimental Features Guide Documents the limitations of the current experimental implementation in CMake. If something doesn't work as expected, check here first.
- Familiarize yourself with the basic feature set and vocabulary of Modules. Daniela Engert's talk is an excellent introduction.
- Read Kitware's blog post for additional info not covered in this answer, like how to try out Modules with a custom build of gcc.
- The tooling will produce a bunch of
.json
files during the build, which contain the data used by the build system to track module dependencies. If something doesn't work as expected, these can be very useful for debugging.
- None of this is cleared for use in production at this point! Keep in mind that this is an experimental feature that is mainly being made available so that compiler and tool implementers can iron out the bugs.
Activating Modules Support in CMake
Since CMake's support for modules is experimental at this point, you will have to opt-in to the feature before being able to use it:
cmake_minimum_required(VERSION 3.27)
project(my_modules_project)
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API aa1f7df0-828a-4fcd-9afc-2dc80491aca7)
set(CMAKE_CXX_STANDARD 20)
The last line here is optional, but your compiler may refuse to compile code using modules if you don't request C++20 support. Note that C++20 does not contain a modularized version of the standard library, you will need at least C++23 for that.
Setting CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API
activates the modules support. The magic number for CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API
changes with every CMake release, so be sure to double-check the docs for your CMake release if CMake complains about not recognizing the module-related commands.
Using Modules
Module source files need to be specified using the FILE_SET
feature of CMake's target_sources
command. FILE_SET
is quite useful for libraries without modules as well, so check it out if you don't know the feature yet.
Module source files are distinguished from normal source files by being part of the special CXX_MODULES
file set:
add_executable(my_app)
target_sources(my_app PRIVATE
FILE_SET all_my_modules TYPE CXX_MODULES
BASE_DIRS
${PROJECT_SOURCE_DIR}
FILES
a.cppm
b.cppm
)
target_sources(my_app PRIVATE
main.cpp
)
Here a.cppm
and b.cppm
are module source files that can make use of the export
keyword of C++20 modules. In contrast main.cpp
may use the import
keyword, but not the export
keyword. The distinguishing factor here is the FILE_SET
, not the file extension! We simply use .cppm
for module sources here for illustrative purposes.
Note that if your source file is a module implementation unit it must not be part of the CXX_MODULES
fileset! You should also not use a module-style file extension like .cppm
or .ixx
, but instead use plain .cpp
as the file extension for these, as some compilers may otherwise treat the files as module interface units, which will break your build.
Header units are currently not supported anywhere (neither by CMake nor by any of the major build systems) and there are serious concerns about the implementability of this feature. Daniel Ruoso gave an excellent talk at C++Now 2023 (video) explaining those concerns. You should stick with named modules for now.
A complete working example
You can also find this example on Github.
// a.cppm
module;
#include <iostream>
export module MyModule;
int hidden() {
return 42;
}
export void printMessage() {
std::cout << "The hidden value is " << hidden() << "\n";
}
// main.cpp
import MyModule;
int main() {
printMessage();
}
# CMakeLists.txt
cmake_minimum_required(VERSION 3.27)
set(CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API aa1f7df0-828a-4fcd-9afc-2dc80491aca7)
project(modules-example)
set(CMAKE_CXX_STANDARD 20)
add_executable(demo)
target_sources(demo
PUBLIC
main.cpp
)
target_sources(demo
PUBLIC
FILE_SET all_my_modules TYPE CXX_MODULES FILES
a.cppm
)
If you set everything up correctly, CMake should give you the following warning during its configure stage:
CMake Warning (dev) at CMakeLists.txt:??? (target_sources):
CMake's C++ module support is experimental. It is meant only for
experimentation and feedback to CMake developers.
This warning is for project developers. Use -Wno-dev to suppress it.
The project should still build fine and rebuild correctly when changing the source files.
If you get an error saying
target_sources File set TYPE may only be "HEADERS"
it means that either your CMake version is too old, or you did not set up the Modules support correctly. Double-check CMake's documentation in this case.