有没有办法用 gcc 查询直接模块依赖关系?
Is there a way to query direct module dependencies with gcc?
给定一个模块
// a-m.cc
export module A;
import B;
import C;
import "D.h";
...
有没有一种调用 gcc 的方法(类似于 -M 对 headers 的作用),它将列出对其他模块的直接依赖关系并导入 headers(即 B、C 和“ D.h")?
我不知道 gcc 有什么方法可以做到这一点,但我建议编写一个辅助脚本来扩展文件并查找名为 import
的所有内容,然后您可能需要使用 [= 对导入进行排序12=] 和 <
并将它们输出为 headers.
然后您需要找到导出所选模块的文件以与您的导入相匹配。也就是说,您需要遍历扩展文件并找到以 export module
.
开头的语句
您使用
展开文件
g++ -E {include flags, standard version etc} > tmpfile
-E
也适用于 clang++,但对于 msvc,您需要 /E
如果有直接的方法可以用 gcc 做到这一点,我也很想知道,但随之而来的问题是:gcc 如何知道在哪里寻找模块?
相反,如果您有一个跟踪每个模块所在位置的构建系统,您可以将其指定为编译命令。 (使用 clang,您可以使用 -fmodule-file=
指定它,我认为它与 gcc 相同,但尚未测试)。至少那是我在 my build system.
中所做的
但总结一下我对你问题的回答。
我认为您需要:
- 扩展您的源文件
- 找到所有包含
import
、export import
和 export module
的文件并处理它们。
[编辑]
看来我们可以使用标志 -MMD
调用 gcc,它也可以跟踪模块依赖性。鉴于我有一个示例项目,我生成它是这样的:
// 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.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.
它尚未完成,但实际上正在运行。如果有兴趣,我会继续扩展。
我还有一堆带有模块的小型示例项目,旨在作为进一步研究的起点:https://github.com/alexpanter/modules_testing
海湾合作委员会
GCC 在本地目录中查找预编译模块 (BMI):./gcm.cache/usr/include/c++/11/iostream.gcm
或(对于本地模块单元)./gcm.cache/,/my-module.gcm
.
如果用户代码导入模块,预编译模块单元必须已经存在于该目录中,否则编译将失败。
不幸的是(至少目前)不可能为每个构建命令指定另一个目录或自定义目录。这将非常实用,我希望 GCC 开发人员会在某个时候添加它。 gcm.cache/
目录由默认模块映射器使用。可以创建自己的模块映射器,但从我读到的内容来看,这听起来像是一个复杂的过程,因为模块映射器本质上是一个 Web 服务器:
- https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Module-Mapper.html
- http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1184r2.pdf
比较
与@Laserskjöld 的回答相比,我认为收集预处理器输出也是一个可行的解决方案,因为预处理器可以识别模块 import/export 命令。但是,我不认为这是一个 好的 解决方案,因为它比我编写的工具慢得多。一个例子:
module;
#include <iostream>
export module mymodule;
import myothermodule;
export
{
[...]
}
预处理后,此文件将有 ~100000 行长,所有行都需要由预处理程序处理。但是使用我的工具(或可能更有效的工具),模块解析工具只会读取前 9 行,文件的其余部分将被忽略。
此外,拥有模块的目的是减少对预处理器的依赖。
给定一个模块
// a-m.cc
export module A;
import B;
import C;
import "D.h";
...
有没有一种调用 gcc 的方法(类似于 -M 对 headers 的作用),它将列出对其他模块的直接依赖关系并导入 headers(即 B、C 和“ D.h")?
我不知道 gcc 有什么方法可以做到这一点,但我建议编写一个辅助脚本来扩展文件并查找名为 import
的所有内容,然后您可能需要使用 [= 对导入进行排序12=] 和 <
并将它们输出为 headers.
然后您需要找到导出所选模块的文件以与您的导入相匹配。也就是说,您需要遍历扩展文件并找到以 export module
.
您使用
展开文件g++ -E {include flags, standard version etc} > tmpfile
-E
也适用于 clang++,但对于 msvc,您需要 /E
如果有直接的方法可以用 gcc 做到这一点,我也很想知道,但随之而来的问题是:gcc 如何知道在哪里寻找模块?
相反,如果您有一个跟踪每个模块所在位置的构建系统,您可以将其指定为编译命令。 (使用 clang,您可以使用 -fmodule-file=
指定它,我认为它与 gcc 相同,但尚未测试)。至少那是我在 my build system.
但总结一下我对你问题的回答。 我认为您需要:
- 扩展您的源文件
- 找到所有包含
import
、export import
和export module
的文件并处理它们。
[编辑]
看来我们可以使用标志 -MMD
调用 gcc,它也可以跟踪模块依赖性。鉴于我有一个示例项目,我生成它是这样的:
// 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.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.
它尚未完成,但实际上正在运行。如果有兴趣,我会继续扩展。
我还有一堆带有模块的小型示例项目,旨在作为进一步研究的起点:https://github.com/alexpanter/modules_testing
海湾合作委员会
GCC 在本地目录中查找预编译模块 (BMI):./gcm.cache/usr/include/c++/11/iostream.gcm
或(对于本地模块单元)./gcm.cache/,/my-module.gcm
.
如果用户代码导入模块,预编译模块单元必须已经存在于该目录中,否则编译将失败。
不幸的是(至少目前)不可能为每个构建命令指定另一个目录或自定义目录。这将非常实用,我希望 GCC 开发人员会在某个时候添加它。 gcm.cache/
目录由默认模块映射器使用。可以创建自己的模块映射器,但从我读到的内容来看,这听起来像是一个复杂的过程,因为模块映射器本质上是一个 Web 服务器:
- https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Module-Mapper.html
- http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1184r2.pdf
比较
与@Laserskjöld 的回答相比,我认为收集预处理器输出也是一个可行的解决方案,因为预处理器可以识别模块 import/export 命令。但是,我不认为这是一个 好的 解决方案,因为它比我编写的工具慢得多。一个例子:
module;
#include <iostream>
export module mymodule;
import myothermodule;
export
{
[...]
}
预处理后,此文件将有 ~100000 行长,所有行都需要由预处理程序处理。但是使用我的工具(或可能更有效的工具),模块解析工具只会读取前 9 行,文件的其余部分将被忽略。 此外,拥有模块的目的是减少对预处理器的依赖。