请注意,本节仍在建设中!
下图展示了 Doxygen 如何处理源文件。
以下部分将更详细地解释上述步骤。
解析控制项目设置的配置文件,并将设置存储在 src/config.h
中的单例类 Config
中。解析器本身使用 flex
编写,位于 src/config.l
中。该解析器也由 Doxywizard 直接使用,因此放在一个单独的库中。
每个配置选项有 5 种可能的类型之一:String
、List
、Enum
、Int
或 Bool
。这些选项的值可以通过全局函数 Config_getXXX()
获取,其中 XXX
是选项的类型。这些函数的参数是配置文件中出现的选项名称字符串。例如:Config_getBool(GENERATE_TESTLIST)
返回一个布尔值的引用,如果测试列表在配置文件中启用,则该值为 TRUE
。
src/doxygen.cpp
中的函数 readConfiguration()
读取命令行选项,然后调用配置解析器。
配置文件中提到的输入文件(默认情况下)会送给 C 预处理器处理(如果可用,先通过用户定义的过滤器进行管道处理)。
预处理器的工作方式与标准 C 预处理器有些不同。默认情况下它不进行宏展开,但可以配置为展开所有宏。典型用法是只展开用户指定的一组宏。这是为了允许宏名称出现在函数参数的类型中等情况。
另一个区别是,预处理器解析 #include
但实际不包含代码({ ... }
块中发现的 #include
除外)。这种偏离标准的原因是为了防止将相同函数/类的多重定义馈送给 Doxygen 的解析器。例如,如果所有源文件都包含一个公共头文件,则类和类型定义(及其文档)将存在于每个翻译单元中。
预处理器使用 flex
编写,可以在 src/pre.l
中找到。对于条件块(#if
),需要评估常量表达式。为此,使用了基于 yacc
的解析器,可以在 src/constexp.y
和 src/constexp.l
中找到。
使用 src/pre.h
中声明的 preprocessFile()
函数对每个文件调用预处理器,并将预处理结果附加到字符缓冲区。字符缓冲区的格式是
0x06 file name 1 0x06 preprocessed contents of file 1 ... 0x06 file name n 0x06 preprocessed contents of file n
预处理后的输入缓冲区被送入语言解析器,该解析器使用 flex
实现为一个大型状态机。它位于文件 src/scanner.l
中。所有语言(C/C++/Java/IDL)共用一个解析器。状态变量 insideIDL
和 insideJava
在某些地方用于特定语言的选择。
解析器的任务是将输入缓冲区转换为条目树(基本上是一个抽象语法树)。条目在 src/entry.h
中定义,是一个包含松散结构信息的“数据块”。最重要的字段是 section
,它指定了条目中包含的信息类型。
未来版本的可能改进
此步骤包含许多更小的步骤,用于构建提取的类、文件、命名空间、变量、函数、包、页面和组的字典。除了构建字典之外,在此步骤中还会计算提取实体之间的关系(例如继承关系)。
每个步骤都有一个在 src/doxygen.cpp
中定义的函数,该函数操作语言解析期间构建的条目树。有关详细信息,请参阅 parseInput()
的“信息收集”部分。
此步骤的结果是一些字典,可以在 src/doxygen.h
中定义的 Doxygen“命名空间”中找到。这些字典的大多数元素派生自 Definition
类;例如,MemberDef
类包含成员的所有信息。此类的一个实例可以属于文件(FileDef
类)、类(ClassDef
类)、命名空间(NamespaceDef
类)、组(GroupDef
类)或 Java 包(PackageDef
类)。
如果在配置文件中指定了标签文件,则这些文件由基于 SAX 的 XML 解析器解析,该解析器位于 src/tagreader.cpp
中。解析标签文件的结果是在条目树中插入 Entry
对象。字段 Entry::tagInfo
用于将条目标记为外部,并包含有关标签文件的信息。
特殊注释块以字符串形式存储在它们所文档化的实体中。有一个字符串用于简要描述,一个字符串用于详细描述。文档解析器读取这些字符串并执行其中找到的命令(这是解析文档的第二遍)。它直接将结果写入输出生成器。
解析器用 C++ 编写,位于 src/docparser.cpp
中。解析器读取的令牌来自 src/doctokenizer.l
。在注释块中找到的代码片段会传递给源代码解析器。
文档解析器的主要入口点是在 src/docparser.h
中声明的 validatingParseDoc()
。对于带有特殊命令的简单文本,使用 validatingParseText()
。
如果启用了源代码浏览,或者如果在文档中遇到代码片段,则会调用源代码解析器。
代码解析器尝试将其解析的源代码与已文档化的实体进行交叉引用。它还对源代码进行语法高亮。输出直接写入输出生成器。
代码解析器的主要入口点是在 src/code.h
中声明的 parseCode()
。
数据收集并交叉引用后,Doxygen 会生成各种格式的输出。为此,它使用抽象类 OutputGenerator
提供的方法。为了同时生成多种格式的输出,而是调用 OutputList
的方法。该类维护一个具体输出生成器的列表,其中调用的每个方法都会委托给列表中的所有生成器。
为了允许写入每个具体输出生成器的输出略有偏差,可以临时禁用某些生成器。OutputList 类为此包含各种 disable()
和 enable()
方法。方法 OutputList::pushGeneratorState()
和 OutputList::popGeneratorState()
用于将已启用/已禁用的输出生成器集合临时保存在堆栈上。
XML 直接从收集的数据结构生成。未来 XML 将用作中间语言(IL)。输出生成器将以此 IL 为起点生成特定输出格式。拥有 IL 的优点是,用各种语言开发的各种独立工具可以从 XML 输出中提取信息。可能的工具包括
由于 Doxygen 使用了大量的 flex
代码,因此理解 flex
如何工作(为此应该阅读 man
手册页)以及理解 flex
在解析某些输入时正在做什么非常重要。幸运的是,当 flex
使用 -d 选项时,它会输出匹配的规则。这使得跟踪特定输入片段发生了什么变得非常容易。
为了更容易切换给定 flex
文件的调试信息,我编写了以下 perl
脚本,该脚本会自动在 Makefile:
中的正确行添加或删除 -d:
#!/usr/bin/perl $file = shift @ARGV; print "Toggle debugging mode for $file\n"; if (!-e "../src/${file}.l") { print STDERR "Error: file ../src/${file}.l does not exist!\n"; exit 1; } system("touch ../src/${file}.l"); unless (rename "src/CMakeFiles/doxymain.dir/build.make","src/CMakeFiles/doxymain.dir/build.make.old") { print STDERR "Error: cannot rename src/CMakeFiles/doxymain.dir/build.make!\n"; exit 1; } if (open(F,"<src/CMakeFiles/doxymain.dir/build.make.old")) { unless (open(G,">src/CMakeFiles/doxymain.dir/build.make")) { print STDERR "Error: opening file build.make for writing\n"; exit 1; } print "Processing build.make...\n"; while (<F>) { if ( s/flex \$\(LEX_FLAGS\) -d(.*) ${file}.l/flex \$(LEX_FLAGS)$1 ${file}.l/ ) { print "Disabling debug info for $file\n"; } elsif ( s/flex \$\(LEX_FLAGS\)(.*) ${file}.l$/flex \$(LEX_FLAGS) -d$1 ${file}.l/ ) { print "Enabling debug info for $file.l\n"; } print G "$_"; } close F; unlink "src/CMakeFiles/doxymain.dir/build.make.old"; } else { print STDERR "Warning file src/CMakeFiles/doxymain.dir/build.make does not exist!\n"; } # touch the file $now = time; utime $now, $now, $file;
从 flex
代码中获取规则匹配/调试信息的另一种方法是在使用 make
时设置 LEX_FLAGS
(make LEX_FLAGS=-d)。
默认情况下,Doxygen 的调试版本(即使用 CMake
设置 -DCMAKE_BUILD_TYPE=Debug 创建的可执行文件)将自动包含所有 flex codefile 的 flex
调试信息。
请注意,运行 Doxygen 时使用 -d lex 会获得有关使用了哪个 flex codefile 的信息。要查看使用 flex 调试选项编译的 flex 解析器的信息,您需要在运行 Doxygen 时指定 -d lex:<flex codefile>。
请注意,关于 lex 解析的信息会输出到 stderr,而其他调试输出默认会输出到 stdout,除非使用 -d stderr。
Doxygen 包含一小组可用测试,用于测试某些代码的完整性。可以通过命令 make tests 运行测试。如果只需要运行一个或几个测试,可以在运行测试时设置变量 TEST_FLAGS
,例如 make TEST_FLAGS="--id 5" tests 或运行多个测试时使用 make TEST_FLAGS="--id 5 --id 7" tests。要查看所有可能的选项,请执行命令 make TEST_FLAGS="--help" tests。还可以将 TEST_FLAGS 指定为环境变量(也适用于通过 Visual Studio 项目进行测试),例如 setenv TEST_FLAGS "--id 5 --id 7" 和 make tests。
如果您需要通过例如论坛沟通与标准 Doxygen 配置文件设置不同的配置设置,可以运行 Doxygen 命令:使用 -x 选项和配置文件的名称(默认为 Doxyfile)。输出将是一个非默认设置的列表(以 Doxyfile 格式)。或者也可以使用 -x_noenv,它与 -x 选项相同,但不替换环境变量和 CMake
类型替换变量。
返回索引。