如何在 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
。
模块是#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
。