用Doxygen和Graphviz给Contiki文档添加类图和调用图

来源:互联网 发布:阿依莲淘宝旗舰店 编辑:程序博客网 时间:2024/06/05 05:26

目录

      • 目录
      • 如何根据源码绘制数据结构
      • 安装Doxygen和Graphviz
      • 修改Doxygen配置文件并运行doxygen
      • 生成的各种图的效果
      • TODO

如何根据源码绘制数据结构?

在学习Contiki系统的过程中,阅读源码是搞清楚实现细节的最好方法。但直接阅读源码有时候也不是很容易的事情,即便有SourceInsight这样的源码阅读利器帮助,你还是时不时会希望能不能看到类的继承关系?能不能看到函数的调用关系?答案是肯定的,搜了一下网上开源的方案不少,例如在emacs中利用Graphviz绘制数据结构图的 、使用编译器特性生成CVG格式的数据结构图的、使用Python或者Java实现这一功能的,等等。但最方便,功能最强大的还是Doxygen+Graphviz。Contiki 是瑞典计算机科学学院的大牛Adam Dunkels 带领团队开发的适用于MCU构成的传感器网络节点的嵌入式操作系统。Contiki麻雀虽小,五脏俱全,集成了uIP协议栈,支持6LoWPAN,代表着传感器网络业界最新的发展方向。其文档也相当的完善,是使用Doxygen自动生成的,但默认没有打开绘制数据结构和调用图的功能,我们只需要将其打开即可,一行代码都不用写。

安装Doxygen和Graphviz

Doxygen和Graphviz都可以从前面给出的官方网站下载源码,Doxygen还可以从github获取。Ubuntu的各个版本都有集成,这里也不用专门定制,就用包管理器直接安装了:

# aptitude install graphviz doxygen

安装完后运行一下dot (graphviz默认用于有向图绘制的工具),确认graphviz能够正常工作:

# dot -V# dot - graphviz version 2.26.3 (20100126.1600)

修改Doxygen配置文件并运行doxygen

用Doxygen生成html文档非常的简单,只需要设置好配置文件,让Doxygen扫描源码目录,Doxygen便能根据配置生成需要的描述信息并进行组织,使得使用者可以按照软件开发者在代码中提供的注释信息和帮助文档按图索骥。这里我们不需要生成全新的配置文件并进行配置,contiki源码目录下的doc/Doxyfile就是contiki项目所使用的配置文件。我们只需要复制一份到工作目录(例如新建一个my_doc,避免污染源文档目录)并打开相应的选项。配置文件里#开头的为注释,中文为我自己添加的说明。配置选项非常的多,可以参考Doxygen文档config一节 的说明进行配置

