【问题标题】:How to compile/use header unit modules under CLang C++?如何在 CLang C++ 下编译/使用头单元模块?
【发布时间】:2021-07-16 12:27:33
【问题描述】:

文档中说 CLang 中的模块支持是部分的。我在最近发布的 LLVM 12.0 的 Windows 64 位下使用 CLang。

我成功地使用了常规模块(通过import modulename; 导入)。

但我还没有设法创建和使用标题单元模块,即您通过import "header.hpp"; 导入的那些。您能否通过示例建议如何做到这一点?

为了尝试标题单元,我创建了下一个玩具文件:

hello.hpp

#include <vector>

使用.cpp

import "hello.hpp";

int main() {
    std::vector<int> v(123);
}

然后我成功(我希望)将头单元hello.hpp编译成PCM文件:

clang++ -std=c++20 -Xclang -emit-header-module -I. hello.hpp -o hello.pcm

命令运行没有错误并产生hello.pcm。如果您在没有-o 标志的情况下运行上面的命令,则文件 hello.hpp.gch 已创建。

然后我尝试编译use.cpp,但没有成功,不知何故它无法识别我的标头单元和/或找不到对应的hello.pcm。我想我缺少一些特殊标志,这些标志显示编译器它是头单元。使用了下一个命令:

clang++ -std=c++20 -fprebuilt-module-path=. -fmodule-file=hello.hpp=hello.pcm -I. use.cpp

编译错误:

use.cpp:1:8: error: header file "hello.hpp" (aka './hello.hpp') cannot be imported because it is not known to be a header unit
import "hello.hpp";
       ^

在 MSVC 下,我成功地使用了常规模块和标头单元模块。但不是在 Clang 中。你能帮我解决这个问题吗?或者告诉我可能还不支持 CLang 标头单元。

【问题讨论】:

    标签: c++ clang c++20 c++-modules


    【解决方案1】:

    我终于设法解决了上面的几乎任务。

    以下说明适用于 Windows 64 位、来自 LLVM 12.0 版本的最新 CLang(您可以获取 here)和最新的 MSVC Community Build Tools 2019 v16.9.4(您可以从 here 获取)。

    我解决的任务不是完全针对标头单元,而是针对标头模块,它们的行为几乎相同,它们的用法没有区别。

    下面的玩具示例文件:

    module.modulemap

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

    mod.hpp

    #include <iostream>
    

    使用.cpp

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

    我使用了接下来的 3 个命令:

    clang++.exe -cc1 module.modulemap -o prebuilt/mod.pcm -emit-module -fmodules -fmodule-name=mod -std=c++20 ^
        -internal-isystem "d:\\bin2\\Microsoft Visual Studio\\2019\\BuildTools\\VC\\Tools\\MSVC\\14.28.29910\\include" ^
        -internal-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.19041.0\\ucrt" ^
        -debug-info-kind=limited -fms-extensions -fms-compatibility -fms-compatibility-version=19.28 -xc++ ^
        -fmath-errno -fexceptions -fcxx-exceptions -triple x86_64-pc-windows-msvc || exit /b
        
    clang++.exe -cc1 -emit-obj use.cpp -fmodule-file=prebuilt/mod.pcm -std=c++20 ^
        -internal-isystem "d:\\bin2\\Microsoft Visual Studio\\2019\\BuildTools\\VC\\Tools\\MSVC\\14.28.29910\\include" ^
        -internal-isystem "C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.19041.0\\ucrt" ^
        -debug-info-kind=limited -fms-extensions -fms-compatibility -fms-compatibility-version=19.28 -xc++ ^
        -fmath-errno -fexceptions -fcxx-exceptions -triple x86_64-pc-windows-msvc || exit /b
        
    clang++.exe use.o -o use.exe || exit /b
    

    这一切都没有错误。您可以看到包含标准库目录的完整路径,这些路径特定于我的系统。这是必需的,因为在命令中我使用了-cc1 选项,该选项启用了使用低级 CLang 前端而不是简化的驱动程序,这个前端需要很多低级选项才能工作。

    您只需执行clang++ -### use.cpp 即可获取所有选项,这将转储到控制台您系统所需的所有选项。

    以上命令只能用于-cc1前端,驱动不支持模块映射文件。

    其实上面第二条命令这3条命令可以简化,编译目标文件不需要低级前端。但是只有在第一个命令有clang -###命令获得的默认参数的情况下才能简化,那么第二个命令可以简写为clang++ use.cpp -o use.o -c -std=c++20 -fmodule-file=prebuilt/mod.pcm

    这些命令的结果是use.o 在几分之一秒内编译完毕。众所周知,iostream 编译需要大量时间。 use.o 的编译速度非常快,这意味着我们正确使用了模块并提高了速度。

    为什么我首先需要标题单元?为了能够升级我的旧代码,只需使用导入自动替换常规的旧式包含,从而大大缩短编译时间。这种更换只能使用接头单元或接头模块进行。据我所知,常规模块无法导出其他完整标题。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-02-27
      • 2021-03-21
      • 2016-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多