使用 clang 将 std lib 作为模块导入

Las*_*öld 4 c++ clang++ c++20 c++-modules

我正在尝试使用 clang 中的模块,并希望将标准库包含为模块而不是包含。

目前我这样做

#include <iostream>
#include <string>
Run Code Online (Sandbox Code Playgroud)

看来您在 msvc 中应该能够导入标准库,例如

import std.core;
Run Code Online (Sandbox Code Playgroud)

然而,当使用 clang 时,这似乎没有实现,或者以另一种方式实现。

我的问题是:是否可以像微软建议的那样导入 stl-includes,或者是否可以将标准库包含映射到模块 somhow。

注意:我无法使用的原因#include <...>或者#import <...>是因为其他错误可能会导致其自身问题。所以我认为import std.core如果可能的话,获取或类似是现在要走的路。

ModernesCpp还提到了 std.core。

Nic*_*las 7

C++20 标准不包括 C++ 标准库的模块定义。Visual Studio可以(不幸的是),而且许多不良站点会表现得像标准一样。但事实并非如此;这只是微软的事情。

如果要通过跨平台的模块包含 C++ 标准库,则必须使用import <header-name>语法或编写自己的标准库模块来导入标头并导出特定的 C++ 声明。

  • @NicolBolas 感谢您的回复!我虽然OP的问题很实际,意思是如何在CLang上解决它(标题和标签中有CLang),而且谈论MSVC意味着OP在Win上。我不认为它应该如何在所有编译器上以标准 C++20 存在是理论上的。 (2认同)

Art*_*oul 6

我解决了你的任务。以下是执行此操作的说明。我在 Win 10 64 位上使用 LLVM 12.0 当前版本中的 CLang(取自此处)执行此操作,并且我还安装了 MSVC 2019 v16.9.4 Community(取自此处)。

笔记。这个答案仅适用于 CLang,我也为 MSVC 写了类似的答案

首先创建以下文件:

模块.模块映射

module std_mod {
    requires cplusplus17
    header "std_mod.hpp"
    export *
}
Run Code Online (Sandbox Code Playgroud)

std_mod.hpp

#include <iostream>
#include <map>
#include <set>
#include <vector>
Run Code Online (Sandbox Code Playgroud)

使用.cpp

import std_mod;

int main() {
    std::cout << "Hello, World!" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

在上面的文件中,std_mod.hpp您可以放置​​您需要的任何标准标头。您应该放置在所有项目中使用的所有可能的 STD 标头,以便能够在任何地方共享相同的预编译 STD 模块。

然后执行命令:

clang++ -### use.cpp -c -std=c++20 -m64 -g -O3 >use.txt 2>&1
Run Code Online (Sandbox Code Playgroud)

您可以在这里-std=c++20 -m64 -g -O3使用您的项目所需的任何选项。每个预编译模块都应具有与其他 .cpp 文件相同的编译选项,以便能够链接到最终的二进制文件。

上面的命令将生成use.txt您需要复制的选项。在此选项中,您应该删除-emit-obj选项、 -o选项(及其后面的路径),同时删除use.cpp. 然后添加到该命令选项字符串module.modulemap -o std_mod.pcm -emit-module -fmodules -fmodule-name=std_mod。在我的系统上,我得到以下结果命令:

"D:\\bin\\llvm\\bin\\clang++.exe" "-cc1" module.modulemap -o std_mod.pcm -emit-module -fmodules -fmodule-name=std_mod  "-triple" "x86_64-pc-windows-msvc19.28.29914" "-mincremental-linker-compatible" "--mrelax-relocations" "-disable-free" "-disable-llvm-verifier" "-discard-value-names" "-main-file-name" "use.cpp" "-mrelocation-model" "pic" "-pic-level" "2" "-mframe-pointer=none" "-fmath-errno" "-fno-rounding-math" "-mconstructor-aliases" "-munwind-tables" "-target-cpu" "x86-64" "-tune-cpu" "generic" "-gno-column-info" "-gcodeview" "-debug-info-kind=limited" "-resource-dir" "D:\\bin\\llvm\\lib\\clang\\12.0.0" "-internal-isystem" "D:\\bin\\llvm\\lib\\clang\\12.0.0\\include" "-internal-isystem" "d:\\bin2\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.28.29910\\include" "-internal-isystem" "d:\\bin2\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.28.29910\\atlmfc\\include" "-internal-isystem" "D:\\Windows Kits\\10\\Include\\10.0.19041.0\\ucrt" "-internal-isystem" "D:\\Windows Kits\\10\\include\\10.0.19041.0\\shared" "-internal-isystem" "D:\\Windows Kits\\10\\include\\10.0.19041.0\\um" "-internal-isystem" "D:\\Windows Kits\\10\\include\\10.0.19041.0\\winrt" "-O3" "-std=c++20" "-fdeprecated-macro" "-fdebug-compilation-dir" "D:\\t\\t4" "-ferror-limit" "19" "-fno-use-cxa-atexit" "-fms-extensions" "-fms-compatibility" "-fms-compatibility-version=19.28.29914" "-fdelayed-template-parsing" "-fno-implicit-modules" "-fcxx-exceptions" "-fexceptions" "-vectorize-loops" "-vectorize-slp" "-faddrsig" "-x" "c++"
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,此命令包含包含的完整路径,它们是必要的。执行上面的命令,它将生成std_mod.pcm您可以在任何地方使用相同编译选项的项目。

为什么需要上面的长命令?因为.modulemap只能通过-cc1命令使用文件,该命令执行低级 CLang 前端而不是简化的 CLang 驱动程序(驱动程序没有-cc1选项)。这个低级前端可以执行许多驱动程序无法执行的操作。

use.cpp现在您可以通过下一个命令编译最终程序import std_mod;

clang++ use.cpp -o use.exe -std=c++20 -m64 -g -O3 -fmodule-file=std_mod.pcm
Run Code Online (Sandbox Code Playgroud)

请参阅我添加的内容-fmodule-file=std_mod.pcm- 每个导入的模块都需要这样的选项。作为替代方案,您可以-fprebuilt-module-path=<directory>指定在何处搜索所有预构建模块。

不久前,我还在这里创建了有关如何从 CLang 中的标头创建模块的问题和答案。

有关模块的更多说明,请参阅 CLang 的Modules DocCommandLine Doc

附言。为什么我在上面实现了很长的解决方案?因为至少在 Windows 的 CLang next 简单程序上

import <iostream>;
int main() {}
Run Code Online (Sandbox Code Playgroud)

不编译,它说use.cpp:1:8: error: header file <iostream> (aka 'd:\bin2\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29910\include\iostream') cannot be imported because it is not known to be a header unit。所以至少在Win上需要一种特殊的解决方案,解决方案import <header-name>;在这里不起作用。

通过import <header>;import "header";语法导入的所有标头都应将特殊编译的标头单元模块放入特殊文件夹中以便能够使用。在 Win STD 标头上没有相应的编译标头单元模块。另外,在花了很多时间之后,我没有在 CLang 中找到如何在 Win 上创建这些所谓的标头单元的方法。只有上面的解决方案解决了我将标头导入为模块的任务。