?
便利的開發(fā)文檔工具-doxygen
mounton @ {www.ihere.org} ( mount0n@yahoo.com)
2003年8月
0. 序言
為代碼寫注釋一直是大多數(shù)程序員有些困擾的事情。當(dāng)前程序員都能接受為了程序的可維護(hù)性、可讀性編碼的同時(shí)寫注釋的說(shuō)法,但對(duì)哪些地方應(yīng)該寫注釋,注釋如何寫,寫多少等這些問(wèn)題,很多程序員仍然沒(méi)有答案。更頭痛的是寫文檔,以及維護(hù)文檔的問(wèn)題,開發(fā)人員通常可以忍受編寫或者改動(dòng)代碼時(shí)編寫或者修改對(duì)應(yīng)的注釋,但之后需要修正相應(yīng)的文檔卻比較困難。如果能從注釋直接轉(zhuǎn)化成文檔,對(duì)開發(fā)人員無(wú)疑是一種福音。而doxygen就能把遵守某種格式的注釋自動(dòng)轉(zhuǎn)化為對(duì)應(yīng)的文檔。
Doxygen是基于GPL的開源項(xiàng)目,是一個(gè)非常優(yōu)秀的文檔系統(tǒng),當(dāng)前支持在大多數(shù)unix(包括linux),windows家族,Mac系統(tǒng)上運(yùn)行,完全支持C++, C, Java, IDL(Corba和Microsoft 家族)語(yǔ)言,部分支持PHP和C#語(yǔ)言,輸出格式包括HTML、latex、RTF、ps、PDF、壓縮的HTML和unix manpage。有很多開源項(xiàng)目(包括前兩篇文章介紹的log4cpp和CppUnit)都使用了doxygen文檔系統(tǒng)。而國(guó)內(nèi)的開發(fā)人員卻使用的不多,這里從開發(fā)人員使用的角度介紹這個(gè)工具,使開發(fā)人員用最少的代價(jià)盡快掌握這種技術(shù),并結(jié)合這個(gè)工具探討如何撰寫注釋的問(wèn)題。以下以linux下的C++語(yǔ)言為例進(jìn)行介紹,以下討論基于doxygen1.3.3。
1. doxygen使用步驟
由于只是工具的使用,這里不介紹它的原理,直接從使用步驟開始。Doxygen的使用步驟非常簡(jiǎn)單。主要可以分為:
?1)第一次使用需要安裝doxygen的程序
?2)生成doxygen配置文件
?3)編碼時(shí),按照某種格式編寫注釋
?4)生成對(duì)應(yīng)文檔
doxygen的安裝非常簡(jiǎn)單, linux下可以直接下載安裝包運(yùn)行即可,下載源代碼編譯安裝也是比較通用的編譯安裝命令。請(qǐng)參考其安裝文檔完成安裝。
Doxygen在生成文檔時(shí)可以定義項(xiàng)目屬性以及文檔生成過(guò)程中的很多選項(xiàng),使用下面命令能夠產(chǎn)生一個(gè)缺省的配置文件:
doxygen -g? [配置文件名]
可以根據(jù)項(xiàng)目的具體需求修改配置文件中對(duì)應(yīng)的項(xiàng),具體的修改過(guò)程在下面介紹。修改過(guò)的配置文件可以作為以后項(xiàng)目的模板。
讓doxygen自動(dòng)產(chǎn)生文檔,平常的注釋風(fēng)格可不行,需要遵循doxygen自己的格式。具體如何寫doxygen認(rèn)識(shí)的注釋在第3節(jié)詳細(xì)介紹。
OK,代碼編完了,注釋也按照格式寫好了,最后的文檔是如何的哪?非常簡(jiǎn)單,運(yùn)行下面的命令,相應(yīng)的文檔就會(huì)產(chǎn)生在指定的目錄中。
??doxygen [配置文件名]
需要注意的是doxygen并不處理所有的注釋,doxygen重點(diǎn)關(guān)注與程序結(jié)構(gòu)有關(guān)的注釋,比如:文件、類、結(jié)構(gòu)、函數(shù)、變量、宏等注釋,而忽略函數(shù)內(nèi)變量、代碼等的注釋。
2. doxygen配置文件
doxygen配置文件的格式是也是通常的unix下配置文件的格式:注釋'#'開始;tag = value [,value2…];對(duì)于多值的情況可以使用 tag += value [,value2…]。
對(duì)doxygen的配置文件的修改分為兩類:一種就是輸出選項(xiàng),控制如何解釋源代碼、如何輸出;一種就是項(xiàng)目相關(guān)的信息,比如項(xiàng)目名稱、源代碼目錄、輸出文檔目錄等。對(duì)于第一種設(shè)置好后,通常所有項(xiàng)目可以共用一份配置,而后一種是每個(gè)項(xiàng)目必須設(shè)置的。下面選擇重要的,有可能需要修改的選項(xiàng)進(jìn)行解釋說(shuō)明,其他選項(xiàng)在配置文件都有詳細(xì)解釋。
TAG?缺省值?含義
PROJECT_NAME??項(xiàng)目名稱
PROJECT_NUMBER??可以理解為版本信息
OUTPUT_DIRECTORY??輸出文件到的目錄,相對(duì)目錄(doxygen運(yùn)行目錄)或者絕對(duì)目錄
INPUT??代碼文件或者代碼所在目錄,使用空格分割
FILE_PATTERNS?*.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp *.h++ *.idl *.odl?指定INPUT的目錄中特定文件,如:*.cpp *.c *.h
RECURSIVE?NO?是否遞歸INPUT中目錄的子目錄
EXCLUDE??在INPUT目錄中需要忽略的子目錄
EXCLUDE_PATTERNS??明確指定的在INPUT目錄中需要忽略的文件,如:FromOut*.cpp
??
OUTPUT_LANGUAGE?English?生成文檔的語(yǔ)言,當(dāng)前支持2、30種語(yǔ)言,國(guó)內(nèi)用戶可以設(shè)置為Chinese
USE_WINDOWS_ENCODING?YES(win版本)
NO(unix版本)?編碼格式,默認(rèn)即可。
EXTRACT_ALL?NO?為NO,只解釋有doxygen格式注釋的代碼;為YES,解析所有代碼,即使沒(méi)有注釋。類的私有成員和所有的靜態(tài)項(xiàng)由EXTRACT_PRIVATE和 EXTRACT_STATIC控制
EXTRACT_PRIVATE?NO?是否解析類的私有成員
EXTRACT_STATIC?NO?是否解析靜態(tài)項(xiàng)
EXTRACT_LOCAL_CLASSES?YES?是否解析源文件(cpp文件)中定義的類
SOURCE_BROWSER?NO?如果為YES,源代碼文件會(huì)被包含在文檔中
INLINE_SOURCES?NO?如果為YES,函數(shù)和類的實(shí)現(xiàn)代碼被包含在文檔中
ALPHABETICAL_INDEX?NO?生成一個(gè)字母序的列表,有很多類、結(jié)構(gòu)等項(xiàng)時(shí)建議設(shè)為YES
GENERATE_HTML?YES?是否生成HTML格式文檔
GENERATE_HTMLHELP?NO?是否生成壓縮HTML格式文檔(.chm)
GENERATE_LATEX?YES?是否乘車latex格式的文檔
GENERATE_RTF?NO?是否生成RTF格式的文檔
GENERATE_MAN?NO?是否生成man格式文檔
GENERATE_XML?NO?是否生成XML格式文檔
??
3. doxygen注釋
3.1 注釋風(fēng)格
下面是工作量最大部分,安裝doxygen格式寫注釋。通常代碼可以附上一個(gè)注釋塊來(lái)對(duì)代碼進(jìn)行解釋,一個(gè)注釋塊由一行或者多行組成。通常一個(gè)注釋塊包括一個(gè)簡(jiǎn)要說(shuō)明(brief)和一個(gè)詳細(xì)說(shuō)明(detailed),這兩部分都是可選的。可以有多種方式標(biāo)識(shí)出doxygen可識(shí)別的注釋塊。
1)JavaDoc類型的多行注釋。
/**
?*? ….text….
?*/
2)QT樣式的多行注釋。
/*!
….text….
?*/
3) /// …text….
4) //! …text….
簡(jiǎn)要說(shuō)明有多種方式標(biāo)識(shí),這里推薦使用@brief命令強(qiáng)制說(shuō)明,例如:
/**
?* @brief [some brief description ]
?*????? [ brief description more. ]
?*
?* [some more detailed description…]
?*/
以上這些注釋格式用來(lái)對(duì)緊跟其后的代碼進(jìn)行注釋。doxygen也允許把注釋放到代碼后面,具體格式是放一個(gè)'<'到注釋開始部分。例如:
int var1 ; /**< ….text…. */
int var2; ///< ….text….
注釋和代碼完全分離,放在其他地方也是允許的,但需要使用特殊的命令加上名稱或者聲明進(jìn)行標(biāo)識(shí),比如:class、struct、union、enum、fn、var、def、file、namespace、package、interface(這些也就是doxygen關(guān)注的注釋類型)。這里不推薦使用,建議注釋盡量放在代碼前后。具體使用方式參見doxygen手冊(cè)。
3.2 doxygen常用注釋格式
通常的選擇上面的一、兩種注釋風(fēng)格,遇到頭文件中各種類型定義,關(guān)鍵變量、宏的定義,在其前或者后使用 @brief 定義其簡(jiǎn)要說(shuō)明,空一行后繼續(xù)寫其詳細(xì)的注釋即可。
對(duì)函數(shù)的注釋,是比較常常需要注釋的部分。除了定義其簡(jiǎn)要說(shuō)明以及詳細(xì)注釋,還可以使用param命令對(duì)其各個(gè)參數(shù)進(jìn)行注釋,使用return命令對(duì)返回值進(jìn)行注釋。常見的格式如下:
/**
?*@brief func's brief comment.
?*
?* Some detailed comment.
?*@param a [param a 's comment.]
?*@param b [param b 's comment.]
?*@exception std::out_of_range [exception's comment.]
?*@return [return's comment.]
?*/
int func1(int a, int b);
進(jìn)行設(shè)計(jì)時(shí),通常有模塊的概念,一個(gè)模塊可能有多個(gè)類或者函數(shù)組成,完成某個(gè)特定功能的代碼的集合。如何對(duì)這個(gè)概念進(jìn)行注釋?doxygen提供了group的概念,生成的模塊的注釋會(huì)單獨(dú)放在一個(gè)模塊的頁(yè)面中。使用下面的格式定義一個(gè)group。
/** [group_name] [brief group description ]
?* detailed group description ]
?* @{
*/
code
/** @} */
group中的代碼可以有自己的注釋。單純定義一個(gè)模塊,去除{ 和}命令即可。任何其他代碼項(xiàng)(比如類、函數(shù)、甚至文件)如果要加入到某個(gè)模塊,可以在其doxygen注釋中使用ingroup命令即可。Group之間使用ingroup命令,可以組成樹狀關(guān)系。
/** @file util.cpp
* @ingroup [group_name]
?* @brief file's brief info.
?*/
把多個(gè)代碼項(xiàng)一起添加到某個(gè)模塊中可以使用addtogroup命令,格式和defgroup相似。
對(duì)于某幾個(gè)功能類似的代碼項(xiàng)(比如類、函數(shù)、變量)等,如果希望一起添加注釋,而又不想提升到模塊的概念,可以通過(guò)下面的方式:
//@{
/** Comments for all below code. */
code…
//@}
對(duì)這種組進(jìn)行命名可以使用name命令。此時(shí)中間代碼可以有自己的注釋。如:
/** @name group_name
?* description for group.
?*/
//@{
code…
//@}
3.3 doxygen常用注釋命令
doxygen通過(guò)注釋命令識(shí)別注釋中需要特殊處理的注釋,比如函數(shù)的參數(shù)、返回值進(jìn)行突出顯示。上面也提到了一些注釋命令(如:brief、param、return、以及group相關(guān)的命令),下面對(duì)其他一些常用的注釋命令進(jìn)行解釋說(shuō)明。
@exception <exception-object> {exception description}?對(duì)一個(gè)異常對(duì)象進(jìn)行注釋。
@warning {warning message }?一些需要注意的事情
@todo { things to be done } ?對(duì)將要做的事情進(jìn)行注釋
@see {comment with reference to other items } 一段包含其他部分引用的注釋,中間包含對(duì)其他代碼項(xiàng)的名稱,自動(dòng)產(chǎn)生對(duì)其的引用鏈接。
@relates <name> 通常用做把非成員函數(shù)的注釋文檔包含在類的說(shuō)明文檔中。
@since {text} 通常用來(lái)說(shuō)明從什么版本、時(shí)間寫此部分代碼。
@deprecated
@pre { description of the precondition } 用來(lái)說(shuō)明代碼項(xiàng)的前提條件。
@post { description of the postcondition } 用來(lái)說(shuō)明代碼項(xiàng)之后的使用條件。
@code 在注釋中開始說(shuō)明一段代碼,直到@endcode命令。
@endcode 注釋中代碼段的結(jié)束。
到此為止,常用的doxygen的注釋格式討論完畢,我們能夠按照一定的格式撰寫doxygen認(rèn)識(shí)的注釋,并能夠使用doxygen方便快捷的生成對(duì)應(yīng)的文檔,不過(guò)注釋中應(yīng)該寫些什么,如何撰寫有效的注釋可能是困擾開發(fā)人員的一個(gè)更深層次的問(wèn)題。
4. 注釋的書寫
注釋應(yīng)該怎么寫,寫多還是寫少。過(guò)多的注釋甚至?xí)蓴_對(duì)代碼的閱讀。寫注釋的一個(gè)總的原則就是注釋應(yīng)該盡量用來(lái)表明作者的意圖,至少也應(yīng)該是對(duì)一部分代碼的總結(jié),而不應(yīng)該是對(duì)代碼的重復(fù)或者解釋。對(duì)代碼的重復(fù)或者解釋的代碼,看代碼可能更容易理解。反映作者意圖的注釋解釋代碼的目的,從解決問(wèn)題的層次上進(jìn)行注釋,而代碼總結(jié)性注釋則是從問(wèn)題的解答的層次上進(jìn)行注釋。
推薦的寫注釋的過(guò)程是首先使用注釋勾勒出代碼的主要框架,然后根據(jù)注釋撰寫相應(yīng)的代碼。對(duì)各種主要的數(shù)據(jù)結(jié)構(gòu)、輸出的函數(shù)、多個(gè)函數(shù)公用的變量進(jìn)行詳細(xì)地注釋。對(duì)代碼中控制結(jié)構(gòu),單一目的的語(yǔ)句集進(jìn)行注釋。下面是一些寫注釋時(shí)需要注意的要點(diǎn):
??避免對(duì)單獨(dú)語(yǔ)句進(jìn)行注釋;
??通過(guò)注釋解釋為什么這么做、或者要做什么,使代碼的讀者可以只閱讀注釋理解代碼;
??對(duì)讀者可能會(huì)有疑問(wèn)的地方進(jìn)行注釋;
??對(duì)數(shù)據(jù)定義進(jìn)行注釋,而不是對(duì)其使用過(guò)程進(jìn)行注釋;
??對(duì)于難于理解的代碼,進(jìn)行改寫,而不要試圖通過(guò)注釋加以說(shuō)明;
??對(duì)關(guān)鍵的控制結(jié)構(gòu)進(jìn)行注釋;
??對(duì)數(shù)據(jù)和函數(shù)的邊界、使用前提等進(jìn)行注釋;
5. 參考資料
?1. doxygen homepage
?http://www.stack.nl/~dimitri/doxygen/
?2. doxygen manual
?http://www.stack.nl/~dimitri/doxygen/manual.html
?3. Code Complete: A Practical Handbook of Software Construction. Redmond, Wa.: Microsoft Press, 880 pages, 1993. ISBN: 1-55615-484-4.
?
?4. 簡(jiǎn)介doxygen
?http://www.stack.nl/~dimitri/doxygen/doxygen_intro_cn.html
?
?5. 10 Minutes to document your code
?http://www.codeproject.com/tips/doxysetup.asp
?6. 使用doxygen
?http://www.csdn.net/Develop/article/16%5C16383.shtm
6. 關(guān)于作者
mounton @ {www.ihere.org} 當(dāng)前關(guān)注于網(wǎng)絡(luò)安全產(chǎn)品的開發(fā)、研究;軟件開發(fā)過(guò)程等方面。您可以通過(guò)mount0n@yahoo.com和他聯(lián)系。