给定一个模块
// a-m.ccexport module A;import B;import C;import "D.h";...
// a-m.cc
export module A;
import B;
import C;
import "D.h";
...
字符串是否有一种方法可以调用gcc(类似于-M对头文件所做的),它将列出对其他模块和导入的头文件(即B、C和“D. h”)的直接依赖关系?
ulydmbyx1#
看起来我们可以用标志-MMD调用gcc,它也跟踪模块依赖关系。给出我的一个示例项目,我像这样生成它:
-MMD
// partition.cppexport module partition;import :partition1;export import :partition2;export import :partition3;export void Hello1() { _Hello1(); }
// partition.cpp
export module partition;
import :partition1;
export import :partition2;
export import :partition3;
export void Hello1() { _Hello1(); }
字符串出于某种原因,我需要在编译主模块接口(上面显示的文件)之前编译模块分区,但也许这可以以某种方式绕过。我编译上面的文件如下:
g++-11 -std=c++20 -fmodules-ts -c -MMD partition.cpp
型这将生成一个文件partition.d,列出模块依赖项:
partition.d
partition.o gcm.cache/partition.gcm: partition.cpppartition.o gcm.cache/partition.gcm: partition:partition3.c++m \ partition:partition2.c++m partition:partition1.c++mpartition.c++m: gcm.cache/partition.gcm.PHONY: partition.c++mgcm.cache/partition.gcm:| partition.oCXX_IMPORTS += partition:partition3.c++m partition:partition2.c++m \ partition:partition1.c++m
partition.o gcm.cache/partition.gcm: partition.cpp
partition.o gcm.cache/partition.gcm: partition:partition3.c++m \
partition:partition2.c++m partition:partition1.c++m
partition.c++m: gcm.cache/partition.gcm
.PHONY: partition.c++m
gcm.cache/partition.gcm:| partition.o
CXX_IMPORTS += partition:partition3.c++m partition:partition2.c++m \
partition:partition1.c++m
型看起来很有希望,但还需要更多的研究。
我已经写了/正在写这样一个工具。它可以在github上找到:https://github.com/alexpanter/cpp_module_parser。它还未完成,但实际上正在工作。如果有兴趣,我将继续扩大它。我也有一个带有模块的小示例项目包,作为进一步研究的起点:
GCC在本地目录中查找预编译模块(BMI):./gcm.cache/usr/include/c++/11/iostream.gcm或(对于本地模块单元)./gcm.cache/,/my-module.gcm。如果用户代码导入了一个模块,那么预编译的模块单元 * 必须 * 已经存在于这个目录中,否则编译将失败。(至少目前)不可能指定另一个目录,或每个构建命令的自定义目录。这将是非常实用的,我希望GCC开发人员会在某个时候添加它。gcm.cache/目录被默认的模块Map器使用。可以创建自己的模块Map器,但从我所做的阅读来看,这听起来像是一个复杂的过程,因为模块Map器本质上是一个Web服务器:
./gcm.cache/usr/include/c++/11/iostream.gcm
./gcm.cache/,/my-module.gcm
gcm.cache/
与@Laserskjöld的答案相比,我认为收集预处理器输出也是一个可行的解决方案,因为模块导入/导出命令是由预处理器识别的。然而,我不认为这是一个 * 好 * 的解决方案,因为它比我写的工具慢得多。举个例子:
module;#include <iostream>export module mymodule;import myothermodule;export{ [...]}
module;
#include <iostream>
export module mymodule;
import myothermodule;
export
{
[...]
}
型经过预处理后,这个文件将有大约100000行,所有的行都需要由预处理器处理。但是使用我的工具(或者一个可能更有效的工具),只有前9行会被模块解析工具读取,文件的其余部分将被忽略。此外,使用模块的目的是减少对预处理器的依赖。
rqqzpn5f2#
GCC 14支持使用-fdeps-file=$depoutput -fdeps-format=p1689r5标志的P1689R5输出。示例:
-fdeps-file=$depoutput -fdeps-format=p1689r5
export module c;import b;export int c(){ return b();}
export module c;
import b;
export int c()
return b();
个字符将生成:
{"rules": [{"primary-output": "c.cxx.o","provides": [{"logical-name": "c","is-interface": true}],"requires": [{"logical-name": "b"}]}],"version": 0,"revision": 0}
"rules": [
"primary-output": "c.cxx.o",
"provides": [
"logical-name": "c",
"is-interface": true
],
"requires": [
"logical-name": "b"
]
"version": 0,
"revision": 0
型
eoxn13cs3#
我不知道gcc有什么方法可以做到这一点,但我建议编写一个帮助脚本,扩展文件并查找所有名为import的内容,然后您可能需要使用"和<对导入进行排序,并将它们作为头文件输出。然后你需要找到哪些文件导出了所选的模块,以匹配你的导入。也就是说,你需要遍历扩展的文件,并找到以export module开头的语句。您可以使用
import
"
<
export module
g++ -E {include flags, standard version etc} > tmpfile
字符串-E也可以和clang++一起工作,但是对于msvc,你需要/E如果有一种直接的方法可以用gcc来做这件事,我也很想知道,但问题随之而来:gcc如何知道在哪里寻找模块?相反,如果你有一个构建系统来跟踪每个模块的位置,你可以像编译命令一样指定它。(用clang你可以用-fmodule-file=指定它,我想这和gcc是一样的,但没有测试过)。至少我在my build system中是这样做的。但总结一下我对你问题的回答。我认为你需要:
-E
/E
-fmodule-file=
export import
3条答案
按热度按时间ulydmbyx1#
[修改]
看起来我们可以用标志
-MMD
调用gcc,它也跟踪模块依赖关系。给出我的一个示例项目,我像这样生成它:字符串
出于某种原因,我需要在编译主模块接口(上面显示的文件)之前编译模块分区,但也许这可以以某种方式绕过。我编译上面的文件如下:
型
这将生成一个文件
partition.d
,列出模块依赖项:型
看起来很有希望,但还需要更多的研究。
我自己的解决方案
我已经写了/正在写这样一个工具。它可以在github上找到:https://github.com/alexpanter/cpp_module_parser。
它还未完成,但实际上正在工作。如果有兴趣,我将继续扩大它。
我也有一个带有模块的小示例项目包,作为进一步研究的起点:
GCC
GCC在本地目录中查找预编译模块(BMI):
./gcm.cache/usr/include/c++/11/iostream.gcm
或(对于本地模块单元)./gcm.cache/,/my-module.gcm
。如果用户代码导入了一个模块,那么预编译的模块单元 * 必须 * 已经存在于这个目录中,否则编译将失败。(至少目前)不可能指定另一个目录,或每个构建命令的自定义目录。这将是非常实用的,我希望GCC开发人员会在某个时候添加它。
gcm.cache/
目录被默认的模块Map器使用。可以创建自己的模块Map器,但从我所做的阅读来看,这听起来像是一个复杂的过程,因为模块Map器本质上是一个Web服务器:对比
与@Laserskjöld的答案相比,我认为收集预处理器输出也是一个可行的解决方案,因为模块导入/导出命令是由预处理器识别的。然而,我不认为这是一个 * 好 * 的解决方案,因为它比我写的工具慢得多。举个例子:
型
经过预处理后,这个文件将有大约100000行,所有的行都需要由预处理器处理。但是使用我的工具(或者一个可能更有效的工具),只有前9行会被模块解析工具读取,文件的其余部分将被忽略。此外,使用模块的目的是减少对预处理器的依赖。
rqqzpn5f2#
GCC 14支持使用
-fdeps-file=$depoutput -fdeps-format=p1689r5
标志的P1689R5输出。示例:个字符
将生成:
型
eoxn13cs3#
我不知道gcc有什么方法可以做到这一点,但我建议编写一个帮助脚本,扩展文件并查找所有名为
import
的内容,然后您可能需要使用"
和<
对导入进行排序,并将它们作为头文件输出。然后你需要找到哪些文件导出了所选的模块,以匹配你的导入。也就是说,你需要遍历扩展的文件,并找到以
export module
开头的语句。您可以使用
字符串
-E
也可以和clang++一起工作,但是对于msvc,你需要/E
如果有一种直接的方法可以用gcc来做这件事,我也很想知道,但问题随之而来:gcc如何知道在哪里寻找模块?
相反,如果你有一个构建系统来跟踪每个模块的位置,你可以像编译命令一样指定它。(用clang你可以用
-fmodule-file=
指定它,我想这和gcc是一样的,但没有测试过)。至少我在my build system中是这样做的。但总结一下我对你问题的回答。我认为你需要:
import
、export import
和export module
的文件并处理它们。