【Doxygen】Doxygen 快速入门

Doxygen 用了很久了,目前为止确实感觉是最适合作为CPP开发的文档软件了。

因此这里就介绍一下 Doxygen ,写一个快速入门教程。


Doxygen 快速入门

引言

在软件开发的过程中,文档化是一项至关重要的任务。它不仅能帮助开发者理解代码的功能和结构,还能为项目维护者提供清晰的指导,确保项目的持续性和可维护性。

然而,手动编写和维护大量的文档是一项繁琐且容易出错的工作。因此,我们将学习使用自动化文档生成工具Doxygen,以快速生成说明文档。

本文将深入探讨Doxygen的标记用法,帮助读者更好地利用这一工具来生成高质量的代码文档。

我们将逐步介绍如何在代码中使用它们来描述变量、类、函数等实体,并分享一些高级用法和技巧,帮助读者在文档化过程中更加得心应手。

变量注释

单行注释是最基础的注释,在CPP中惯用//,而Doxygen不会对基础注释//生成文档。

一般在编程中变量的描述都比较简洁,往往一行几个字就可以说清,所以变量注释通常用单行注释。

Doxygen 识别特定的单行注释格式来提取信息:

  • 注释下一行的代码:
    • /** 注释 */
    • /// 注释
  • 注释同一行的代码:
    • /**< 注释 */
    • ///< 注释
  • 注释上一行的代码:
    • //! 注释

类注释

类注释基础

类注释通常提供关于类及其成员的全面信息。

通常类定义、命名空间、结构体定义、联合体定义、枚举定义的注释方式是相同的。

Doxygen 支持多种标签来标记这些信息:

  • @ingroup / @addtogroup 加入组:将类添加到该group中,格式为模块名 显示名(可选项)。我们将在下文的组注释中对此进行更详细的介绍。
  • @brief 概要信息: 简要描述类的功能、目的或主要用途。
  • @details 详细描述:提供关于类的更详细描述,包括其实现细节、依赖关系、使用场景等。这部分内容通常比@brief更详尽,可以包含多个段落和子标题。
  • @note 额外信息:用于添加关于类的额外信息或注意事项,可以用来提醒用户某些特殊行为、限制或潜在的陷阱。
  • @remark 评论:作为公共文档。

对于多行信息,可以使用<p>或是空行来表示换行。

写一个CPP的示例:

1
2
3
4
5
6
7
8
9
10
11
/**  
 * @brief 示例类的简要说明    
 * @details 示例类的详细描述
 * 换行
 * @note 注意事项  
 * @remark 评论  
 */
class A
{
    private int x;
};

类注释扩展

对于比较复杂的情况,以上的注释标签可能不足以详细说明。

Doxygen 支持多种扩展标签来进一步标记这些信息:

  • @deprecated 废弃:标记一个类为已废弃。这意味着该类在未来的版本中可能不再被支持或维护,并且建议开发者避免使用它。
  • @exception 异常:用于描述类可能抛出的异常。在这个标签后面,你可以列出类可能抛出的异常类型,并为每个异常提供简短的描述。
  • @warning 警告: 标记潜在问题或风险,提醒用户在使用时特别注意。
  • @attention 注意: 强调某个重要的信息或细节。
  • @bug 漏洞:简要描述目前存在的bug。
  • @todo 待办事项:简要描述未来的更新计划。
  • @see 参照:在注释中创建对其他类、函数、变量、文件或外部URL的引用,在生成的文档中转换成超链接。
    • 引用类中的函数时,如果函数名具有唯一性,可以直接使用类名加上双冒号(::)和函数名。
    • 函数名存在重载(即具有相同名称但参数列表不同的函数),需要带上参数列表以区分不同的重载版本。
  • @code@endcode 代码段:这两个标签用于在注释中插入代码段。@code 开始一个代码块的注释,而 @endcode 结束它。在这两个标签之间的内容会被Doxygen解析为代码,并以适当的格式在生成的文档中显示。这对于展示类的示例用法、算法实现或特定方法的调用方式非常有用。

函数注释

