5

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

目前我这样做

#include <iostream>
#include <string>

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

import std.core;

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

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

注意:我不能使用的原因#include <...>或者#import <...>是因为其他错误可能会产生自己的问题。所以我认为import std.core如果可能的话,getting 或类似的方法是现在要走的路。

ModernesCpp还提到了 std.core。

4

3 回答 3

7

C++20 标准不包括 C++ 标准库的模块定义。Visual Studio确实如此(不幸的是),而且很多糟糕的网站都会表现得像这样是标准的。但事实并非如此;这只是微软的事情。

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

于 2021-02-28T18:02:47.867 回答
5

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

首先创建以下文件:

module.modulemap

module std_mod {
    requires cplusplus17
    header "std_mod.hpp"
    export *
}

std_mod.hpp

#include <iostream>
#include <map>
#include <set>
#include <vector>

使用.cpp

import std_mod;

int main() {
    std::cout << "Hello, World!" << std::endl;
}

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

然后执行命令:

clang++ -### use.cpp -c -std=c++20 -m64 -g -O3 >use.txt 2>&1

在这里,-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++"

如您所见,此命令包含包含的完整路径,它们是必需的。执行上面的命令,它将产生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

看到我添加了-fmodule-file=std_mod.pcm- 每个导入的模块都需要这样的选项。作为替代方案,您可以使用-fprebuilt-module-path=<directory>指定搜索所有预构建模块的位置。

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

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

附言。为什么我在上面实施了相当长的解决方案?因为至少在 Windows 的 CLang 下一个简单的程序

import <iostream>;
int main() {}

不编译,它说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 one 需要一个特殊的解决方案,解决方案import <header-name>;在这里不起作用。

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

于 2021-04-29T18:27:00.233 回答
-1

我找到了获得想法的地方,llvms 文档。有一段说明

“例如,C 标准库的模块映射文件可能看起来有点像这样:”

module std [system] [extern_c] {
  module assert {
    textual header "assert.h"
    header "bits/assert-decls.h"
    export *
  }

  module complex {
    header "complex.h"
    export *
  }

  module ctype {
    header "ctype.h"
    export *
  }

  module errno {
    header "errno.h"
    header "sys/errno.h"
    export *
  }

  module fenv {
    header "fenv.h"
    export *
  }

  // ...more headers follow...
}

看来您随后命名了该文件something.modulemap并将其发送给编译器。快速谷歌搜索没有找到任何类似的 msvc 解决方案(除了前面讨论的 std.io)。

我还没有尝试过,我想我会接受我自己的答案,或者如果其他人想出更好的答案。

于 2021-02-28T18:16:14.887 回答