从一个巨大的 CPP 项目的依赖图中提取一个自治块?

Extract an autonomous chunk of the dependency graph of a huge CPP project?

考虑 Chromium 代码库。如果我没记错的话,它很大,大约 4gb 的纯代码。但是无论它多么庞大,它在本质上仍然是模块化的。它在内部实现了很多有趣的功能。

我的意思是,例如,我想从源代码中提取 websocket 实现,但手工操作并不容易。好的,如果我们转到 https://github.com/chromium/chromium/tree/main/net/websockets,我们会看到很多头文件。要将代码编译为“库”,我们需要它们 + 它们在 .cpp 文件中的实现。但诀窍是这些头文件 include 其他头文件在 chromium 项目的其他目录中。轮到他们 include 其他人...

但是 如果没有循环依赖,我们应该能够到达这棵树的根,头文件不会 include 任何东西(或将include 已编译的库),这应该意味着此依赖子树所需的所有文件都已就位,因此我们可以将原始代码库的一部分与其余部分分开编译。

就是这个主意。至少理论上是这样。

有人知道怎么做吗?我找到了 this repo and this repo,但它们只显示依赖关系图,没有从中提取树的功能。

我想应该已经有一个工具了。 google 很难说出来。或许我弄错了,这种方法实际上行不通?

您的编译器几乎肯定能够提取此依赖信息,以便它可用于帮助构建系统确定增量构建。例如,在 gcc 中,我们有 -MMD 标志。

假设我们有四个编译单元,ball.cppfootball.cppbasketball.cpphockey.cpp。每个源文件都包含一个同名的头文件。此外,football.hppbasketball.hpp 每个都包含 ball.hpp.

如果我们运行

g++ -MMD   -c -o football.o football.cpp
g++ -MMD   -c -o basketball.o basketball.cpp
g++ -MMD   -c -o hockey.o hockey.cpp
g++ -MMD   -c -o ball.o ball.cpp

然后这将产生,除了目标文件之外,一些名称如 basketball.d 的文件包含依赖信息如

basketball.o: basketball.cpp basketball.h ball.h

将它们读入 python 脚本很简单,然后只需合并要包含的文件的所有依赖项即可。


编辑:事实上,python 甚至可能有点矫枉过正。在上面的情况下,如果你想获得任何包含单词“ball”的所有依赖项,你可以这样做

$ cat *.d | awk -F: ' ~ "ball" { print  }' | xargs -n 1 echo | sort | uniq

这将输出

ball.cpp
ball.h
basketball.cpp
basketball.h
football.cpp
football.h

如果您不习惯阅读 UNIX 管道,这:

  • 连接当前目录中的所有 *.d 文件;
  • 遍历它们 line-by-line,将每行拆分为由 : 个字符分隔的字段;
  • 为第一个字段(即目标)与正则表达式“ball”匹配的任何行打印出第二个字段(即依赖项列表);
  • 将结果分成单独的行;
  • 对结果行进行排序;和
  • 丢弃任何重复项。

您可以看到,这生成了 ball-related 文件所依赖的所有内容的列表,但跳过了 hockey.cpphockey.hpp,它们不是任何具有“ball”的文件的依赖项以它的名字。 (当然,在你的情况下,你可能会使用“websockets”而不是“ball”,如果有一些目录结构而不是根目录中的所有内容,你可能需要做一些补偿。)