如何在 Clang 中使用 C++ 模块?

How do I use C++ modules in Clang?

模块是#includes 的替代品。 Clang has a complete implementation for C++。如果我现在想使用 Clang 来使用模块,我该怎么办?


正在使用

import std.io;

在 C++ 源文件中还不能工作(编译),因为模块规范(包括语法)不是最终的。


Clang documentation 指出,当传递 -fmodules 标志时,#includes 将被重写为适当的导入。但是,检查预处理器会提出其他建议(test.cpp 仅包含 #include <stdio.h> 和一个空的 main):

$ clang++-3.5 -fmodules -E test.cpp -o test
$ grep " printf " test
extern int printf (const char *__restrict __format, ...);

此外,使用 -fmodules 与完全不使用任何标志编译此测试文件会生成相同的目标文件。

我做错了什么?

就像你提到的,clang 还没有用于导入的 C++ 语法, 所以我怀疑 #include 指令在预处理文件时会被 按字面意思 重写为导入,因此这可能不是测试模块是否按预期工作的最佳方法。

但是,如果您明确设置 -fmodules-cache-path=<path>,您可以观察到 clang 在构建期间使用预编译模块文件 (*.pcm) 填充它 - 如果涉及任何模块。

如果你现在想使用启用模块的标准库,你需要使用 libc++(从 3.7.0 版本开始它似乎带有 module.modulemap)——尽管根据我的经验,这是还没有完全工作。 (Visual Studio 2015 年的 C++ 编译器也应该在 11 月的更新 1 中获得某种形式的模块支持)

独立于 stdlib,您仍然可以在自己的代码中使用模块。 clang 文档包含 Module Map Language.

的详细描述

截至 this commit, Clang has experimental support for the Modules TS

让我们使用与 VS blog post 关于实验模块支持的示例文件相同的示例文件(稍作改动)。

首先,定义模块接口文件。默认情况下,Clang 将具有 cppm 扩展名(和其他一些)的文件识别为 C++ 模块接口文件。

// file: foo.cppm
export module M;

export int f(int x)
{
    return 2 + x;
}
export double g(double y, int z)
{
    return y * z;
} 

请注意,模块接口声明需要是 export module M; 而不是像 VS 博客 post.

中那样只是 module M;

然后消费模块如下:

// file: bar.cpp
import M;

int main()
{
    f(5);
    g(0.0, 1);
    return 0;
}

现在,用

预编译模块foo.cppm
clang++ -fmodules-ts --precompile foo.cppm -o M.pcm

或者,如果模块接口扩展名不是 cppm(比方说 ixx,因为它与 VS 一样),您可以使用:

clang++ -fmodules-ts --precompile -x c++-module foo.ixx -o M.pcm

然后使用

构建程序
clang++ -fmodules-ts -c M.pcm -o M.o
clang++ -fmodules-ts -fprebuilt-module-path=. M.o bar.cpp

或者,如果 pcm 文件名与模块名不同,则必须使用:

clang++ -fmodules-ts -fmodule-file=M.pcm bar.cpp

我使用 r303050 build(2017 年 5 月 15 日)在 Windows 上测试了这些命令。

注意:当使用 -fprebuilt-module-path=. 选项时,我收到警告:

clang++.exe: warning: argument unused during compilation: '-fprebuilt-module-path=.' [-Wunused-command-line-argument]

这似乎是不正确的,因为没有那个选项,就找不到模块 M