cmake-cxxmodules(7)

版本 3.28 新增。

C++ 20 引入了语言的“模块”概念。其设计要求构建系统在编译之间进行排序,以可靠地满足 import 语句。CMake 的实现要求编译器在构建期间扫描源文件以获取模块依赖项,整理扫描结果以推断排序约束,并告知构建工具如何动态更新构建图。

编译策略

使用 C++ 模块,编译一组 C++ 源文件不再是高度并行的。也就是说,任何给定的源文件可能首先需要编译另一个源文件,以便提供 C++ 编译器用于满足其他源文件中的 import 语句的“CMI”(编译模块接口)或“BMI”(二进制模块接口)。使用头文件时,源文件可以共享它们的声明,以便任何使用者都可以独立编译。使用模块时,声明现在由编译器在编译期间根据源文件的内容及其 export 语句生成到这些 BMI 文件中。

编译所需的顺序需要在构建时解析,因为该顺序由源文件的内容控制。这意味着需要在构建期间从源文件中提取顺序,以避免为每次源文件更改重新生成构建图(通过配置和生成阶段)以获得正确的构建。

一般策略是使用“扫描器”提取排序依赖信息,并通过将每源扫描结果(由 P1689R5 文件表示)与目标内以及与目标可见的模块的依赖项进行“整理”,从而在现有边之间更新构建图。主要任务是生成“模块映射”文件,以传递给每个编译规则,其中包含满足 import 语句所需的 BMI 路径。整理器还负责使用构建时信息填充信息,包括模块接口单元及其 BMI 的 install 规则,以及任何具有 C++ 模块的导出目标的属性。

注意

CMake 正在专注于正确的构建,然后再考虑性能改进。所选策略中存在一些已知策略,它们可能会带来构建性能改进。然而,它们正在推迟,直到我们有一个可供比较的有效模型。还需要注意的是,在一种情况下(例如,全新构建)有用的策略在另一种情况(例如,增量构建)下可能表现不佳。寻找平衡并提供控件来选择策略是未来的工作。

扫描控制

源文件是否被扫描以查找 C++ 模块使用情况取决于以下查询。使用第一个提供是/否答案的查询。

  • 如果源文件属于 CXX_MODULES 类型的文件集,它将被扫描。

  • 如果目标不使用至少 C++ 20,它将不会被扫描。

  • 如果源文件不是 CXX 语言,它将不会被扫描。

  • 如果设置了 CXX_SCAN_FOR_MODULES 源文件属性,则使用其值。

  • 如果设置了 CXX_SCAN_FOR_MODULES 目标属性,则使用其值。设置 CMAKE_CXX_SCAN_FOR_MODULES 变量,以便在创建所有目标时初始化此属性。

  • 否则,如果编译器和生成器支持扫描,源文件将被扫描。请参阅策略 CMP0155

请注意,任何被扫描的源文件都将从任何统一构建中排除(请参阅 UNITY_BUILD),因为模块相关语句只能在 C++ 翻译单元中的一个位置出现。

编译器支持

CMake 原生支持模块依赖扫描的编译器包括:

  • MSVC 工具集 14.34 及更新版本(随 Visual Studio 17.4 及更新版本提供)

  • LLVM/Clang 16.0 及更新版本

  • GCC 14(适用于开发中分支,在 2023-09-20 之后)及更新版本

import std 支持

import std 的支持仅限于以下工具链和标准库组合:

  • Clang 18.1.2 及更高版本,支持 -stdlib=libc++-stdlib=libstdc++

  • MSVC 工具集 14.36 及更新版本(随 Visual Studio 17.6 预览版 2 及更新版本提供)

  • GCC 15 及更新版本。

可以使用 CMAKE_CXX_COMPILER_IMPORT_STD 变量检测活动 C++ 工具链对标准级别的支持。

注意

此支持仅在通过 CMAKE_EXPERIMENTAL_CXX_IMPORT_STD 门启用 import std; 的实验性支持时提供。

生成器支持

支持扫描 C++ 模块源文件的生成器列表包括:

限制

CMake 当前的 C++ 模块支持存在许多已知限制。本文档不记录编译器中已知的限制或错误,因为这些限制或错误会随时间变化。

对于所有生成器:

  • 不支持头单元。

  • 不支持 import std; 或其他编译器提供的模块的内置支持。

对于 Ninja 生成器:

  • 需要 ninja 1.11 或更新版本。

对于 Visual Studio 生成器

  • 仅支持 Visual Studio 2022 和 MSVC 工具集 14.34 (Visual Studio 17.4) 及更新版本。

  • 不支持导出或安装 BMI 或模块信息。

  • 不支持从具有 C++ 模块的 IMPORTED 目标编译 BMI(包括 import std)。

  • 对于从 PUBLIC 模块源使用 PRIVATE 源提供的模块,没有诊断。