cmake-cxxmodules(7)

添加于 3.28 版本。

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

编译策略

采用 C++ 模块后,就不再能并发的编译一组 C++ 源代码。也就是说,为了提供 C++ 编译器用来满足其他源代码中 import 语句的“CMI”(编译的模块接口)或“BMI”(二进制模块接口),任何给定的源代码可能首先需要编译另一个源文件。有了头文件,源代码就可以共享它们的声明,这样任何消费者都可以独立地进行编译。有了模块,编译器将根据源文件的内容及其 export 语句,在编译期间将声明生成为这些 BMI 文件。

编译必需的顺序需要在编译时解析该顺序,因为该顺序由源代码的内容控制。这意味着在构建期间需要从源代码中提取顺序,以避免因每个源代码更改而重新通过配置和生成阶段来生成构建图,以获取正确的构建结果。

总体策略是使用“扫描器”提取顺序依赖项信息,并通过使用按源扫描结果(由 P1689R5 文件表示)以及“整理”目标内的依赖项和在目标中可见的其他目标所生成模块,来使用现有的边更新构建图中的新边,。最重要的任务是生成“模块映射”文件,以便将包含满足 import 语句所需的 BMI 路径传递到每个编译规则。整理器还有使用构建时信息来填写导出目标的模块接口单元、其 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 年 9 月 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++ 工具链的标准级别的支持。

注意

仅当 import std; 的实验性支持已通过 CMAKE_EXPERIMENTAL_CXX_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。

  • 不诊断使用 PRIVATE 源中提供的模块 PUBLIC 模块源。