歡迎您光臨本站 註冊首頁

學慣用 doxygen 生成源碼文檔

←手機掃碼閱讀     火星人 @ 2014-03-12 , reply:0
  
維護用 C/C++ 開發的遺留系統並添加新特性是一項艱難的任務。幸運的是,doxygen 可以幫助您完成這個任務。doxygen 是一種用於 C/C++、Java™、Python 和其他編程語言的文檔系統。本文在 C/C++ 項目的上下文中討論 doxygen 的特性,以及如何用 doxygen 定義的標記生成代碼文檔。

維護用 C/C++ 開發的遺留系統並添加新特性是一項艱難的任務。這涉及幾方面的問題:理解現有的類層次結構和全局變數,不同的用戶定義類型,以及函數調用圖分析等等。本文在 C/C++ 項目的上下文中通過示例討論 doxygen 的幾個特性。但是,doxygen 非常靈活,也可用於用 Python、Java、PHP 和其他語言開發的軟體項目。本文的主要目的是幫助您從 C/C++ 源代碼提取出信息,但也簡要描述了如何用 doxygen 定義的標記生成代碼文檔。

安裝 doxygen

有兩種獲得 doxygen 的方法。可以下載預編譯的可執行文件,也可以從 SVN 存儲庫下載源代碼並自己編譯。清單 1 演示的是后一種方法。


清單 1. 安裝和構建 doxygen 源代碼
                  bash-2.05$ svn co https://doxygen.svn.sourceforge.net/svnroot/doxygen/trunk doxygen-svn    bash-2.05$ cd doxygen-svn  bash-2.05$ ./configure –prefix=/home/user1/bin  bash-2.05$ make    bash-2.05$ make install  

注意,配置腳本把編譯的源代碼存儲在 /home/user1/bin 中(進行編譯后,會在 PATH 變數中添加這個目錄),因為並非每個 UNIX® 用戶都有寫 /usr 文件夾的許可權。另外,需要用 svn 實用程序下載源代碼。





使用 doxygen 生成文檔

使用 doxygen 生成源代碼的文檔需要執行三個步驟。

生成配置文件

在 shell 提示上,輸入命令 doxygen -g 。這個命令在當前目錄中生成一個可編輯的配置文件 Doxyfile。可以改變這個文件名,在這種情況下,應該調用 doxygen -g <user-specified file name>,見 清單 2。


清單 2. 生成默認的配置文件
                  bash-2.05b$ doxygen -g  Configuration file 'Doxyfile' created.  Now edit the configuration file and enter    doxygen Doxyfile  to generate the documentation for your project  bash-2.05b$ ls Doxyfile  Doxyfile  

編輯配置文件

配置文件採用 <TAGNAME> = <VALUE> 這樣的結構,與 Make 文件格式相似。下面是最重要的標記:

  • <OUTPUT_DIRECTORY>:必須在這裡提供一個目錄名,例如 /home/user1/documentation,這個目錄是放置生成的文檔文件的位置。如果提供一個不存在的目錄名,doxygen 會以這個名稱創建具有適當用戶許可權的目錄。
  • <INPUT>:這個標記創建一個以空格分隔的所有目錄的列表,這個列表包含需要生成文檔的 C/C++ 源代碼文件和頭文件。例如,請考慮以下代碼片段:
    INPUT = /home/user1/project/kernel /home/user1/project/memory  

    在這裡,doxygen 會從這兩個目錄讀取 C/C++ 源代碼。如果項目只有一個源代碼根目錄,其中有多個子目錄,那麼只需指定根目錄並把 <RECURSIVE> 標記設置為 Yes。

  • <FILE_PATTERNS>:在默認情況下,doxygen 會搜索具有典型 C/C++ 擴展名的文件,比如 .c、.cc、.cpp、.h 和 .hpp。如果 <FILE_PATTERNS> 標記沒有相關聯的值,doxygen 就會這樣做。如果源代碼文件採用不同的命名約定,就應該相應地更新這個標記。例如,如果項目使用 .c86 作為 C 文件擴展名,就應該在 <FILE_PATTERNS> 標記中添加這個擴展名。
  • <RECURSIVE>:如果源代碼層次結構是嵌套的,而且需要為所有層次上的 C/C++ 文件生成文檔,就把這個標記設置為 Yes。例如,請考慮源代碼根目錄層次結構 /home/user1/project/kernel,其中有 /home/user1/project/kernel/vmm 和 /home/user1/project/kernel/asm 等子目錄。如果這個標記設置為 Yes,doxygen 就會遞歸地搜索整個層次結構並提取信息。
  • <EXTRACT_ALL>:這個標記告訴 doxygen,即使各個類或函數沒有文檔,也要提取信息。必須把這個標記設置為 Yes。
  • <EXTRACT_PRIVATE>:把這個標記設置為 Yes。否則,文檔不包含類的私有數據成員。
  • <EXTRACT_STATIC>:把這個標記設置為 Yes。否則,文檔不包含文件的靜態成員(函數和變數)。

