cmake-cxxmodules(7)

在 3.28 版本中添加。

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

编译策略

使用 C++ 模块,编译一组 C++ 源文件不再是易于并行化的。也就是说,任何给定的源文件可能首先需要先编译另一个源文件,以便提供 CMI(编译模块接口)或 BMI(二进制模块接口),C++ 编译器使用它们来满足其他源文件中的 import 语句。使用头文件,源文件可以共享它们的声明,以便任何使用者都可以独立编译。使用模块,声明现在由编译器在编译期间基于源文件的内容及其 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++

  • MSVC 工具集 14.36 及更高版本(随 Visual Studio 17.6 Preview 2 及更高版本提供)

可以使用 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 源提供的模块。