維護用 C/C++
開發的遺留係統並添加新特性是一項艱難的任務。這涉及幾方麵的問題:理解現有的類層次結構和全局變量,不同的用戶定義類型,以及函數調用圖分析等等。本文在 C/C++
項目的上下文中通過示例討論 doxygen 的幾個特性。但是,doxygen 非常靈活,也可用於用 Python、Java、PHP 和其他語言開發的軟件項目。本文的主要目的是幫助您從 C/C++
源代碼提取出信息,但也簡要描述了如何用 doxygen 定義的標記生成代碼文檔。
有兩種獲得 doxygen 的方法。可以下載預編譯的可執行文件,也可以從 SVN 存儲庫下載源代碼並自己編譯。清單 1 演示的是後一種方法。
清單 1. 安裝和構建 doxygen 源代碼
bash-2.05$ svn co https://doxygen.svn.sourceforge.net/svnroot/doxygen/trunk doxygen-svnbash-2.05$ cd doxygen-svnbash-2.05$ ./configure –prefix=/home/user1/binbash-2.05$ makebash-2.05$ make install |
注意,配置腳本把編譯的源代碼存儲在 /home/user1/bin 中(進行編譯後,會在 PATH 變量中添加這個目錄),因為並非每個 UNIX® 用戶都有寫 /usr 文件夾的權限。另外,需要用 svn
實用程序下載源代碼。
使用 doxygen 生成源代碼的文檔需要執行三個步驟。
在 shell 提示上,輸入命令 doxygen -g
。這個命令在當前目錄中生成一個可編輯的配置文件 Doxyfile。可以改變這個文件名,在這種情況下,應該調用 doxygen -g <user-specified file name>
,見 清單 2。
清單 2. 生成默認的配置文件
bash-2.05b$ doxygen -gConfiguration file 'Doxyfile' created.Now edit the configuration file and enter doxygen Doxyfileto generate the documentation for your projectbash-2.05b$ ls DoxyfileDoxyfile |
配置文件采用
=
這樣的結構,與 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/docsEXTRACT_ALL = yesEXTRACT_PRIVATE = yesEXTRACT_STATIC = yesINPUT = /home/user1/project/kernel#Do not add anything here unless you need to. Doxygen already covers all #common formats like .c/.cc/.cxx/.c++/.cpp/.inl/.h/.hppFILE_PATTERNS = RECURSIVE = yes |
在 shell 提示下輸入 doxygen Doxyfile
(或者已為配置文件選擇的其他文件名)運行 doxygen。在最終生成 Hypertext Markup Language(HTML)和 Latex 格式(默認)的文檔之前,doxygen 會顯示幾個消息。在生成文檔期間,在
標記指定的文件夾中,會創建兩個子文件夾 html 和 latex。清單 4 是一個 doxygen 運行日誌示例。
清單 4. doxygen 的日誌輸出
Searching for include files...Searching for example files...Searching for images...Searching for dot files...Searching for files to excludeReading input files...Reading and parsing tag filesPreprocessing /home/user1/project/kernel/kernel.h…Read 12489207 bytesParsing input...Parsing file /project/user1/project/kernel/epico.cxx…Freeing input...Building group list.....Generating docs for compound MemoryManager::ProcessSpec…Generating docs for namespace stdGenerating group index...Generating example index...Generating file member index...Generating namespace member index...Generating page index...Generating graph info page...Generating search index...Generating style sheet... |
除了 HTML 之外,doxygen 還可以生成幾種輸出格式的文檔。可以讓 doxygen 生成以下格式的文檔:
- UNIX 手冊頁:把
標記設置為 Yes。在默認情況下,會在
指定的目錄中創建 man 子文件夾,生成的文檔放在這個文件夾中。必須把這個文件夾添加到 MANPATH 環境變量中。 - Rich Text Format(RTF):把
標記設置為 Yes。把
標記設置為希望放置 .rtf 文件的目錄;在默認情況下,文檔放在 OUTPUT_DIRECTORY 中的 rtf 子文件夾中。要想支持跨文檔瀏覽,應該把
標記設置為 Yes。如果設置這個標記,生成的 .rtf 文件會包含跨文檔鏈接。 - Latex:在默認情況下,doxygen 生成 Latex 和 HTML 格式的文檔。在默認的 Doxyfile 中,
標記設置為 Yes。另外,
標記設置為 Latex,這意味著會在 OUTPUT_DIRECTORY 中創建 latex 子文件夾並在其中生成 Latex 文件。 - Microsoft® Compiled HTML Help(CHM)格式:把
標記設置為 Yes。因為在 UNIX 平台上不支持這種格式,doxygen 隻在保存 HTML 文件的文件夾中生成一個 index.hhp 文件。您必須通過 HTML 幫助編譯器把這個文件轉換為 .chm 文件。 - Extensible Markup Language(XML)格式:把
標記設置為 Yes。(注意,doxygen 開發團隊還在開發 XML 輸出)。
清單 5 提供的 Doxyfile 示例讓 doxygen 生成所有格式的文檔。
清單 5. 生成多種格式的文檔的 Doxyfile
#for HTML GENERATE_HTML = YESHTML_FILE_EXTENSION = .htm#for CHM filesGENERATE_HTMLHELP = YES#for Latex outputGENERATE_LATEX = YESLATEX_OUTPUT = latex#for RTFGENERATE_RTF = YESRTF_OUTPUT = rtf RTF_HYPERLINKS = YES#for MAN pagesGENERATE_MAN = YESMAN_OUTPUT = man#for XMLGENERATE_XML = YES |
doxygen 包含幾個特殊標記。
為了提取信息,doxygen 必須對 C/C++
代碼進行預處理。但是,在默認情況下,它隻進行部分預處理 —— 計算條件編譯語句(#if…#endif
),但是不執行宏展開。請考慮 清單 6 中的代碼。
清單 6. 使用宏的 C++ 代碼示例
#include |
通過源代碼中定義的
,doxygen 生成的文檔如下:
Defines #define USE_ROPE #define STRING std::ropeVariables static STRING name |
在這裏可以看到 doxygen 執行了條件編譯,但是沒有對 STRING
執行宏展開。Doxyfile 中的
標記在默認情況下設置為 Yes。為了執行宏展開,還應該把
標記設置為 Yes。這會使 doxygen 產生以下輸出:
Defines #define USE_ROPE #define STRING std::stringVariables static std::rope name |
如果把
標記設置為 No,前麵源代碼的 doxygen 輸出就是:
Variables static STRING name |
注意,文檔現在沒有定義,而且不可能推導出 STRING
的類型。因此,總是應該把
標記設置為 Yes。
在文檔中,可能希望隻展開特定的宏。為此,除了把
和
標記設置為 Yes 之外,還必須把
標記設置為 Yes(這個標記在默認情況下設置為 No),並在
或
標記中提供宏的細節。請考慮 清單 7 中的代碼,這裏隻希望展開宏 CONTAINER
。
清單 7. 包含多個宏的 C++ 源代碼
#ifdef USE_ROPE #define STRING std::rope#else #define STRING std::string#endif#if ALLOW_RANDOM_ACCESS == 1 #define CONTAINER std::vector#else #define CONTAINER std::list#endifstatic STRING name;static CONTAINER gList; |
清單 8 給出配置文件。
清單 8. 允許有選擇地展開宏的 Doxyfile
ENABLE_PREPROCESSING = YESMACRO_EXPANSION = YESEXPAND_ONLY_PREDEF = YESEXPAND_AS_DEFINED = CONTAINER… |
下麵的 doxygen 輸出隻展開了 CONTAINER
:
Defines#define STRING std::string #define CONTAINER std::listVariablesstatic STRING namestatic std::list gList |
注意,隻有 CONTAINER
宏被展開了。在
和
都設置為 Yes 的情況下,
標記隻選擇展開等號操作符右邊列出的宏。
對於預處理過程,要注意的最後一個標記是
。就像用 -D
開關向 C++ 編譯器傳遞預處理器定義一樣,使用這個標記定義宏。請考慮 清單 9 中的 Doxyfile。
清單 9. 定義了宏展開標記的 Doxyfile
ENABLE_PREPROCESSING = YESMACRO_EXPANSION = YESEXPAND_ONLY_PREDEF = YESEXPAND_AS_DEFINED = PREDEFINED = USE_ROPE= ALLOW_RANDOM_ACCESS=1 |
下麵是 doxygen 生成的輸出:
Defines#define USE_CROPE #define STRING std::rope #define CONTAINER std::vectorVariablesstatic std::rope name static std::vector gList |
在使用
標記時,宏應該定義為 <macro name>=<value>
形式。如果不提供值,比如簡單的 #define
,那麽隻使用 <macro name>=<spaces>
即可。多個宏定義以空格或反斜杠()分隔。
在 Doxyfile 中的
標記中,添加不應該為其生成文檔的文件或目錄(以空格分隔)。因此,如果提供了源代碼層次結構的根,並要跳過某些子目錄,這將非常有用。例如,如果層次結構的根是 src_root,希望在文檔生成過程中跳過 examples/ 和 test/memoryleaks 文件夾,Doxyfile 應該像 清單 10 這樣。
清單 10. 使用 EXCLUDE 標記的 Doxyfile
INPUT = /home/user1/src_rootEXCLUDE = /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++ 類和結構示例
struct D { int d;};class A { int a;};class B : public A { int b;};class C : public B { int c; D d;}; |
圖 1 給出 doxygen 的輸出。
圖 1. 使用 dot 工具生成的類繼承圖和協作圖
到目前為止,我們都是使用 doxygen 從原本沒有文檔的代碼中提取信息。但是,doxygen 也鼓勵使用文檔樣式和語法,這有助於生成更詳細的文檔。本節討論 doxygen 鼓勵在 C/C++
代碼中使用的一些常用標記。更多信息參見 參考資料。
每個代碼元素有兩種描述:簡短的和詳細的。簡短描述通常是單行的。函數和類方法還有第三種描述體內描述(in-body description),這種描述把在函數體中找到的所有注釋塊集中在一起。比較常用的一些 doxygen 標記和注釋樣式如下:
- 簡短描述:使用單行的
C++
注釋,或使用
標記。 - 詳細描述:使用 JavaDoc 式的注釋
/** … test … */
(注意開頭的兩個星號 [*
])或 Qt 式的注釋/*! … text … */
。 - 體內描述:類、結構、聯合體和名稱空間等
C++
元素都有自己的標記,比如
、
、
和
。
為了為全局函數、變量和枚舉類型生成文檔,必須先對對應的文件使用
標記。清單 12 給出的示例包含用於四種元素的標記:函數標記(
)、函數參數標記()、變量名標記(
)、用於
#define
的標記(
)以及用來表示與一個代碼片段相關的問題的標記(
)。
清單 12. 典型的 doxygen 標記及其使用方法
/*! file globaldecls.h brief Place to look for global variables, enums, functions and macro definitions *//** var const int fileSize brief Default size of the file on disk */const int fileSize = 1048576;/** def SHIFT(value, length) brief Left shift value by length in bits */#define SHIFT(value, length) ((value) << (length))/** fn bool check_for_io_errors(FILE* fp) brief Checks if a file is corrupted or not param fp Pointer to an already opened file warning Not thread safe! */bool check_for_io_errors(FILE* fp); |
下麵是生成的文檔:
Defines#define SHIFT(value, length) ((value) << (length)) Left shift value by length in bits.Functionsbool check_for_io_errors (FILE *fp) Checks if a file is corrupted or not.Variablesconst int fileSize = 1048576;Function Documentationbool check_for_io_errors (FILE* fp)Checks if a file is corrupted or not.Parameters fp: Pointer to an already opened fileWarningNot thread safe! |
本文討論如何用 doxygen 從遺留的 C/C++
代碼提取出大量相關信息。如果用 doxygen 標記生成代碼文檔,doxygen 會以容易閱讀的格式生成輸出。隻要以適當的方式使用,doxygen 就可以幫助任何開發人員維護和管理遺留係統。
學習
- 您可以參閱本文在 developerWorks 全球站點上的 英文原文 。
- doxygen 站點 包含關於 doxygen 的非常有價值的手冊和幾篇文章。
- 下載 dot 實用程序。
- AIX and UNIX 專區:developerWorks 的“AIX and UNIX 專區”提供了大量與 AIX 係統管理的所有方麵相關的信息,您可以利用它們來擴展自己的 UNIX 技能。
- AIX and UNIX 新手入門:訪問“AIX and UNIX 新手入門”頁麵可了解更多關於 AIX 和 UNIX 的內容。
- AIX and UNIX 專題匯總:AIX and UNIX 專區已經為您推出了很多的技術專題,為您總結了很多熱門的知識點。我們在後麵還會繼續推出很多相關的熱門專題給您,為了方便您的訪問,我們在這裏為您把本專區的所有專題進行匯總,讓您更方便的找到您需要的內容。
- developerWorks 技術活動和網絡廣播:隨時關注 developerWorks 技術活動和網絡廣播。
- Podcasts:收聽 IBM 技術專家的訪談錄。
獲得產品和技術
討論