请注意,本节仍在建设中!
下图显示了 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
中定义,是一个松散结构的信息 blob。最重要的字段是 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
调试信息。
请注意,通过使用 -d lex
运行 Doxygen,您可以获得有关使用哪个 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 配置文件设置不同的配置设置,则可以使用 -x
选项和配置文件名称(默认为 Doxyfile
)运行 Doxygen 命令。输出将是未默认设置的列表(采用 Doxyfile
格式)。或者,也可以使用 -x_noenv
,它与 -x
选项相同,但不替换环境变量和 CMake
类型替换变量。
返回 索引。