实验模块支持
这反映了 CMake 3.27 的状态.
我会随着情况的变化不断更新这个答案。
重要的:CMake 对 C++20 模块的支持目前已正常运行,但仍处于实验阶段。在某些情况下事情可能会起作用,但在其他情况下可能会崩溃。预计版本之间会出现错误和重大更改!也可以看看CMake 问题跟踪器中的相关问题 https://gitlab.kitware.com/cmake/cmake/-/issues/18355.
请注意,支持模块需要构建系统提供比插入新编译器选项更多的支持。它从根本上改变了构建过程中处理源文件之间依赖关系的方式:在前模块世界中,所有 cpp 源文件都可以按任何顺序独立构建。对于模块来说,情况不再如此,这不仅对 CMake 本身有影响,而且对下游构建系统也有影响。
看看CMake Fortran 模块论文 https://mathstuf.fedorapeople.org/fortran-modules/fortran-modules.html对于血淋淋的细节。从构建系统的角度来看,Fortran 模块的行为与 C++20 模块非常相似。
先决条件
目前正确的集成仅适用于以下生成器:
- Ninja 版本 1.10 或更高版本
- Visual Studio 2022 版本 19.34 或更高版本。
目前以下编译器支持模块依赖关系扫描:
- MSVC 编译器版本 19.34 或更高版本
- LLVM/Clang 版本 16 或更高版本。
请确保both您的编译器和构建系统已经足够最新了!
注意:让 Clang 工作至少需要 Clang 版本 16,并且此时可能仍然需要一些摆弄CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE
。由于这对于工具内部来说太深入了,我将not在这个答案中涵盖这一点!查看CMake的功能指南 https://github.com/Kitware/CMake/blob/release/Help/dev/experimental.rst#c20-module-apis如果你想尝试一下。不过,这个问题应该会在 CMake 的未来版本中得到解决。
一些一般性评论
- 尽可能使用绝对最新的 CMake、构建工具和编译器版本。此功能仍在大力开发中,并不断收到重要的错误修复。
- Read the docs:
-
D1483 https://mathstuf.fedorapeople.org/fortran-modules/fortran-modules.html解释了模块的构建过程如何,以及为什么它比非模块构建要困难得多。这是一本必读的书。
-
CMake 实验功能指南 https://github.com/Kitware/CMake/blob/release/Help/dev/experimental.rst#c20-module-apis记录 CMake 当前实验实现的局限性。如果某些内容未按预期工作,请先检查此处。
- 熟悉模块的基本功能集和词汇。丹妮拉·恩格特的演讲 https://www.youtube.com/watch?v=Kqo-jIq4V3I是一个很好的介绍。
- Read Kitware 的博客文章 https://www.kitware.com/import-cmake-c20-modules/有关此答案中未涵盖的其他信息,例如如何使用 gcc 的自定义构建来尝试模块。
- 该工具将产生一堆.json files https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1689r5.html在构建期间,其中包含构建系统用于跟踪模块依赖性的数据。如果某些东西没有按预期工作,这些对于调试非常有用。
-
目前这些都还没有被允许在生产中使用!请记住,这是一项实验性功能,主要是为了让编译器和工具实现者可以消除错误。
激活 CMake 中的模块支持
由于 CMake 对模块的支持目前处于实验阶段,因此您必须先选择加入该功能,然后才能使用它:
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)
这里的最后一行是可选的,但如果您不请求 C++20 支持,您的编译器可能会拒绝使用模块编译代码。请注意,C++20 不包含标准库的模块化版本,为此您至少需要 C++23。
Setting CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API
激活模块支持。神奇的数字为CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API
每个 CMake 版本都会发生变化,因此请务必仔细检查the docs https://github.com/Kitware/CMake/blob/release/Help/dev/experimental.rst#c20-module-apis如果 CMake 抱怨无法识别与模块相关的命令,则针对您的 CMake 版本。
使用模块
模块源文件需要使用指定FILE_SETCMake的特点target_sources https://cmake.org/cmake/help/latest/command/target_sources.html#file-sets命令。FILE_SET
对于没有模块的库也非常有用,所以如果您还不知道该功能,请检查一下。
模块源文件与普通源文件的区别在于它是特殊源文件的一部分CXX_MODULES
文件集:
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
是可以利用的模块源文件export
C++20 模块的关键字。相比之下main.cpp
可以使用import
关键字,但不是export
关键词。这里的区别因素是FILE_SET
,不是文件扩展名!我们简单地使用.cppm
此处的模块源仅供说明之用。
请注意,如果您的源文件是模块实施单位它必须not成为其中的一部分CXX_MODULES
文件集!您也不应该使用模块样式的文件扩展名,例如.cppm
or .ixx
,而是使用普通的.cpp
作为这些文件的文件扩展名,因为某些编译器可能会将这些文件视为模块接口单元,这将破坏您的构建。
目前,头文件单元不受任何地方的支持(无论是 CMake 还是任何主要构建系统),并且人们对此功能的可实现性存在严重担忧。丹尼尔·鲁索 (Daniel Ruoso) 给出了C++Now 2023 上的精彩演讲 https://schedule.cppnow.org/session/c-modules-the-challenges-of-implementing-header-units/ (video https://www.youtube.com/watch?v=_LGR0U5Opdg)解释这些担忧。您现在应该坚持使用命名模块。
一个完整的工作示例
您还可以在以下位置找到此示例Github https://github.com/ComicSansMS/CMake_Modules.
// 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
)
如果您正确设置了所有内容,CMake 应在配置阶段向您发出以下警告:
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.
更改源文件时,项目仍应正常构建并正确重建。
如果您收到错误消息
target_sources File set TYPE may only be "HEADERS"
这意味着您的 CMake 版本太旧,或者您没有正确设置模块支持。再检查一遍CMake 的文档 https://github.com/Kitware/CMake/blob/release/Help/dev/experimental.rst#c20-module-apis在这种情况下。