清單 3 給出一個 Doxyfile 示例。


清單 3. 包含用戶提供的標記值的 doxyfile 示例
                  OUTPUT_DIRECTORY = /home/user1/docs  EXTRACT_ALL = yes  EXTRACT_PRIVATE = yes  EXTRACT_STATIC = yes  INPUT = /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/.hpp  FILE_PATTERNS =   RECURSIVE = yes  

運行 doxygen

在 shell 提示下輸入 doxygen Doxyfile(或者已為配置文件選擇的其他文件名)運行 doxygen。在最終生成 Hypertext Markup Language(HTML)和 Latex 格式(默認)的文檔之前,doxygen 會顯示幾個消息。在生成文檔期間,在 <OUTPUT_DIRECTORY> 標記指定的文件夾中,會創建兩個子文件夾 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 exclude  Reading input files...  Reading and parsing tag files  Preprocessing /home/user1/project/kernel/kernel.h  …  Read 12489207 bytes  Parsing input...  Parsing file /project/user1/project/kernel/epico.cxx  …  Freeing input...  Building group list...  ..  Generating docs for compound MemoryManager::ProcessSpec  …  Generating docs for namespace std  Generating 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 手冊頁:把 <GENERATE_MAN> 標記設置為 Yes。在默認情況下,會在 <OUTPUT_DIRECTORY> 指定的目錄中創建 man 子文件夾,生成的文檔放在這個文件夾中。必須把這個文件夾添加到 MANPATH 環境變數中。
  • Rich Text Format(RTF):把 <GENERATE_RTF> 標記設置為 Yes。把 <RTF_OUTPUT> 標記設置為希望放置 .rtf 文件的目錄;在默認情況下,文檔放在 OUTPUT_DIRECTORY 中的 rtf 子文件夾中。要想支持跨文檔瀏覽,應該把 <RTF_HYPERLINKS> 標記設置為 Yes。如果設置這個標記,生成的 .rtf 文件會包含跨文檔鏈接。
  • Latex:在默認情況下,doxygen 生成 Latex 和 HTML 格式的文檔。在默認的 Doxyfile 中,<GENERATE_LATEX> 標記設置為 Yes。另外,<LATEX_OUTPUT> 標記設置為 Latex,這意味著會在 OUTPUT_DIRECTORY 中創建 latex 子文件夾並在其中生成 Latex 文件。
  • Microsoft® Compiled HTML Help(CHM)格式:把 <GENERATE_HTMLHELP> 標記設置為 Yes。因為在 UNIX 平台上不支持這種格式,doxygen 只在保存 HTML 文件的文件夾中生成一個 index.hhp 文件。您必須通過 HTML 幫助編譯器把這個文件轉換為 .chm 文件。
  • Extensible Markup Language(XML)格式:把 <GENERATE_XML> 標記設置為 Yes。(注意,doxygen 開發團隊還在開發 XML 輸出)。

清單 5 提供的 Doxyfile 示例讓 doxygen 生成所有格式的文檔。


