請注意,此章節仍在建構中!
下圖顯示 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 程式碼檔案
提供 flex
除錯資訊。
請注意,藉由執行帶有 -d lex
的 Doxygen,您可以取得有關使用了哪個 flex 程式碼檔案
的資訊。若要查看使用 flex 除錯選項編譯的 flex 解析器的資訊,您必須在執行 Doxygen 時指定 -d lex:<flex 程式碼檔案>
。
請注意,有關 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
類型替換變數。
返回索引。