# Doxyfile 1.4.1#---------------------------------------------------------------------------# Project related configuration options#---------------------------------------------------------------------------PROJECT_NAME           = "Contiki 2.6"PROJECT_NUMBER         = OUTPUT_DIRECTORY       = my_doc     #生成的html和latex文档及doxygen的日志会放到这个目录下CREATE_SUBDIRS         = NOOUTPUT_LANGUAGE        = EnglishUSE_WINDOWS_ENCODING   = YESBRIEF_MEMBER_DESC      = YESREPEAT_BRIEF           = YESABBREVIATE_BRIEF       = ALWAYS_DETAILED_SEC    = NOINLINE_INHERITED_MEMB  = NOFULL_PATH_NAMES        = YESSTRIP_FROM_PATH        = $(docroot)STRIP_FROM_INC_PATH    = $(docroot)SHORT_NAMES            = YESJAVADOC_AUTOBRIEF      = YESMULTILINE_CPP_IS_BRIEF = NODETAILS_AT_TOP         = YESINHERIT_DOCS           = YESDISTRIBUTE_GROUP_DOC   = NOTAB_SIZE               = 8ALIASES                = OPTIMIZE_OUTPUT_FOR_C  = YES    # Contiki主要是C代码,所以C-YES,Java-NOOPTIMIZE_OUTPUT_JAVA   = NOSUBGROUPING            = YES#---------------------------------------------------------------------------# Build related configuration options#---------------------------------------------------------------------------EXTRACT_ALL            = YES    # 这里我将全部的EXTRACT_XXX都打开了, 后面可以根据需要进行删减EXTRACT_PRIVATE        = YES    # 这几个选项控制要针对哪些符号生成文档,例如这里将类的私有属性和EXTRACT_STATIC         = YES    # 方法都提取出来EXTRACT_LOCAL_CLASSES  = YESEXTRACT_LOCAL_METHODS  = YESHIDE_UNDOC_MEMBERS     = NO     # 是否显示没有文档说明的成员和类?HIDE_UNDOC_CLASSES     = NOHIDE_FRIEND_COMPOUNDS  = YESHIDE_IN_BODY_DOCS      = NOINTERNAL_DOCS          = NOCASE_SENSE_NAMES       = YESHIDE_SCOPE_NAMES       = NOSHOW_INCLUDE_FILES     = YESINLINE_INFO            = YESSORT_MEMBER_DOCS       = YESSORT_BRIEF_DOCS        = NOSORT_BY_SCOPE_NAME     = NOGENERATE_TODOLIST      = YESGENERATE_TESTLIST      = YESGENERATE_BUGLIST       = NOGENERATE_DEPRECATEDLIST= NOENABLED_SECTIONS       = MAX_INITIALIZER_LINES  = 30SHOW_USED_FILES        = NOSHOW_DIRECTORIES       = YESFILE_VERSION_FILTER    = #---------------------------------------------------------------------------# configuration options related to warning and progress messages#---------------------------------------------------------------------------QUIET                  = NO     #这一段控制输出到doxygen.log文件中的信息WARNINGS               = YESWARN_IF_UNDOCUMENTED   = YESWARN_IF_DOC_ERROR      = YESWARN_NO_PARAMDOC       = YESWARN_FORMAT            = "$file:$line: $text"WARN_LOGFILE           = doxygen.log#---------------------------------------------------------------------------# configuration options related to the input files#---------------------------------------------------------------------------INPUT                  = $(docsrc)FILE_PATTERNS          = *.h *.c *.doc.html *.txtRECURSIVE              = YES    #这个选项很关键,需要打开才能对源码目录进行递归扫描,把所有的EXCLUDE                =        #源码都扫描到EXCLUDE_SYMLINKS       = YES                                    #下面一行指定了不扫描含有printf的文件,因为printf主要是用来输出                                #信息的,并不体现其所在函数的代码逻辑,在callgraph里出现反而会干                                #扰呈现主干的调用关系。EXCLUDE_PATTERNS       = *-printf.c printf.c EXAMPLE_PATH           = . ../examples/rime ../examples/multi-threadingEXAMPLE_PATTERNS       = EXAMPLE_RECURSIVE      = NOIMAGE_PATH             = picsINPUT_FILTER           = FILTER_PATTERNS        = FILTER_SOURCE_FILES    = NO#---------------------------------------------------------------------------# configuration options related to source browsing#---------------------------------------------------------------------------SOURCE_BROWSER         = YESINLINE_SOURCES         = NOSTRIP_CODE_COMMENTS    = NOREFERENCED_BY_RELATION = YESREFERENCES_RELATION    = YESVERBATIM_HEADERS       = YES#---------------------------------------------------------------------------# configuration options related to the alphabetical class index#---------------------------------------------------------------------------ALPHABETICAL_INDEX     = YESCOLS_IN_ALPHA_INDEX    = 5IGNORE_PREFIX          = #---------------------------------------------------------------------------# configuration options related to the HTML output#---------------------------------------------------------------------------GENERATE_HTML          = YES    #默认只生成HTML文档和LaTeX文档HTML_OUTPUT            = htmlHTML_FILE_EXTENSION    = .htmlHTML_HEADER            = HTML_FOOTER            = HTML_STYLESHEET        = HTML_ALIGN_MEMBERS     = YESGENERATE_HTMLHELP      = YESCHM_FILE               = HHC_LOCATION           = GENERATE_CHI           = YESBINARY_TOC             = YESTOC_EXPAND             = YESDISABLE_INDEX          = NOENUM_VALUES_PER_LINE   = 4GENERATE_TREEVIEW      = YESTREEVIEW_WIDTH         = 250#---------------------------------------------------------------------------# configuration options related to the LaTeX output#---------------------------------------------------------------------------GENERATE_LATEX         = $(doclatex)LATEX_OUTPUT           = latexLATEX_CMD_NAME         = latexMAKEINDEX_CMD_NAME     = makeindexCOMPACT_LATEX          = YESPAPER_TYPE             = a4wideEXTRA_PACKAGES         = LATEX_HEADER           = PDF_HYPERLINKS         = YESUSE_PDFLATEX           = YESLATEX_BATCHMODE        = NOLATEX_HIDE_INDICES     = NO#---------------------------------------------------------------------------# configuration options related to the RTF output#---------------------------------------------------------------------------GENERATE_RTF           = NORTF_OUTPUT             = rtfCOMPACT_RTF            = NORTF_HYPERLINKS         = NORTF_STYLESHEET_FILE    = RTF_EXTENSIONS_FILE    = #---------------------------------------------------------------------------# configuration options related to the man page output#---------------------------------------------------------------------------GENERATE_MAN           = NOMAN_OUTPUT             = manMAN_EXTENSION          = .3MAN_LINKS              = NO#---------------------------------------------------------------------------# configuration options related to the XML output#---------------------------------------------------------------------------GENERATE_XML           = NOXML_OUTPUT             = xmlXML_SCHEMA             = XML_DTD                = XML_PROGRAMLISTING     = YES#---------------------------------------------------------------------------# configuration options for the AutoGen Definitions output#---------------------------------------------------------------------------GENERATE_AUTOGEN_DEF   = NO#---------------------------------------------------------------------------# configuration options related to the Perl module output#---------------------------------------------------------------------------GENERATE_PERLMOD       = NOPERLMOD_LATEX          = NOPERLMOD_PRETTY         = YESPERLMOD_MAKEVAR_PREFIX = #---------------------------------------------------------------------------# Configuration options related to the preprocessor   #---------------------------------------------------------------------------ENABLE_PREPROCESSING   = YESMACRO_EXPANSION        = NOEXPAND_ONLY_PREDEF     = NOSEARCH_INCLUDES        = YESINCLUDE_PATH           = INCLUDE_FILE_PATTERNS  = PREDEFINED             = CC_FUNCTION_POINTER_ARGS \                         WITH_UIP6 UIP_CONF_IPV6 UIP_CONF_IPV6_RPL \                         WITH_LOADER_ARCH \                         DOXYGEN \                         "ASCCMD(name, flags, args)=void CMD_ASCII(name)"EXPAND_AS_DEFINED      = SKIP_FUNCTION_MACROS   = NO#---------------------------------------------------------------------------# Configuration::additions related to external references   #---------------------------------------------------------------------------TAGFILES               = "contiki_tags"GENERATE_TAGFILE       = ALLEXTERNALS           = NOEXTERNAL_GROUPS        = YESPERL_PATH              = /usr/bin/perl#---------------------------------------------------------------------------# Configuration options related to the dot tool   #---------------------------------------------------------------------------CLASS_DIAGRAMS         = YES    # 与 HAVE_DOT 互斥的HIDE_UNDOC_RELATIONS   = NOHAVE_DOT               = YESCLASS_GRAPH            = YESCOLLABORATION_GRAPH    = YESGROUP_GRAPHS           = YESUML_LOOK               = YESTEMPLATE_RELATIONS     = YESINCLUDE_GRAPH          = NOINCLUDED_BY_GRAPH      = NOCALL_GRAPH             = YESGRAPHICAL_HIERARCHY    = YESDIRECTORY_GRAPH        = YESDOT_IMAGE_FORMAT       = pngDOT_PATH               =/dotDOTFILE_DIRS           = ./dotMAX_DOT_GRAPH_WIDTH    = 1920MAX_DOT_GRAPH_HEIGHT   = 1080MAX_DOT_GRAPH_DEPTH    = 9DOT_TRANSPARENT        = YESDOT_MULTI_TARGETS      = YESGENERATE_LEGEND        = YESDOT_CLEANUP            = YES#这一段配置是我们要重点关注的内容。HAVE_DOT设置成YES,这样Doxygen就会调用dot程序来绘制callgraph。#这里把所有支持的图都选择上了,可以根据需要删减。DOT_PATH指定dot程序的位置,但这里出现了一个小BUG:#Doxygen在分析dot程序的绝对路径时会漏掉一个“/”把/usr/bin/dot变成/usr/bindot。这样一来到了使用dot#时就会报错,这里只好把dot放到项目目录里并把这个变量设成/dot。后面的MAX指定生成的各种图最大的分辨率#和调用层数,GENERATE_LEGEND选上可以方便随时查看图例(在每个graph下方都会有一个[legend]标签,打开#会显示图例)#---------------------------------------------------------------------------# Configuration::additions related to the search engine   #---------------------------------------------------------------------------SEARCHENGINE           = NO