清單 5. 生成多種格式的文檔的 Doxyfile
                  #for HTML   GENERATE_HTML = YES  HTML_FILE_EXTENSION = .htm    #for CHM files  GENERATE_HTMLHELP = YES    #for Latex output  GENERATE_LATEX = YES  LATEX_OUTPUT = latex    #for RTF  GENERATE_RTF = YES  RTF_OUTPUT = rtf   RTF_HYPERLINKS = YES    #for MAN pages  GENERATE_MAN = YES  MAN_OUTPUT = man  #for XML  GENERATE_XML = YES  





doxygen 中的特殊標記

doxygen 包含幾個特殊標記。

C/C++ 代碼的預處理

為了提取信息,doxygen 必須對 C/C++ 代碼進行預處理。但是,在默認情況下,它只進行部分預處理 —— 計算條件編譯語句(#if…#endif),但是不執行宏展開。請考慮 清單 6 中的代碼。


清單 6. 使用宏的 C++ 代碼示例
                  #include <cstring>  #include <rope>    #define USE_ROPE    #ifdef USE_ROPE    #define STRING std::rope  #else    #define STRING std::string  #endif    static STRING name;  

通過源代碼中定義的 <USE_ROPE>,doxygen 生成的文檔如下:

                Defines      #define USE_ROPE      #define STRING std::rope    Variables      static STRING name  

在這裡可以看到 doxygen 執行了條件編譯,但是沒有對 STRING 執行宏展開。Doxyfile 中的 <ENABLE_PREPROCESSING> 標記在默認情況下設置為 Yes。為了執行宏展開,還應該把 <MACRO_EXPANSION> 標記設置為 Yes。這會使 doxygen 產生以下輸出:

                Defines     #define USE_ROPE      #define STRING std::string    Variables      static std::rope name  

如果把 <ENABLE_PREPROCESSING> 標記設置為 No,前面源代碼的 doxygen 輸出就是:

                Variables      static STRING name  

注意,文檔現在沒有定義,而且不可能推導出 STRING 的類型。因此,總是應該把 <ENABLE_PREPROCESSING> 標記設置為 Yes。

在文檔中,可能希望只展開特定的宏。為此,除了把 <ENABLE_PREPROCESSING> 和 <MACRO_EXPANSION> 標記設置為 Yes 之外,還必須把 <EXPAND_ONLY_PREDEF> 標記設置為 Yes(這個標記在默認情況下設置為 No),並在 <PREDEFINED> 或 <EXPAND_AS_DEFINED> 標記中提供宏的細節。請考慮 清單 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  #endif    static STRING name;  static CONTAINER gList;  

清單 8 給出配置文件。


清單 8. 允許有選擇地展開宏的 Doxyfile
                  ENABLE_PREPROCESSING = YES  MACRO_EXPANSION = YES  EXPAND_ONLY_PREDEF = YES  EXPAND_AS_DEFINED = CONTAINER  …  

下面的 doxygen 輸出只展開了 CONTAINER:

                Defines  #define STRING   std::string   #define CONTAINER   std::list    Variables  static STRING name  static std::list gList  

注意,只有 CONTAINER 宏被展開了。在 <MACRO_EXPANSION> 和 <EXPAND_ONLY_PREDEF> 都設置為 Yes 的情況下,<EXPAND_AS_DEFINED> 標記只選擇展開等號操作符右邊列出的宏。

對於預處理過程,要注意的最後一個標記是 <PREDEFINED>。就像用 -D 開關向 C++ 編譯器傳遞預處理器定義一樣,使用這個標記定義宏。請考慮 清單 9 中的 Doxyfile。


清單 9. 定義了宏展開標記的 Doxyfile
                  ENABLE_PREPROCESSING = YES  MACRO_EXPANSION = YES  EXPAND_ONLY_PREDEF = YES  EXPAND_AS_DEFINED =   PREDEFINED = USE_ROPE= \                               ALLOW_RANDOM_ACCESS=1  

下面是 doxygen 生成的輸出:

                Defines  #define USE_CROPE   #define STRING   std::rope   #define CONTAINER   std::vector    Variables  static std::rope name   static std::vector gList  

在使用 <PREDEFINED> 標記時,宏應該定義為 <macro name>=<value> 形式。如果不提供值,比如簡單的 #define,那麼只使用 <macro name>=<spaces> 即可。多個宏定義以空格或反斜杠(\)分隔。

從文檔生成過程中排除特定文件或目錄

在 Doxyfile 中的 <EXCLUDE> 標記中,添加不應該為其生成文檔的文件或目錄(以空格分隔)。因此,如果提供了源代碼層次結構的根,並要跳過某些子目錄,這將非常有用。例如,如果層次結構的根是 src_root,希望在文檔生成過程中跳過 examples/ 和 test/memoryleaks 文件夾,Doxyfile 應該像 清單 10 這樣。


清單 10. 使用 EXCLUDE 標記的 Doxyfile
                  INPUT = /home/user1/src_root  EXCLUDE = /home/user1/src_root/examples /home/user1/src_root/test/memoryleaks  …  





生成圖形和圖表

在默認情況下,Doxyfile 把 <CLASS_DIAGRAMS> 標記設置為 Yes。這個標記用來生成類層次結構圖。要想生成更好的視圖,可以從 Graphviz 下載站點 下載 dot 工具。Doxyfile 中的以下標記用來生成圖表:

  • <CLASS_DIAGRAMS>:在 Doxyfile 中這個標記默認設置為 Yes。如果這個標記設置為 No,就不生成繼承層次結構圖。
  • <HAVE_DOT>:如果這個標記設置為 Yes,doxygen 就使用 dot 工具生成更強大的圖形,比如幫助理解類成員及其數據結構的協作圖。注意,如果這個標記設置為 Yes,<CLASS_DIAGRAMS> 標記就無效了。
  • <CLASS_GRAPH>:如果 <HAVE_DOT> 標記和這個標記同時設置為 Yes,就使用 dot 生成繼承層次結構圖,而且其外觀比只使用 <CLASS_DIAGRAMS> 時更豐富。
  • <COLLABORATION_GRAPH>:如果 <HAVE_DOT> 標記和這個標記同時設置為 Yes,doxygen 會生成協作圖(還有繼承圖),顯示各個類成員(即包含)及其繼承層次結構。

清單 11 提供一個使用一些數據結構的示例。注意,在配置文件中 <HAVE_DOT>、<CLASS_GRAPH> 和 <COLLABORATION_GRAPH> 標記都設置為 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++ 註釋,或使用 <\brief> 標記。
  • 詳細描述:使用 JavaDoc 式的註釋 /** … test … */(注意開頭的兩個星號 [*])或 Qt 式的註釋 /*! … text … */。
  • 體內描述:類、結構、聯合體和名稱空間等 C++ 元素都有自己的標記,比如 <\class>、<\struct>、<\union> 和 <\namespace>。

為了為全局函數、變數和枚舉類型生成文檔,必須先對對應的文件使用 <\file> 標記。清單 12 給出的示例包含用於四種元素的標記:函數標記(<\fn>)、函數參數標記(<\param>)、變數名標記(<\var>)、用於 #define 的標記(<\def>)以及用來表示與一個代碼片段相關的問題的標記(<\warning>)。


清單 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.    Functions  bool check_for_io_errors (FILE *fp)            Checks if a file is corrupted or not.    Variables  const int fileSize = 1048576;  Function Documentation  bool check_for_io_errors (FILE* fp)  Checks if a file is corrupted or not.    Parameters                fp: Pointer to an already opened file    Warning  Not thread safe!   





結束語

本文討論如何用 doxygen 從遺留的 C/C++ 代碼提取出大量相關信息。如果用 doxygen 標記生成代碼文檔,doxygen 會以容易閱讀的格式生成輸出。只要以適當的方式使用,doxygen 就可以幫助任何開發人員維護和管理遺留系統。(責任編輯:A6)



[火星人 ] 學慣用 doxygen 生成源碼文檔已經有1264次圍觀

http://coctec.com/docs/linux/show-post-69103.html