# Doxygen入門 [TOC] ## Doxygen簡介 Doxygen是一個document generator。由於其廣泛被使用在許多專案來產生軟體文件,因此可以說其語法已經變成一個標準。 缺點:產生的HTML頁面不適合在mobile device上瀏覽。據說可以透過[Doxygen-Bootstrap](https://github.com/StratifyLabs/Doxygen-Bootstrap)解決。 ## Doxygen安裝 這裡我們只描述在windows系統上安裝doxygen最簡單的方法。我們不依靠windows installer,直接下載[doxygen-1.8.15.windows.bin.zip ](http://doxygen.nl/files/doxygen-1.8.15.windows.bin.zip)並解壓縮到特定目錄。 解壓縮後可以看到目錄裡面包含: - doxygen.exe - doxyindexer.exe - doxysearch.cgi.exe - libclang.dll 四個檔案。我們只需要`doxygen.exe`和`libclang.dll`兩個檔案。 建議除了doxygen以外另外再安裝[GraphViz](https://www.graphviz.org/)。Doxygen可以使用GraphViz內的dot tool來渲染更好的圖表。安裝方法如下: 1. 下載[graphviz-2.38.zip](https://graphviz.gitlab.io/_pages/Download/windows/graphviz-2.38.zip) 2. 解壓縮後,只留下`[graphviz_root]\release\bin`目錄內的東西,甚至`[graphviz_root]\release\bin`內的執行檔除了`dot.exe`以外都可以移除。 3. 之後要記得修改Doxygen的設定檔,將`DOT_PATH`設為`[graphviz_root]\release\bin`,並將`HAVE_DOT`設為`YES`。 ## Doxygen 用法 ### 第一步:建立設定檔 使用doxygen的第一步是先產生設定檔,您可以透過以下命令來產生一個預設的設定檔。 ``` doxygen -g <config-file> ``` 其中`<config-file>`是設定檔的名稱。如果省略檔名,將創建名為Doxyfile的檔案。如果檔名為`<config-file>`的檔案已存在,則doxygen會在生成設定樣版之前將其重命名為`<config-file>.bak`。 您也可以透過以下命令來升級現有的設定檔: ``` doxygen -u <config-file> ``` 設定檔的格式類似於Makefile的格式。它由以下形式的多個對標記(tags)的賦值語句組成: ``` TAGNAME = VALUE or TAGNAME = VALUE1 VALUE2 ... ``` 您可以將生成的樣版設定檔中的大多數標記的值保留為其預設值。 對於包含少量C和/或C ++ source和header files的小專案,可以將[INPUT](http://www.doxygen.nl/manual/config.html#cfg_input)標記留空,並且doxygen將搜索當前目錄中的原始碼檔案。 如果您有一個包含原始碼目錄或原始碼樹的較大專案,則應將根目錄分配給[**INPUT**](http://www.doxygen.nl/manual/config.html#cfg_input)標記,並將一個或多個file patterns添加到**FILE_PATTERNS**標記(例如`*.cpp *.h`)。只有檔案與其中一個pattern匹配才會被解析(如果省略設定**FILE_PATTERNS**標記,則使用doxygen通常支持的檔案類型列表,細節直接看**FILE_PATTERNS**標記上面的註解)。要對source tree進行遞歸解析,必須將**RECURSIVE**標記設置為YES。要進一步微調被解析的檔案列表,可以使用**EXCLUDE**和**EXCLUDE_PATTERNS**標記。 ### 第二步:執行doxygen 設定完成後,要生成文件,您現在可以輸入: ``` doxygen <config-file> ``` 預設輸出目錄是doxygen啟動的目錄。可以使用[OUTPUT_DIRECTORY](http://www.doxygen.nl/manual/config.html#cfg_output_directory)更改輸出的根目錄。可以使用設定檔的[HTML_OUTPUT](http://www.doxygen.nl/manual/config.html#cfg_html_output),[RTF_OUTPUT](http://www.doxygen.nl/manual/config.html#cfg_html_output),[LATEX_OUTPUT](http://www.doxygen.nl/manual/config.html#cfg_latex_output),[XML_OUTPUT](http://www.doxygen.nl/manual/config.html#cfg_xml_output),[MAN_OUTPUT](http://www.doxygen.nl/manual/config.html#cfg_man_output)和[DOCBOOK_OUTPUT](http://www.doxygen.nl/manual/config.html#cfg_docbook_output)標記選擇中特定格式的輸出目錄。如果輸出目錄不存在,doxygen將嘗試為您創建它。 #### HTML output 可以透過HTML瀏覽器開啟html目錄中的`index.html`檔案來查看生成的HTML文件。HTML部分的某些功能(例如如果您開啟了 [GENERATE_TREEVIEW](http://www.doxygen.nl/manual/config.html#cfg_generate_treeview) 設定或搜索引擎)需要支持動態HTML和Javascript的瀏覽器。 ### 第三步:為程式碼撰寫文件 如果設定檔中的[EXTRACT_ALL](http://www.doxygen.nl/manual/config.html#cfg_extract_all) 選項設置為`NO`(預設值),則doxygen將僅為文件化實體(原文是entity,意旨file、namespace、class、function、method、variable、struct、enum...之類的東西)生成文件。那麼你如何文件化這些實體?基本上有兩個方式: 1. 直接在宣告或定義前(有些可以在後面)放置一個特殊註釋區塊 ([Special comment blocks](http://www.doxygen.nl/manual/docblocks.html#specialblock))。對於某些實體,還允許將特殊註釋區塊直接放在實體之後。 譬如: ```c /** * @brief only print "hello world" to the console * */ void hello() { printf("Hello World!\n"); } ``` 這個方式的優點是您不必重複實體的名稱。 2. 在其他地方(另一個檔案或其他位置,只要不是在緊鄰實體前後的地方都算)放置一個特殊註釋區塊,並在特殊註釋區塊中放置一個結構命令(structural command)。該結構命令將註釋區塊鏈結到可以被文件化的特定實體。結構命令是特殊命令的一個子集,我們在Doxygen語法解說的部分會在講解什麼是特殊命令。 譬如您可以在任何一個doxygen能讀取的到的檔案內放置: ```c++ /** @class Test @brief A test class. A more detailed class description. */ ``` 來為一個class添加文件。而且這個特殊註釋區塊無須放在class定義或宣告的前面。 這種方式所需要付出的代價是需要在特殊註解區塊中放置結構命令,這會導致一些訊息重複。所以在實踐中你應該避免使用結構命令,除非其他要求強迫你這樣做。 檔案只能使用第二個選項文件化,是因為無法在"檔案之前"放置特殊註解區塊。 ## Doxygen 語法 ### Markdown doxygen在1.8版後支援了markdown語法。markdown語法與doxygen語法相比簡單許多,所以會建議在單獨文件的部分(意思是非內嵌在原始程式碼註解內的文件)多採用markdown語法。無論如何,doxygen的根基還是使用doxygen語法,即時您是採用markdown語法撰寫文件,也會在doxygen一開始處理時先轉換成對應的doxygen語法再進一步處理。所以了解doxygen語法還是非常的重要。 有關markdown語法的部分直接看[Doxygen Manual: Markdown support](http://www.doxygen.nl/manual/markdown.html)。或者可以看[從無到有學習HackMD](https://www.youtube.com/watch?v=r5FOR-YU33c)順便把HackMD的用法學一學好了。 :::warning 要注意doxygen對markdown有自己的特殊extension,還有就是它的排版方式可能與您所使用的markdown editor (譬如[typora](https://typora.io/))有些微不同。 ::: :::info 會將markdown放在這麼前面提到是因為markdown語法比doxygen語法簡潔多了,而且又有很多WYSIWYG editor support。 ::: ### Special comment blocks Special comment blocks是帶有一些額外標記的C或C++ style comment block,==doxygen只會拿special comment blocks內的內容來產生文件==(副檔名為`.md`和`.markdown`的檔案例外,doxygen會對這兩種副檔名的檔案先採用markdown parser處理)。因此==要利用doxygen語法撰寫文件,一定得先了解special comment blocks有哪些樣式。== 底下介紹了doxygen支持的各種Special comment blocks的樣式。 1. Javadoc style 由`/**`和`*/`包圍的區塊。建議採用此樣式。 範例如下: ```c /** * ... text ... */ ``` 或 ```c /** ... text ... */ ``` 2. Qt style 由`/*!`和`*/`包圍的區塊。 範例如下: ```c /*! * ... text ... */ ``` 或 ```c /*! ... text ... */ ``` 3. C++ comment lines style ```c /// /// ... text ... /// ``` 或 ```c //! //!... text ... //! ``` 4. 浮誇樣式 注意第一行末尾的2斜杠(即`//`)用於結束正常註釋區塊並開始特殊註釋區塊。 ```c /********************************************//** * ... text ***********************************************/ ``` 或 ```c ///////////////////////////////////////////////// /// ... text ... ///////////////////////////////////////////////// ``` ### Putting documentation after members 要文件化file、struct、union、class或enum的成員,有時需要將文件區塊放在成員之後而不是之前。為此,您必須在特殊註釋區塊中額外添加一個`<`標記。請注意,這也適用於函式的參數。 譬如: 1. Javadoc style 建議採用此樣式 ```c int var; /**< Detailed description after the member */ ``` 2. Qt style ```c int var; /*!< Detailed description after the member */ ``` 或 ```c++ int var; //!< Detailed description after the member //!< ``` 或 ```c int var; ///< Detailed description after the member ///< ``` 大多數情況下,人們只想在member後面做一個brief描述。可以這樣做: ```c int var; //!< Brief description after the member ``` 或 (建議採用此樣式) ```c int var; ///< Brief description after the member ``` 對於function的參數,您除了可以用: ```c /** * @brief Your brief descriptions * * @param v[in] docs for input parameter v */ void foo(int v); ``` 也可以寫成inline的型式: ```c void foo(int v /**< [in] docs for input parameter v. */); ``` 以下是使用Javadoc樣式為一個c++ class添加註解的範例: ```c++ /** * A test class. A more elaborate class description. */ class Javadoc_Test { public: /** * An enum. * More detailed enum description. */ enum TEnum { TVal1, /**< enum value TVal1. */ TVal2, /**< enum value TVal2. */ TVal3 /**< enum value TVal3. */ } *enumPtr, /**< enum pointer. Details. */ enumVar; /**< enum variable. Details. */ /** * A constructor. * A more elaborate description of the constructor. */ Javadoc_Test(); /** * A destructor. * A more elaborate description of the destructor. */ ~Javadoc_Test(); /** * a normal member taking two arguments and returning an integer value. * @param a an integer argument. * @param s a constant character pointer. * @see Javadoc_Test() * @see ~Javadoc_Test() * @see testMeToo() * @see publicVar() * @return The test results */ int testMe(int a, const char *s); /** * A pure virtual member. * @see testMe() * @param c1 the first argument. * @param c2 the second argument. */ virtual void testMeToo(char c1, char c2) = 0; /** * a public variable. * Details. */ int publicVar; /** * a function variable. * Details. */ int (*handler)(int a, int b); }; ``` ## Step by Step ### 安裝和基本設定 1. 首先我們先建立一個空目錄,將[doxygen-1.8.15.windows.bin.zip](http://doxygen.nl/files/doxygen-1.8.15.windows.bin.zip)下載後並解壓縮到`d:\doxygen`。 此時`d:\doxygen`目錄下會有以下四個檔案: ``` \doxygen.exe \doxyindexer.exe \doxysearch.cgi.exe \libclang.dll ``` 2. 接著下載[graphviz-2.38.zip](https://graphviz.gitlab.io/_pages/Download/windows/graphviz-2.38.zip),並解壓縮到`d:\doxygen\graphviz-2.38`。 此時`d:\doxygen`目錄下的內容會類似底下這樣: ``` \graphviz-2.38\release\... <- 裡面有一堆檔案 \doxygen.exe \doxyindexer.exe \doxysearch.cgi.exe \libclang.dll ``` 如果要節省空間,`graphviz`的部分可以可以只保留`\graphviz-2.38\release\bin`底下的程式並刪除其餘目錄。甚至`\graphviz-2.38\release\bin`裡面除了`dot.exe`以外的執行檔都可以刪除(但dll、ini等檔案可不要誤刪了)。 3. 在`開始`->輸入`cmd`->開啟`命令提示字元`,利用以下command切換到`d:\doxygen`目錄: ``` d: cd d:\doxygen ``` 4. 輸入`doxygen -g`來產生預設設定檔`Doxyfile`。 5. 用任何純文字編輯工具開啟`d:\doxygen\Doxyfile`,修改以下幾個選項: - PROJECT_NAME - 專案名稱。這裡我們先保留不改。 - PROJECT_NUMBER - 版本編號,譬如`4.3.1`。這裡我們先保留不改。 - OUTPUT_LANGUAGE - 您希望文件以什麼語系產生,您可以改成`Chinese`來產生中文文件。這裡我們先保留不改。 - INPUT - 您想要為其產生文件的程式碼根目錄,譬如`d:\myproject`。這裡我們先保留不改。 - RECURSIVE - 是否要連子目錄的檔案都一起視為input檔案。這裡記得改成`YES`。 - EXCLUDE_PATTERNS - 要排除在外的樣式。我們在這裡宣告我們要排除`graphviz-2.38`和`html`目錄,即: ``` EXCLUDE_PATTERNS = */graphviz-2.38/* \ */html/* ``` - GENERATE_TREEVIEW - 是否要在畫面左半邊顯示樹狀列表。這裡記得改成`YES`。 `GENERATE_TREEVIEW = NO`的畫面: ![GENERATE_TREEVIEW = NO](https://i.imgur.com/4tqygJR.png) `GENERATE_TREEVIEW = YES`的畫面: ![GENERATE_TREEVIEW = YES](https://i.imgur.com/5WGPm6z.png) - GENERATE_LATEX - 是否要產生LATEX,這裡記得改成`NO`。 - HAVE_DOT - 是否有dot tool。因為我們有下載`graphviz`,所以這裡可以改為`YES`。如果沒有安裝`graphviz`,則保持為`NO`。 - DOT_PATH - dot tool的路徑,這裡改成`graphviz-2.38/release/bin`。注意,請採用反斜線`/`表示路徑分隔。 其他設定細節請參考[Doxygen Manual: Configuration](http://www.doxygen.nl/manual/config.html) 6. 在`d:\doxygen`目錄下輸入`doxygen`或`doxygen <config-file>` (如果您的設定檔名稱不是預設的`Doxyfile`)來產生最簡易版本的文件。 如果您有按照上面步驟設定,我們可以看到產生出來的頁面如下: ![Init Document](https://i.imgur.com/5WGPm6z.png) 注意最上排的index列表(doxygen內把`Main Page`那橫排的部分稱為`index`。您可以透過將設定檔的`DISABLE_INDEX`選項設為`YES`把那整條橫排隱藏起來。) 只包含一個`Main Page`頁籤(原文是tab)。後面的講解會逐步加入更多項目。 ### 開始撰寫註解 在開始為程式碼撰寫註釋之前,我們先要瞭解doxygen的兩個很重要的術語: 1. Special comment blocks Special comment blocks是一段區塊,符合以下條件的都屬於special comment blocks: 1. `/**`和`*/`之間的內容 2. `/*!`和`*/`之間的內容 3. `///`後面的內容 4. `//!`後面的內容 只有位於special comment blocks內的內容才會被產生到文件中(副檔名為`.md`和`.markdown`的檔案例外)。 完整的special comment blocks種類請看[Doxygen Manual: Special comment blocks](http://www.doxygen.nl/manual/docblocks.html)。 2. Special commands 位於Special comment blocks內以`\`或`@`符號開頭的字串。該字串會被doxygen當成特殊命令並產生對應的文件。 完整的special commands請看[Doxygen Manual: Special Commands](http://www.doxygen.nl/manual/commands.html)。 #### Example 1: Files/File List/File Members 在這範例中,我們要讓doxygen在`Main Page`頁籤旁邊產生一個`Files`頁籤,並在該頁籤裡面列出被文件化的檔案列表以及檔案內被文件化的成員列表。這也是最容易產生的。 1. 首先,在`D:\doxygen`目錄下先建立一個`math.h`檔案,並填入以下內容: ```c /** * @file * @author MyName (myemail@igoole.com) * @brief A brief description about this file * @version 0.1 * @date 2019-02-25 * * @copyright Copyright (c) 2019 XXX. Inc. All Rights Reserved. * */ #include <stdint.h> /** * @brief Return the largest * @details Returns the largest of a and b. If both are equivalent, a is returned. * * @param[in] a Value to compare. * @param[in] b Value to compare. * @return uint32_t the largest value. */ uint32_t max(uint32_t a, uint32_t b); ``` 2. 接著在`D:\doxygen`內執行`doxygen`。產生出來的畫面如下: ![File brief description](https://i.imgur.com/v0tXSfA.png) 可以看到在原本的`Main Page`頁籤旁邊多了一個`Files`頁籤。 - 裡面的`File List`列出我們剛加入的`math.h`檔案。 - 而`File Members`則列出`All`和`Functions`。 - 左邊的`math.h`列表內列出了我們加入的`max` function。 - 右邊頁面上方列出`math.h`的file brief description和function列表以及每個function的brief description。 - 在右邊頁面下半部則是file和function的detailed description。 ![File detailed description](https://i.imgur.com/hOfvzvo.png) 這邊要注意的是,如果您沒有為`math.h`加上`@file` command,您看到的頁面如下: ![No file description](https://i.imgur.com/x5SX3C5.png) 連`max` function的註解都看不到。這是因為`max` function是`math.h` file的member。如果父實體未被文件化導致未輸出到文件,則其中的成員也跟著不會被輸出到文件。這要特別注意。 #### Example 2: Modules 這範例延續上一個範例,我們在原有的`file.h`中再多加一個`min()` function,並將`max()`和`min()` function一起group到`math` module。 ```c /** * @file * @author MyName (myemail@igoole.com) * @brief A brief description about this file * @version 0.1 * @date 2019-02-25 * * @copyright Copyright (c) 2019 XXX. Inc. All Rights Reserved. * */ #include <stdint.h> /** * @addtogroup math * * @brief brief description about `math` module. * * detailed description about `math` module. * * - Sample code * @code * #include <stdint.h> * * int32_t main() * { * uint32_t a = 1; * uint32_t b = 2; * uint32_t min = min(a, b); * uint32_t max = max(a, b); * * return 0; * } * * @endcode * * @{ */ /** * @brief Return the largest * @details Returns the largest of a and b. If both are equivalent, a is returned. * * @param[in] a Value to compare. * @param[in] b Value to compare. * @return uint32_t the largest value. */ uint32_t max(uint32_t a, uint32_t b); /** * @brief Return the smallest * @details Returns the smallest of a and b. If both are equivalent, a is returned. * * @param[in] a Value to compare. * @param[in] b Value to compare. * @return uint32_t uint32_t the smallest value. */ uint32_t min(uint32_t a, uint32_t b); /** * @} */ ``` 特別要注意的是line 14起的 ``` /** * @addtogroup math * @{ */ ``` 和結尾的 ``` /** * @} */ ``` 這兩個special comment block將其中的內容全部group到`math` module。 產生出來的畫面如下: ![Math Module](https://i.imgur.com/Diwv9ee.png) #### Example 3: Nested Modules 這範例延續上一個範例,我們想進一步把`max()`和`min()`function放到`math` module底下的`compare` module,修改後的結果如下: ```c /** * @file * @author MyName (myemail@igoole.com) * @brief A brief description about this file * @version 0.1 * @date 2019-02-25 * * @copyright Copyright (c) 2019 XXX. Inc. All Rights Reserved. * */ #include <stdint.h> /** * @addtogroup math * * @brief brief description about `math` module. * * detailed description about `math` module. * * @{ */ /** * @addtogroup compare * * @brief brief description about `math::compare` module. * * detailed description about `math::compare` module. * * - Sample code * @code * #include <stdint.h> * * int32_t main() * { * uint32_t a = 1; * uint32_t b = 2; * uint32_t min = min(a, b); * uint32_t max = max(a, b); * * return 0; * } * @endcode * * @{ */ /** * @brief Return the largest * @details Returns the largest of a and b. If both are equivalent, a is returned. * * @param[in] a Value to compare. * @param[in] b Value to compare. * @return uint32_t the largest value. */ uint32_t max(uint32_t a, uint32_t b); /** * @brief Return the smallest * @details Returns the smallest of a and b. If both are equivalent, a is returned. * * @param[in] a Value to compare. * @param[in] b Value to compare. * @return uint32_t uint32_t the smallest value. */ uint32_t min(uint32_t a, uint32_t b); /** * @} */ /** * @} */ ``` 這裡要注意的是line 14~20我們定義了第一層的module `math`。line 23~44我們定義了第二層的module `compare`。由於`compare` module定義在`math` module的`@{...@}` 區塊內,因此變成了`math` module的submodule。 產生出來的頁面如下: ![Module math::comapre](https://i.imgur.com/1xOeTGq.png) #### Example 4: Sections/Subsections 有時候我們想在detail description內描述很長的內容,但希望又有標題和子標題的效果,我們可以利用`Sections`和`Subsections`(其實還有`Subsubsections`)。這裡我們建議使用markdown語法來產生標題和子標題。範例程式碼如下(此範例修改自Example 2): ```c /** * @file * @author MyName (myemail@igoole.com) * @brief A brief description about this file * @version 0.1 * @date 2019-02-25 * * @copyright Copyright (c) 2019 XXX. Inc. All Rights Reserved. * */ #include <stdint.h> /** * @addtogroup math * * @brief brief description about `math` module. * * # Overview * description for section 1 * * ## Subsection 1 of Overview * description for subsection 1 * * ### Subsubsection 1 * description for subsubsection 1 * * ## Subsection 2 of Overview * description for subsection 2 * * # Example * description for section 2 * - Sample code * @code * #include <stdint.h> * * int32_t main() * { * uint32_t a = 1; * uint32_t b = 2; * uint32_t min = min(a, b); * uint32_t max = max(a, b); * * return 0; * } * * @endcode * * @{ */ /** * @brief Return the largest * @details Returns the largest of a and b. If both are equivalent, a is returned. * * @param[in] a Value to compare. * @param[in] b Value to compare. * @return uint32_t the largest value. */ uint32_t max(uint32_t a, uint32_t b); /** * @brief Return the smallest * @details Returns the smallest of a and b. If both are equivalent, a is returned. * * @param[in] a Value to compare. * @param[in] b Value to compare. * @return uint32_t the smallest value. */ uint32_t min(uint32_t a, uint32_t b); /** * @} */ ``` 注意line 18~32之間的內容。我們利用了markdown語法中的`#`符號來幫我們產生Sections/Subsections/Subsubsections。產生出來的畫面如下: ![Sections/Subsections/Subsubsections](https://i.imgur.com/S5SDYAo.png) #### Example 5: Macro 這裡我們示範為Macro產生文件。 範例程式碼如下: ```c /** * @file * @author MyName (myemail@igoole.com) * @brief A brief description about this file * @version 0.1 * @date 2019-02-25 * * @copyright Copyright (c) 2019 XXX. Inc. All Rights Reserved. * */ #include <stdint.h> /** * @brief Computes the maximum of @a a and @a b. * * @param a Value to compare. * @param b Value to compare. * @return the largest value. */ #define MAX(a,b) (((a) >= (b)) ? (a) : (b)) ``` 可以看到註解撰寫方式與function雷同,除了`@return`的部分無須加上回傳型別。 其實還有另一種寫法: ```c /** * @file * @author MyName (myemail@igoole.com) * @brief A brief description about this file * @version 0.1 * @date 2019-02-25 * * @copyright Copyright (c) 2019 XXX. Inc. All Rights Reserved. * */ #include <stdint.h> /** * @def MAX(a,b) * @brief Computes the maximum of @a a and @a b. * * @param a Value to compare. * @param b Value to compare. * @return the largest value. */ /** * Just a dummy function. */ void Dummy(); #define MAX(a,b) (((a) >= (b)) ? (a) : (b)) ``` 這就是分離式寫法,意思是針對實體的特殊註解區塊無須緊鄰著實體的寫法。但不是很建議這樣寫。 呈現畫面如下: ![macro_brief](https://i.imgur.com/BGuTfAF.png) 其實跟Functions很像。 #### Example 6: Struct/Enum 這裡我們示範為Struct和Enum產生文件。 ```c /** * @file * @author MyName (myemail@igoole.com) * @brief A brief description about this file * @version 0.1 * @date 2019-02-25 * * @copyright Copyright (c) 2019 XXX. Inc. All Rights Reserved. * */ #include <stdint.h> /** * A structure to represent 3d vectors */ typedef struct { /** * @brief Brief description of x * @details Detailed description of y */ double x ; double y ; /**< Detailed description of y */ double z ; ///< Brief description of z uint8_t * name ; ///< Detailed description of name ///< int32_t namelength ; //!< Brief description of namelength } point3d ; /** * The enumeration of space dimension */ typedef enum { UND, /**< 1D (detailed description) */ DEUXD, ///< 2D (detailed description) TROISD ///< 3D (detailed description) ///< } dimensions ; ``` :::info 注意enum的部分,無論你用什麼註解樣式,enumerator都只有detailed description。 ::: struct的部分呈現畫面如下: ![struct brief description](https://i.imgur.com/8t4HwiR.png) 有趣的是,stuct的定義被分到classes分類。 #### 自訂類似@warning的效果 修改Doxyfile: ``` ALIASES += context="@par Context" ``` 程式碼註解: ``` /** * @context * single threaded during gadget setup */ ``` ###### tags: `Doxygen`