CMake added support for C++20 named modules in version 3.28.
A complete working example
You can try this example in Compiler Explorer and find it 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.28)
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
)
The project should build fine and rebuild correctly when changing the source files.
Further details
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
Ensure that your compiler has proper support for C++20 modules and dependency scanning:
- MSVC compiler version 19.34 or newer
- LLVM/Clang version 16 or newer. (I personally recommend at least version 17 due to a number of bugs in 16)
- gcc version 14 or newer.
Also be aware that CMake only supports modules for the following generators:
- Visual Studio 2022, toolset 19.34 (Visual Studio 17.4) or newer
- Ninja version 1.11 or newer
Be sure that both your compiler and build system are sufficiently up-to-date!
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:
- 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.
- This feature is still in an early stage, so be prepared to encounter bugs in both the compiler and build system implementations.
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.
Limitations
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.
CXX_STANDARD, and a CMake if-statement to check for Clang or MSVC, then adding the appropriate compiler flags based on your compiler.-std=c++2a -fmodules-tsand it says fatal error: module 'VulkanRender' not found. How can i tell clang where my modules are stored?