如何在 CMake 中使用 c++20 模块?

2024-03-03

Clang http://clang.llvm.org/docs/Modules.html and MSVC http://blogs.msdn.com/b/vcblog/archive/2015/12/03/c-modules-in-vs-2015-update-1.aspx已经支持模块 TS https://github.com/cplusplus/modules-ts来自未完成的 C++20 标准。 我可以使用 CMake 或其他构建系统构建基于模块的项目吗?如何构建?

I tried build2 https://build2.org/,它支持模块并且工作得很好,但是我有一个question https://stackoverflow.com/questions/57296089/build2-analog-of-cmakes-find-package关于它的依赖管理(UPD:问题已关闭)。


实验模块支持

这反映了 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是可以利用的模块源文件exportC++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在这种情况下。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 CMake 中使用 c++20 模块? 的相关文章

随机推荐

  • 亚马逊AWS通过Java API创建EBS(弹性块存储)

    我正在尝试找到一种方法来创建新的 EBS 并通过 AWSJavaSDK 以语法方式将其附加到正在运行的实例程序 我看到了使用命令行工具和基于休息的调用来做到这一点的方法 但没有办法通过正确的 SDK 你应该能够使用创建卷 http docs
  • Azure AD 与 sonarqube 集成

    我使用 nginx 反向代理在 https 上运行 sonarqube 这是我的 nginx 反向代理配置 server server name sonarqube mydomain co in access log var log ngi
  • ASP.net 模型视图演示器值得花时间吗?

    我这个周末正在阅读有关 ASP net MVP 模式的内容 似乎即使是最简单的任务也会花费太多精力 如果以 MVP 模式进行 回报似乎是在更大的项目中 但我想 如果我将会追随MVP 为什么不直接用 ASP net MVC 来做这个项目呢 我
  • 如果是 Chrome,请使用 WebP

    因为目前只有 Chrome 和 Opera 支持 WebP 所以我想知道是否可以针对这两个特定浏览器并将它们重定向以获取我网站的另一个版本 以便我可以帮助更快地优化我的网站下载速度 Thanks 我这样解决了这个问题 检查客户端是否在 Ac
  • 同时显示选项卡栏和列表操作栏。 (安卓蜂巢)

    有一种情况 我想在操作栏中同时使用选项卡栏和列表导航 文档说 我们可以将 Actionbar 置于列表导航模式或选项卡导航模式 有没有办法同时使用两者 任何指示 帮助 先感谢您 抱歉 您只能选择其中之一 话虽这么说 你可以使用android
  • Select2 4.0.x 多复选框 JS 插件

    我正在使用Select2控制与Select2 Multi checkboxes JS插件允许多复选框选择 以下演示显示该控件可以正常工作选择2 3 x http jsfiddle net wasikuss gx93rwnk http jsf
  • 如何以编程方式检查 iPhone 中是否安装了应用程序列表

    在我的应用程序中 我显示了应用程序列表 是否有可能发现 iPhone 中是否安装了应用程序数组 如果有可能 请有人快速提供相关代码来检查 iPhone 中是否安装了一系列应用程序 在过去你可以使用canOpenURL像这样的图书馆iHasA
  • .net 8 预览版 Linux 上托管的 Azure 应用服务无法启动,显然要求安装 8.0.0-rc

    最后 App Service 可以在 Linux 容器下的 NET 8 Preview 上运行 尚不支持 Windows 我创建了一个并部署了一个简单的应用程序 但容器没有启动 如下所示 2023 09 17T20 25 27 314076
  • Google 应用内支付:如何处理 Google 的回发 JWT

    也许这是一个愚蠢的问题 但我不是高级程序员 我有 已成功为我的应用程序设置应用内付款 但它只能工作 不使用回发 url 我已经在谷歌上搜索了很多个小时 试图自己解决这个问题 但没有 成功 希望有人能帮助我 我已经包含了脚本 处理发布数据这显
  • 创建模型时使用外键自动创建模型 - Django

    我正在我的网页上创建评论部分 并希望用户能够对评论投赞成票或反对票 我的模型是这样的 class Comment models Model owner models ForeignKey User body models TextField
  • Windows attrib 命令行程序不会删除只读属性?

    我使用 windows attrib 命令删除目录只读属性并将其设置回来 如下所示 attrib r C build attrib C build C build attrib r C build attrib C build R C bu
  • 原始浮点编码

    Update原来的问题不再是这个问题的适当问题 所以我将单独保留这个问题来演示我尝试 学到的内容和背景 很明显 这不仅仅是一个 Base64 变体 而且涉及更多一些 背景 我使用 python 3 x 进行编程主要是为了与开源程序 Blen
  • 在日期/时间调用方法

    我正在寻找一个modern在给定日期 时间执行给定方法的方法 ZonedDateTime尤其 我知道Timer类和Quartz库 如下所示 线程包括完整的解决方案 Java 在特定日期执行方法 关闭 https stackoverflow
  • 如何将 Firestore 数据库从 Google 存储桶导出到 Json 文件

    情况如下 我有一个 Firestore 数据库 我每天都会将其下载到 Google Cloud Storage Bucket 作为备份 如果我想在本地下载它 我使用这个命令gsutil m cp r gs BUCKET PATH DESTI
  • ngrx/data 实体数据服务

    尝试理解ngrx data实体数据服务示例here https ngrx io guide data creating entity data services 其中显示 创建实体数据服务 在展示该服务之后 文档继续展示如何在组件中使用 n
  • C++ 重载虚函数发出 clang 警告?

    clang 在编译以下代码时发出警告 struct Base virtual void get char e virtual void get char e int index struct Derived public Base virt
  • 如果 ID 存在则更新记录,否则插入值

    如果记录存在 我正在尝试更新值 否则将值插入数据库 然而 这是行不通的 我写了下面的代码 String sqlCheck Select from UAP dbo UAP EMPLOYEE where EMP EMPLOYEE ID empI
  • 在 XCode 5 中应用程序窗口预计在应用程序启动结束时有一个根视图控制器

    我使用 Single View 或 Master View 模板在新的 XCode 5 中创建的每个新项目都会给我错误 应用程序窗口预计在应用程序启动结束时有一个根视图控制器 但只有当 UIView 等对象添加到类中时才会出现错误 我一如既
  • 无法在 Visual Studio 2010 中调试 MVC 源代码

    我正在尝试使用 Microsoft 符号服务器在 Visual Studio 2010 中调试 MVC 源代码 我已经配置了调试选项 如下所示 我的项目面向 NET Framework 4 0 如中所述调试 NET Framework 的源
  • 如何在 CMake 中使用 c++20 模块?

    Clang http clang llvm org docs Modules html and MSVC http blogs msdn com b vcblog archive 2015 12 03 c modules in vs 201