doxygen 的配置文件是一个纯文本文件. 虽然用 Windows 自带的记事本就可以编辑, 但是为了更好的体验, 以下使用 Notepad++ 编辑配置文件.
我们已经知道, 命令 doxygen -g
生成模板配置文件, 参数中没有指定文件名, 所以使用了默认的文件名 Doxyfile
. 右键, 选择用 Notepad++ 打开这个模板配置文件.
打开之后会看到许多类似下面这样的英文:
其中以 #
开头的一行是配置文件的注释, 会被 doxygen 忽略, 而类似 TAG_NAME = xxx
的语句, 则是我们要关心的设置. 等号的左侧是个 tag, 即标签, 而等号的右侧, 是该 tag 的值(value). 这里的注释告诉我们, 这个 name 会被用在大多数页面的标题中, 默认值是 "My Project"
. 我们试着修改这个默认值
PROJECT_NAME = "Hello Project"
然后run doxygen Doxyfile
重新生成文档, 看看网页发生了什么变化
我们发现, 网页左上角的标题变成了我们刚刚修改的文本.
接下来找到另外两个 tag 并修改为以下值.
PROJECT_NUMBER = v1.0
PROJECT_BRIEF = "say hello to doxygen"
重新生成文档, 刷新网页.
可以看到, 在标题的周围, 多了版本号和简介.
可以推测, 其他的 tag 也是一样的套路. 我们通过这种方式, 告诉 doxygen 我们想要输出怎样的文档.
在继续之前, 我们先看看官方手册对配置文件的准确规定吧. 以下内容摘自 Reference Manual - Configuration 一节.
A configuration file is a free-form ASCII text file with a structure that is similar to that of a Makefile, with the default name Doxyfile. It is parsed by doxygen. The file may contain tabs and newlines for formatting purposes. The statements in the file are case-sensitive. Comments may be placed anywhere within the file (except within quotes).
…
Comments begin with the hash character (#) and ends at the end of the line.
The file essentially consists of a list of assignment statements. Each statement consists of a TAG_NAME written in capitals, followed by the equal sign (=) and one or more values. If the same tag is assigned more than once, the last assignment overwrites any earlier assignment. For tags that take a list as their argument, the += operator can be used instead of = to append new values to the list. Values are sequences of non-blanks. If the value should contain one or more blanks it must be surrounded by quotes ("…"). Multiple lines can be concatenated by inserting a backslash () as the last character of a line. Environment variables can be expanded using the pattern $(ENV_VARIABLE_NAME).
什么是 “free-form ASCII text file” 我也不理解, 不过从其余的叙述中, 我们可以得到以下信息:
#
开头, 在行末结束.+=
而不是 =
来添加新值.\
结尾.官方手册里可以找到所有 tag 的介绍, 而且还提供了索引以便查找. 下面介绍一些常用的 tag, 权当抛砖引玉, 以加深初学者对于配置文件功能的认知.
顾名思义, 该 tag 指定文档的输出目录. 如果是相对路径, 则相对于 doxygen 启动的目录(即工作目录). 如果留空, 则使用对当前目录.
在前面的教程中, 我们创建了一个项目 hello_doxygen
, 生成文档后的目录结构是这样的:
|--hello_doxygen\
|--html\
|--latex\
|--Doxyfile
|--hello.c
可以看到, 其中 html\
和 latex\
是生成的文档, 但是直接输出到了项目目录下. 对于有洁癖的程序猿来说, 通常会期望把文档的输出放到一个专门的文件夹中, 例如 doxygen_output
.
先给 tag 赋值 OUTPUT_DIRECTORY = doxygen_output
, 然后 run doxygen, 输出文档后的目录结构应该变成了这样:
|--hello_doxygen\
|--doxygen_output\
|--html\
|--latex\
|--Doxyfile
|--hello.c
这里有个小细节, 相对路径是相对于工作目录的, 上面是工作目录为 hello_doxygen
时的结果. 也就是, 终端里的显示是这样的:
C:\hello_doxygen>doxygen Doxyfile
提个小问题. 如果在 hello_doxygen
的父目录运行命令, 输出文档会发生什么呢? 就留给读者取探索了. 此时终端的显示应该是这个样子(注意提示符>
以及命令的参数):
C:\>doxygen hello_doxygen/Doxyfile
INPUT
指出用作输入的源文件是什么, 它的值可以是文件, 也可以是目录, 每个值用空格隔开. 源文件可以是代码, 如 .c
, .h
, 也可以是其他 doxygen 支持的文件, 如 .md
, .dox
. 下面是一个例子:
INPUT = user \
lib \
main.c
如果该 tag 留空的话, 则默认它的值是当前目录(工作目录).
RECURSIVE
则指出是否要递归地在 INPUT
给出的目录的子目录中搜索源文件. 它的值为 YES 或 NO.
默认情况下, EXTRACT_ALL = NO
, doxygen 输出的文档中, 只包含那些已按 doxygen 语法注释的 entity (documented entities). 而如果设为 YES, 则 doxygen 会将所有的 entity 写入文档, 当然, static 和 private 的 entity 除外.
还是以前面的项目 hello_doxygen
为例. 我们把 hello.c
改成如下内容:
/**@file hello.c */
/**
* @brief A hello func.
* @details This hello function does nothing.
*/
void hello(){
// do nothing
}
void undocumented_hello() {}
我们先以 EXTRACT_ALL = YES
跑一次 doxygen. 然后点击 Files-hello.c, 网页是这个样子的:
可以看到 “Function Documentation” 下有函数 undocumented_hello()
, 但是里面没有任何内容. 这是当然的啦, 因为我们没有为它写任何注释.
然后将配置改成 EXTRACT_ALL = NO
, 输出文档, 刷新网页, 结果变成了这样:
“Functinos” 下 undocumented_hello()
不再是超链接的样式, “Function Documentation” 也没了这个函数.
除此之外, doxygen 还有一条规则, 原文是这样的:
To document a member of a C++ class, you must also document the class itself. The same holds for namespaces. To document a global C function, typedef, enum or preprocessor definition you must first document the file that contains it (usually this will be a header file, because that file contains the information that is exported to other source files).
总的来说就是, 要让 doxygen 把低层次的注释放到输出的文档中, 必须先做高层次的注释. 这个在后面还会举例解释, 这里先了解, 对于所有 entity 来说, 文件的层次最高了, 因此必须注释文件, 也就是源文件中至少必须有这一句 /**@file*/
, 否则输出的文档中是没有这个文件中的内容的.
这是一个常常被忽视的问题, 如果发现明明给函数写的注释完全符合规则, 但是输出的文档却看不到, 可能就是没有注释源文件. 感兴趣的读者可以试着把 hello.c
的第一句注释 /**@file hello.c */
删除掉再运行 doxygen, 看看输出的文档包含哪些内容.
之所以提这个问题, 是因为 EXTRACT_ALL = YES
时, 会把所有 entity 都记录在文档上, 那么文件是否被注释就没有那么重要了.
光看文字描述容易绕进去, 若按下表输出hello_doxygen
的文档, 把各种搭配都试一遍, 也许就清楚了.
有无 /**@file*/ |
EXTRACT_ALL |
输出的文档有无hello.c内容 |
---|---|---|
有 | NO | 有 |
无 | NO | 无 |
无 | YES | 有 |
该 tag 用于指定文档框架的语言. 文档的内容本身是来自于注释的, 所以注释写了什么, 文档内容就是什么, 不存在自动翻译的. 这里的语言是指文档框架, 即网页上那些固定的文字所使用的语言. 前面的例子, 使用的都是默认值 OUTPUT_LANGUAGE = English
, 而如果我们改为 OUTPUT_LANGUAGE = Chinese
, 那么页面就会变成下面这样子:
除了中文之外, doxygen 还支持许多其他的语言, 详情请看配置模板中, 该 tag 前的注释.
最开始提到, 本套教程只涉及 html 输出, 大多数场合下也只需要 html 输出. 但是默认情况下, doxygen 同时还生成了 latex 输出. 对于有洁癖的人来说, 产生了多余的东西会很难受, 所以就要设置 GENERATE_LATEX = NO
.
设置为 NO 以后, 删掉之前输出的文档, 重新生成一遍, 这次是不是就只有 html 输出了?