学习用 doxygen 生成源码.docx
《学习用 doxygen 生成源码.docx》由会员分享,可在线阅读,更多相关《学习用 doxygen 生成源码.docx(15页珍藏版)》请在冰豆网上搜索。
![学习用 doxygen 生成源码.docx](https://file1.bdocx.com/fileroot1/2022-12/12/8849fa1a-0e76-4652-a731-452eeb5893bc/8849fa1a-0e76-4652-a731-452eeb5893bc1.gif)
学习用doxygen生成源码
学习用doxygen生成源码文档
ArpanSen,资深工程师,StudioBProductions
简介:
维护用 C/C++ 开发的遗留系统并添加新特性是一项艰难的任务。
幸运的是,doxygen可以帮助您完成这个任务。
doxygen是一种用于 C/C++、Java™、Python和其他编程语言的文档系统。
本文在 C/C++ 项目的上下文中讨论doxygen的特性,以及如何用doxygen定义的标记生成代码文档。
标记本文!
发布日期:
2008年10月13日
级别:
中级
其他语言版本:
英文
访问情况 2985次浏览
建议:
0 (添加评论)
平均分(共1个评分)
维护用 C/C++ 开发的遗留系统并添加新特性是一项艰难的任务。
这涉及几方面的问题:
理解现有的类层次结构和全局变量,不同的用户定义类型,以及函数调用图分析等等。
本文在 C/C++ 项目的上下文中通过示例讨论doxygen的几个特性。
但是,doxygen非常灵活,也可用于用Python、Java、PHP和其他语言开发的软件项目。
本文的主要目的是帮助您从 C/C++ 源代码提取出信息,但也简要描述了如何用doxygen定义的标记生成代码文档。
安装doxygen
有两种获得doxygen的方法。
可以下载预编译的可执行文件,也可以从SVN存储库下载源代码并自己编译。
清单1 演示的是后一种方法。
清单1.安装和构建doxygen源代码
bash-2.05$svncodoxygen-svn
bash-2.05$cddoxygen-svn
bash-2.05$./configure–prefix=/home/user1/bin
bash-2.05$make
bash-2.05$makeinstall
注意,配置脚本把编译的源代码存储在/home/user1/bin中(进行编译后,会在PATH变量中添加这个目录),因为并非每个UNIX®用户都有写/usr文件夹的权限。
另外,需要用 svn 实用程序下载源代码。
回页首
使用doxygen生成文档
使用doxygen生成源代码的文档需要执行三个步骤。
生成配置文件
在shell提示上,输入命令 doxygen-g 。
这个命令在当前目录中生成一个可编辑的配置文件 Doxyfile。
可以改变这个文件名,在这种情况下,应该调用 doxygen-g,见 清单2。
清单2.生成默认的配置文件
bash-2.05b$doxygen-g
Configurationfile'Doxyfile'created.
Nowedittheconfigurationfileandenter
doxygenDoxyfile
togeneratethedocumentationforyourproject
bash-2.05b$lsDoxyfile
Doxyfile
编辑配置文件
配置文件采用 = 这样的结构,与Make文件格式相似。
下面是最重要的标记:
∙:
必须在这里提供一个目录名,例如/home/user1/documentation,这个目录是放置生成的文档文件的位置。
如果提供一个不存在的目录名,doxygen会以这个名称创建具有适当用户权限的目录。
∙:
这个标记创建一个以空格分隔的所有目录的列表,这个列表包含需要生成文档的 C/C++ 源代码文件和头文件。
例如,请考虑以下代码片段:
INPUT=/home/user1/project/kernel/home/user1/project/memory
在这里,doxygen会从这两个目录读取 C/C++ 源代码。
如果项目只有一个源代码根目录,其中有多个子目录,那么只需指定根目录并把 标记设置为 Yes。
∙:
在默认情况下,doxygen会搜索具有典型 C/C++ 扩展名的文件,比如 .c、.cc、.cpp、.h 和 .hpp。
如果 标记没有相关联的值,doxygen就会这样做。
如果源代码文件采用不同的命名约定,就应该相应地更新这个标记。
例如,如果项目使用 .c86 作为 C 文件扩展名,就应该在 标记中添加这个扩展名。
∙:
如果源代码层次结构是嵌套的,而且需要为所有层次上的 C/C++ 文件生成文档,就把这个标记设置为Yes。
例如,请考虑源代码根目录层次结构/home/user1/project/kernel,其中有/home/user1/project/kernel/vmm和/home/user1/project/kernel/asm等子目录。
如果这个标记设置为 Yes,doxygen就会递归地搜索整个层次结构并提取信息。
∙:
这个标记告诉doxygen,即使各个类或函数没有文档,也要提取信息。
必须把这个标记设置为 Yes。
∙:
把这个标记设置为 Yes。
否则,文档不包含类的私有数据成员。
∙:
把这个标记设置为 Yes。
否则,文档不包含文件的静态成员(函数和变量)。
清单3 给出一个Doxyfile示例。
清单3.包含用户提供的标记值的doxyfile示例
OUTPUT_DIRECTORY=/home/user1/docs
EXTRACT_ALL=yes
EXTRACT_PRIVATE=yes
EXTRACT_STATIC=yes
INPUT=/home/user1/project/kernel
#Donotaddanythinghereunlessyouneedto.Doxygenalreadycoversall
#commonformatslike.c/.cc/.cxx/.c++/.cpp/.inl/.h/.hpp
FILE_PATTERNS=
RECURSIVE=yes
运行doxygen
在shell提示下输入 doxygenDoxyfile(或者已为配置文件选择的其他文件名)运行doxygen。
在最终生成HypertextMarkupLanguage(HTML)和Latex格式(默认)的文档之前,doxygen会显示几个消息。
在生成文档期间,在 标记指定的文件夹中,会创建两个子文件夹 html 和 latex。
清单4 是一个doxygen运行日志示例。
清单4.doxygen的日志输出
Searchingforincludefiles...
Searchingforexamplefiles...
Searchingforimages...
Searchingfordotfiles...
Searchingforfilestoexclude
Readinginputfiles...
Readingandparsingtagfiles
Preprocessing/home/user1/project/kernel/kernel.h
…
Read12489207bytes
Parsinginput...
Parsingfile/project/user1/project/kernel/epico.cxx
…
Freeinginput...
Buildinggrouplist...
..
GeneratingdocsforcompoundMemoryManager:
:
ProcessSpec
…
Generatingdocsfornamespacestd
Generatinggroupindex...
Generatingexampleindex...
Generatingfilememberindex...
Generatingnamespacememberindex...
Generatingpageindex...
Generatinggraphinfopage...
Generatingsearchindex...
Generatingstylesheet...
回页首
文档输出格式
除了HTML之外,doxygen还可以生成几种输出格式的文档。
可以让doxygen生成以下格式的文档:
∙UNIX手册页:
把 标记设置为 Yes。
在默认情况下,会在 指定的目录中创建 man 子文件夹,生成的文档放在这个文件夹中。
必须把这个文件夹添加到MANPATH环境变量中。
∙RichTextFormat(RTF):
把 标记设置为 Yes。
把 标记设置为希望放置.rtf文件的目录;在默认情况下,文档放在OUTPUT_DIRECTORY中的 rtf 子文件夹中。
要想支持跨文档浏览,应该把 标记设置为 Yes。
如果设置这个标记,生成的.rtf文件会包含跨文档链接。
∙Latex:
在默认情况下,doxygen生成Latex和HTML格式的文档。
在默认的Doxyfile中, 标记设置为 Yes。
另外, 标记设置为Latex,这意味着会在OUTPUT_DIRECTORY中创建 latex 子文件夹并在其中生成Latex文件。
∙Microsoft®CompiledHTMLHelp(CHM)格式:
把 标记设置为 Yes。
因为在UNIX平台上不支持这种格式,doxygen只在保存HTML文件的文件夹中生成一个 index.hhp 文件。
您必须通过HTML帮助编译器把这个文件转换为.chm文件。
∙ExtensibleMarkupLanguage(XML)格式:
把 标记设置为 Yes。
(注意,doxygen开发团队还在开发XML输出)。
清单5 提供的Doxyfile示例让doxygen生成所有格式的文档。
清单5.生成多种格式的文档的Doxyfile
#forHTML
GENERATE_HTML=YES
HTML_FILE_EXTENSION=.htm
#forCHMfiles
GENERATE_HTMLHELP=YES
#forLatexoutput
GENERATE_LATEX=YES
LATEX_OUTPUT=latex
#forRTF
GENERATE_RTF=YES
RTF_OUTPUT=rtf
RTF_HYPERLINKS=YES
#forMANpages
GENERATE_MAN=YES
MAN_OUTPUT=man
#forXML
GENERATE_XML=YES
回页首
doxygen中的特殊标记
doxygen包含几个特殊标记。
C/C++代码的预处理
为了提取信息,doxygen必须对 C/C++ 代码进行预处理。
但是,在默认情况下,它只进行部分预处理——计算条件编译语句(#if…#endif),但是不执行宏展开。
请考虑 清单6 中的代码。
清单6.使用宏的C++代码示例
#include
#include
#defineUSE_ROPE
#ifdefUSE_ROPE
#defineSTRINGstd:
:
rope
#else
#defineSTRINGstd:
:
string
#endif
staticSTRINGname;
通过源代码中定义的 ,doxygen生成的文档如下:
Defines
#defineUSE_ROPE
#defineSTRINGstd:
:
rope
Variables
staticSTRINGname
在这里可以看到doxygen执行了条件编译,但是没有对 STRING 执行宏展开。
Doxyfile中的 标记在默认情况下设置为 Yes。
为了执行宏展开,还应该把 标记设置为 Yes。
这会使doxygen产生以下输出:
Defines
#defineUSE_ROPE
#defineSTRINGstd:
:
string
Variables
staticstd:
:
ropename
如果把 标记设置为 No,前面源代码的doxygen输出就是:
Variables
staticSTRINGname
注意,文档现在没有定义,而且不可能推导出 STRING 的类型。
因此,总是应该把 标记设置为Yes。
在文档中,可能希望只展开特定的宏。
为此,除了把 和 标记设置为 Yes之外,还必须把 标记设置为 Yes(这个标记在默认情况下设置为 No),并在 或 标记中提供宏的细节。
请考虑 清单7 中的代码,这里只希望展开宏 CONTAINER。
清单7.包含多个宏的C++源代码
#ifdefUSE_ROPE
#defineSTRINGstd:
:
rope
#else
#defineSTRINGstd:
:
string
#endif
#ifALLOW_RANDOM_ACCESS==1
#defineCONTAINERstd:
:
vector
#else
#defineCONTAINERstd:
:
list
#endif
staticSTRINGname;
staticCONTAINERgList;
清单8 给出配置文件。
清单8.允许有选择地展开宏的Doxyfile
ENABLE_PREPROCESSING=YES
MACRO_EXPANSION=YES
EXPAND_ONLY_PREDEF=YES
EXPAND_AS_DEFINED=CONTAINER
…
下面的doxygen输出只展开了 CONTAINER:
Defines
#defineSTRINGstd:
:
string
#defineCONTAINERstd:
:
list
Variables
staticSTRINGname
staticstd:
:
listgList
注意,只有 CONTAINER 宏被展开了。
在 和 都设置为 Yes 的情况下, 标记只选择展开等号操作符右边列出的宏。
对于预处理过程,要注意的最后一个标记是 。
就像用 -D 开关向C++编译器传递预处理器定义一样,使用这个标记定义宏。
请考虑 清单9 中的Doxyfile。
清单9.定义了宏展开标记的Doxyfile
ENABLE_PREPROCESSING=YES
MACRO_EXPANSION=YES
EXPAND_ONLY_PREDEF=YES
EXPAND_AS_DEFINED=
PREDEFINED=USE_ROPE=\
ALLOW_RANDOM_ACCESS=1
下面是doxygen生成的输出:
Defines
#defineUSE_CROPE
#defineSTRINGstd:
:
rope
#defineCONTAINERstd:
:
vector
Variables
staticstd:
:
ropename
staticstd:
:
vectorgList
在使用 标记时,宏应该定义为 = 形式。
如果不提供值,比如简单的 #define,那么只使用 = 即可。
多个宏定义以空格或反斜杠(\)分隔。
从文档生成过程中排除特定文件或目录
在Doxyfile中的 标记中,添加不应该为其生成文档的文件或目录(以空格分隔)。
因此,如果提供了源代码层次结构的根,并要跳过某些子目录,这将非常有用。
例如,如果层次结构的根是src_root,希望在文档生成过程中跳过examples/和test/memoryleaks文件夹,Doxyfile应该像 清单10 这样。
清单10.使用EXCLUDE标记的Doxyfile
INPUT=/home/user1/src_root
EXCLUDE=/home/user1/src_root/examples/home/user1/src_root/test/memoryleaks
…
回页首
生成图形和图表
在默认情况下,Doxyfile把 标记设置为 Yes。
这个标记用来生成类层次结构图。
要想生成更好的视图,可以从 Graphviz下载站点 下载dot工具。
Doxyfile中的以下标记用来生成图表:
∙:
在Doxyfile中这个标记默认设置为 Yes。
如果这个标记设置为 No,就不生成继承层次结构图。
∙:
如果这个标记设置为 Yes,doxygen就使用dot工具生成更强大的图形,比如帮助理解类成员及其数据结构的协作图。
注意,如果这个标记设置为 Yes, 标记就无效了。
∙:
如果 标记和这个标记同时设置为 Yes,就使用 dot 生成继承层次结构图,而且其外观比只使用 时更丰富。
∙:
如果 标记和这个标记同时设置为 Yes,doxygen会生成协作图(还有继承图),显示各个类成员(即包含)及其继承层次结构。
清单11 提供一个使用一些数据结构的示例。
注意,在配置文件中 、 和 标记都设置为 Yes。
清单11.C++类和结构示例
structD{
intd;
};
classA{
inta;
};
classB:
publicA{
intb;
};
classC:
publicB{
intc;
Dd;
};
图1 给出doxygen的输出。
图1.使用dot工具生成的类继承图和协作图
回页首
代码文档样式
到目前为止,我们都是使用doxygen从原本没有文档的代码中提取信息。
但是,doxygen也鼓励使用文档样式和语法,这有助于生成更详细的文档。
本节讨论doxygen鼓励在 C/C++ 代码中使用的一些常用标记。
更多信息参见 参考资料。
每个代码元素有两种描述:
简短的和详细的。
简短描述通常是单行的。
函数和类方法还有第三种描述体内描述(in-bodydescription),这种描述把在函数体中找到的所有注释块集中在一起。
比较常用的一些doxygen标记和注释样式如下:
∙简短描述:
使用单行的 C++ 注释,或使用 <\brief> 标记。
∙详细描述:
使用JavaDoc式的注释 /**…test…*/(注意开头的两个星号[*])或Qt式的注释 /*!
…text…*/。
∙体内描述:
类、结构、联合体和名称空间等 C++ 元素都有自己的标记,比如 <\class>、<\struct>、<\union> 和<\namespace>。
为了为全局函数、变量和枚举类型生成文档,必须先对对应的文件使用 <\file> 标记。
清单12 给出的示例包含用于四种元素的标记:
函数标记(<\fn>)、函数参数标记(<\param>)、变量名标记(<\var>)、用于 #define 的标记(<\def>)以及用来表示与一个代码片段相关的问题的标记(<\warning>)。
清单12.典型的doxygen标记及其使用方法
/*!
\fileglobaldecls.h
\briefPlacetolookforglobalvariables,enums,functions
andmacrodefinitions
*/
/**\varconstintfileSize
\briefDefaultsizeofthefileondisk
*/
constintfileSize=1048576;
/**\defSHIFT(value,length)
\briefLeftshiftvaluebylengthinbits
*/
#defineSHIFT(value,length)((value)<<(length))
/**\fnboolcheck_for_io_errors(FILE*fp)
\briefChecksifafileiscorruptedornot
\paramfpPointertoanalreadyopenedfile
\warningNotthreadsafe!
*/
boolcheck_for_io_errors(FILE*fp);
下面是生成的文档:
Defines
#defineSHIFT(value,length)((value)<<(l