大家都知道, Doxygen 可以用于提取代码的注释生成项目的文档,只要注释满足其规定的格式。但我更喜欢利用它生成类继承图(inheritance diagram)和函数调用图(callgraph),通过他们能够加快对代码的理解。
以 MySQL 代码为例, Doxygen 生成的类继承图和调用图分别是这样的:


之前工作中交接了几个 C++ 项目,由于还不熟悉,就想用 Doxygen 来生成这两种图来加快熟悉代码,但结果却生成失败了。
几经排查,最后发现只要代码中包含2个以上的 using namespace xxx;
语句,调用图就无法生成。比如下面这样一个简单的类实现,就无法生成调用关系图。
#pragma once
namespace demo {
class Test {
public:
void foo();
void bar();
};
}
#include <iostream>
#include "test.h"
using namespace demo;
using namespace std;
void Test::foo()
{
bar();
}
void Test::bar()
{
return;
}
int main()
{
Test test;
test.foo();
return 0;
}
虽然这种直接包含命名空间的用法不推荐,但是在已有项目中却很常见,这就意味着 Doxygen 基本不可用了。
由于当时没有时间,就先给官方报了一个 Issue ,等待他们解决。
没想到几个月之后,官方也还没有解决,而最近正好有点时间,就重新去分析这个 bug ,看如何解决。解决过程虽然花了不少时间,但总结起来就几点:
-
对比正常生成调用图和无法生成调用图的两种输出,再 grep 差异信息定位到生成 callgraph 图的相关代码;
-
添加 printf 调试信息,找出 callgraph 元数据的来源,即 Doxygen 怎么得到调用关系的,最终找到实现在
code.l
(C族语言的 flex 实现,用于解析工程源码)中,其中基于 flex 自己实现了词法解析; -
学习 flex 的使用方法;
最后终于找到问题的根源在于, Doxygen 在解析 using namespace xxx;
指令的时候,错误地把文件中其后的代码包围在 xxx 命名空间中( pushScope
),从而把函数的绝对命名空间弄错,就没法解析出正确的调用关系了。
提了 PR 修复了之后, Doxygen 就能够正常地生成调用图了,前面的测试代码就能正确地生成如下的函数调用图了。

目前(2021.02)这个 PR 已经合并到 master 了,但是还没有发布,需要再等一等。