配置完成后我们就进入contiki源码的根目录,运行doxygen进行扫描。执行的时候需要指定我们修改过的配置文件。

# doxygen my_doc/Doxyfile

由于打开了很多选项扫,描并生成整个contiki源码的文档还是比较耗时的。如果需要加速,可以添加一个配置项:

DOT_NUM_THREADS = 0

Doxygen会根据你的CPU核数并发地调用多个dot线程同时处理。

完成后,就可以进入/my_doc/html目录下查看整个项目源码的文档了,各种数据结构和调用关系的图都是链接到对应的类和函数中的,非常清晰。这里只把图片单独抠出来展示一下效果。

生成的各种图的效果

图例:
这里写图片描述


类图:
类图


协作图:
协作图


调用图
调用图


TODO

这里对Doxygen和Graphviz的使用还是很粗浅的,这两个工具的强大远远不止这些,下一步的工作就是控制Doxygen的扫描和对生成的dot代码进行修改,使得显示的结果更精确,只关注我们需要研究的部分,这样绘制出来的图才能更好地起到辅助理解程序逻辑的作用。

另外,由于是对代码的静态扫描分析,所以这里生成的调用图对于理解程序逻辑是有局限性的:它无法跟踪C语言中通过函数指针实现的动态绑定。这种调用关系只有依靠Profiling工具,例如内核中的oprofile才能捕捉到,之后再送至dot处理绘制callgraph。

0 0
原创粉丝点击