分类: C/C++
2008-01-27 19:36:13
c/c++支持独立编译,其源代码有多个头文件(.h)和执行文件(.c或.cpp)组成。在查看这样的源代码时,搞清楚所有这些文件之间的依赖或使用关系,就能系统地,全面地了解整个系统的层次结构。根据大多编码的习惯,有下面的事实:
1.每一个头文件往往对应一个同名执行文件(文件扩展名不同)。比如,在c++中,往往在"filename.h"中声明一个或多个类;在"filename.cpp"定义这个类的所有函数。这样的组合一般习惯上构成一个“模块”。
2.模块的实现文件包含(#include语句)模块的使用文件.
3.一个模块如果要调用其他模块,需要直接或间接包含被调用模块的头文件.
基于上面的情况,可以考虑:利用源代码中的#include语句,可以找出所有模块的直接依赖关系。利用这些依赖关系,结合Graphviz就可以生成一个简略的模块结构图。本文章以hp snmp ++的源代码为例,进行一次尝试.
OS: debian linux , 2.6.21-2
SHELL : bash
使用到的工具:grep, awk, graphviz, sort
1. 下载源代码并解压缩
wget
tar -xzvf snmp++v3.2.23.tar.gz
2. 在src子目录下,搜索所有的cpp文件,得到'#include "'语句,保存到临时文件
cd snmp++/src
grep "^\#include \+\"" *.cpp >/tmp/xx.dep
注意:不要以'<'号括起来的系统的库文件
3. 在include子目录下,搜索所有的h文件,得到'#include "'语句,保存到临时文件
cd ../include/snmp_pp
grep "^\#include \+\"" *.h >>/tmp/xx.dep
4. 查d 看临时文件中的内容
cd /tmp
emacs -nw xx.dep
5. 精简临时文件中的内容
#去掉':#include',去掉引号
sed s/\:\#include// xx.dep | sed s/\"//g >xx2.dep
#去掉文件的路径和扩展名
sed s/snmp_pp\\/// xx2.dep | sed s/\\.h//g | sed s/\\.cpp//g >xx3.dep
现在生成的文件,每一行第一列为调用者,第二列为使用者
image file xx_2.gif
6. 生成Graphivz的源代码
echo "digraph snmp_pp_struct {" > xx.dot
awk '{ print $1 " -> " $2 ";" }' xx3.dep | sort -u >>xx.dot
echo "}" >>xx.dot
注意 sort -u 可以去掉重复的依赖关系
7. 使用Graphivz生成图形
编辑xx.dot, 补充一下绘制属性
graph [fontsize = 6,
label = "by cuichaox@gmail.com"]
node [ shape = box,
style = filled,
color = lightblue ];
生成图形
dot -Tgif xx.dot -o test.gif
见文档最后的图形.
试验情况不是太理想,生成的线太多,图形太复杂
(1)文件见的包含关系,有许多互相包含的情况.
(2)间接包含加上直接包含,有重复包含的情况.
(1)如果要让图形更好,需要手工编辑xx.dot文件,太麻烦。
(2)编写一个脚本或程序,使用更智能的源文件分析(不只使用include语句,而是分析到函数或类的定义和实现)。自动完成源代码的分析,和graphivz源代码策生成。有希望取得成功。