函数注释通常应该详细且全面,包括函数的目的、输入参数、输出参数和返回值。

函数注释中也可以使用上文提到的类注释标签等,可以自由组合注释。

Doxygen 支持多种标签来标记这些信息:

  • @brief 函数描述:简短描述函数的功能。
  • @param 参数:描述函数参数。格式通常为参数名 详细描述
    • @param[in] 输入参数:描述函数的输入参数,用法同上
    • @param[out] 输出参数:描述函数的输出参数,用法同上
  • @return 返回:描述函数的返回值。
    • @retval 返回值:描述特定返回值的意义(当函数返回多种可能的值时很有用,比如用int表示不同错误类型)。
  • @pre 前置条件:描述代码项的前提条件。
  • @post 后置条件:描述代码项的后置条件。

写一个CPP的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**  
 * @brief 反余弦函数
 * @param[in] x 输入参数x
 * @param[out] res 余弦x对应的角度
 * @return :返回是否成功
 * @retval :0 失败
 * @retval :1 成功
 */
bool Acos(double x, double &res) 
{
    if (x < -1.0 || x > 1.0) 
    {  
        return 0;
    }  
    res = std::acos(x);
    return 1;
}

文件注释

文件注释通常放在整个文件开头,提供关于整个文件的概述和相关信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
 * @file 文件名
 * @brief 简介
 * @details 细节
 * @mainpage 工程概览
 * 如果这个文件是整个项目的入口点或主要文档页面,可以使用@mainpage标签。  
 * 在这里,提供关于整个工程的概述、目标、结构和使用说明。 
 * @author 作者
 * @email 邮箱
 * @version 版本号
 * @date 年-月-日
 * @license 版权
 */

组注释

Doxygen中的groups是一个强大的功能,可以将相关的文档实体(如函数、类、变量等)组织在一起,在生成的文档中更清晰地展示它们之间的关系和层次结构。

一个group通常代表一个特定的功能模块、一个库的一部分或一个逻辑上相关的代码集合。

  • @defgroup 定义组:说明该group的目的、功能和使用场景,格式为模块名 显示名
  • @ingroup 加入组:作为子模块将文档实体添加到该group中,格式为模块名 显示名(可选项)
  • @addtogroup 加入组:作为成员将文档实体添加到该group中,格式为模块名 显示名(可选项)

写一个CPP的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**  
 * @defgroup top 所有的组  
 * @brief 所有的组的总集合
 */

/**  
 * @ingroup top
 * @brief 测试类
 */
class A;

/**  
 * @addtogroup top
 * @brief 测试类
 */
class B;

markdown扩展

Doxygen 支持部分 markdown 语法,可以更好的生成说明文档。

表格

markdown的表格中,| 用于分隔单元格,:----: 用于指定列的对齐方式(可选)。每一行数据都由|分隔的单元格组成,单元格之间由空格分隔。

1
2
3
4
| 列1   | 列2   | 列3   |  
| :----: | :----: | :----: |  
| 数据1  | 数据2  | 数据3  |  
| 数据4  | 数据5  | 数据6  |
列1 列2 列3
数据1 数据2 数据3
数据4 数据5 数据6

Doxygen支持markdown的表格语法, 可以如下表示:

1
2
3
4
5
6
7
/**  
 * @brief 测试表格
 * | 列1   | 列2   | 列3   |  
 * | :----: | :----: | :----: |  
 * | 数据1  | 数据2  | 数据3  |  
 * | 数据4  | 数据5  | 数据6  |
 */

列表

在markdown中,可以使用星号(*)或连字符(-)来创建无序列表,使用数字加上点(1.、2.、3.)来创建有序列表。

1
2
3
4
- data1
- data2
1. data1st
2. data2st
  • data1
  • data2
    1. data1st
    2. data2st

Doxygen支持markdown的列表语法, 可以如下表示:

1
2
3
4
5
6
7
/**  
 * @brief 测试列表
 * - data1
 * - data2
 * 1. data1st
 * 2. data2st
*/

用好以上用法,Doxygen就可以生成比较完善的,可读性较强的说明文档了。