cmake-cxxmodules(7)

版本 3.28 新增。

C++ 20 在语言中引入了“模块”的概念。该设计要求构建系统对编译进行排序,以可靠地满足 import 语句。CMake 的实现通过让编译器在构建过程中扫描源文件以查找模块依赖项,汇总扫描结果以推断排序约束,并告知构建工具如何动态更新构建图来完成此工作。

编译策略

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

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

总体策略是使用“扫描器”提取排序依赖信息,并通过在现有边之间添加新边来更新构建图,方法是采用每个源文件的扫描结果(由 P1689R5 文件表示),并在目标内以及目标可见的模块之间进行“汇总”依赖关系。主要任务是生成“模块映射”文件,将其传递给每个编译规则,其中包含满足 import 语句所需的 BMI 的路径。汇总器还有任务要使用构建时信息来填充信息,包括模块接口单元的 install 规则、它们的 BMI 以及带有 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 Preview 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++ 模块(包括 import std)从 IMPORTED 目标编译 BMI。

  • 不支持诊断从 PUBLIC 模块源使用 PRIVATE 源提供的模块。