Doxgen的安装与使用

背景:使用CCS开发DSP工程时,当随着工程逐渐增大,代码的可读性时逐渐下降的。此时如何能够快速的了解代码工程就显得尤为重要。如果能够解决这个问题,或许也能够约束代码编写时的格式不统一的问题。提升代码的编写质量和可读性。

参考:

  1. Eclipse Doxygen Installation also Code Composer Studio v5.x (coder-tronics.com)

  2. callgraph工具, 函数调用关系 | cflow, egypt 和 doxygen 使用 - whilewell - 博客园 (cnblogs.com)

  3. 相关插件工具:

    1. Doxygen download

    2. Releases · anb0s/eclox (github.com)

    3. Download | Graphviz

实现:

  • 首先参考了第一条的安装过程,先下载并安装了doxygen(1.12.0)软件,并且在CCS的市场中安装了插件eclox(0.13.0)

  • 然后使用对应插件,并配置对应的doxygen工具的安装目录,使用插件建立得到一份doxygen.file文件

  • 编译boxygen文件得到对应的html文件

  • 安装Graphviz工具,手动配置对应工具的bin文件夹路径,然后指定生成图片的格式,深度等细节,再次编译doxygen文件。

  • 重新查看对应的html文件,可以看到对应的说明文件已经更新了插图。(SVG格式比PNG格式要清晰)

​​

参考

  • 能根据代码给出函数调用关系的工具

    • 有一些工具可以分析代码并生成函数调用关系图,帮助你理解代码的结构和函数之间的依赖关系。以下是几种常用的工具:

      1. Doxygen

      • 支持语言:C/C++、Java、Python 等多种语言。

      • 功能:Doxygen 是一个自动生成文档的工具,可以分析代码并生成函数调用关系图。它可以输出多种格式,包括 HTML、LaTeX 和 XML。如果你启用 CALL_GRAPH​ 和 CALLER_GRAPH​ 选项,它还能为每个函数生成调用者和被调用者的图。

      • 使用方法

        1. 编写配置文件 Doxyfile​。

        2. Doxyfile​ 中启用 CALL_GRAPH = YES​ 和 CALLER_GRAPH = YES​。

        3. 运行 Doxygen,它会生成包含函数调用关系的文档。

      2. Gprof

      • 支持语言:C/C++。

      • 功能:Gprof 是一个性能分析工具,能生成程序的函数调用图。它主要用于检测程序的性能瓶颈,但也能展示函数之间的调用关系。

      • 使用方法

        1. 编译程序时加上 -pg​ 选项生成可执行文件。

        2. 运行程序,生成 gmon.out​ 文件。

        3. 使用 gprof​ 分析 gmon.out​ 文件,查看函数调用关系。

      3. Cscope

      • 支持语言:C/C++。

      • 功能:Cscope 是一个交互式的代码浏览工具,可以查找函数的定义、调用、全局变量等信息,适合分析大规模的 C/C++ 项目。

      • 使用方法

        1. 生成索引文件:cscope -R​。

        2. 在 Cscope 的交互界面中查找函数调用关系。

      4. Code2flow

      • 支持语言:Python、JavaScript、Ruby、PHP 等。

      • 功能:Code2flow 是一个简单的工具,可以从代码中生成流程图和调用图,适用于不需要深度分析的小项目。

      • 使用方法

        1. 安装 code2flow​。

        2. 运行 code2flow your_file.py​,工具会生成相应的调用图。

      5. Callgrind (结合 KCachegrind 使用)

      • 支持语言:C/C++。

      • 功能:Callgrind 是 Valgrind 的一个工具,专门用于分析函数调用关系和性能。生成的报告可以用 KCachegrind 可视化,展示函数调用的详细图谱。

      • 使用方法

        1. 使用 valgrind --tool=callgrind ./your_program​ 运行程序。

        2. 生成的 callgrind.out​ 文件可以使用 kcachegrind​ 查看调用关系。

      这些工具各有特点,适合不同语言和场景的需求。如果你是在做 C/C++ 项目,可以考虑 Doxygen 和 Gprof。如果是其他语言,Code2flow 和 Cscope 也是不错的选择。你可以根据具体情况选择合适的工具。

  • Doxygen生成函数调用图

    • Doxygen 是一个非常强大的文档生成工具,它不仅可以为代码生成文档,还可以生成函数调用图。要生成函数调用图,必须正确配置 Doxygen。以下是如何使用 Doxygen 生成函数调用图的详细步骤:

      1. 安装 Doxygen

      首先,你需要确保 Doxygen 已安装在你的系统中。你可以通过以下方式进行安装:

      • Windows:可以从 Doxygen官网 下载可执行安装文件。

      • Linux:通过包管理器安装,例如:

        sudo apt-get install doxygen graphviz
        
      • macOS:使用 Homebrew 安装:

        brew install doxygen graphviz
        

        Graphviz 是一个用于生成图的工具,Doxygen 生成调用图时依赖于它。因此,你还需要安装 Graphviz。

      2. 配置 Doxygen

      Doxygen 通过配置文件 Doxyfile​ 来控制生成文档的行为。你可以通过以下方式生成该文件:

         doxygen -g
      

      这将创建一个名为 Doxyfile​ 的默认配置文件。

      3. 修改 Doxyfile​ 配置文件

      打开 Doxyfile​,并根据需要修改以下选项以启用函数调用图的生成:

      • 启用调用图和调用者图

        CALL_GRAPH = YES          # 生成函数的调用图(显示被哪些函数调用)
        CALLER_GRAPH = YES        # 生成函数的调用者图(显示调用了哪些函数)
        
      • 启用图形输出格式

        HAVE_DOT = YES            # 确保 Graphviz 的 dot 工具可用
        

        如果 HAVE_DOT​ 被设置为 NO​,则需要将其更改为 YES​ 以支持图形生成。

      • 图形显示样式(可选)

        DOT_IMAGE_FORMAT = svg    # 可以选择生成的图形格式,如 png 或 svg
        

        SVG 格式通常质量更好并支持放大缩小操作。

      • 限制图的深度(可选)
        如果你的项目很大,可以设置调用图的最大深度以避免生成过于复杂的图:

        MAX_DOT_GRAPH_DEPTH = 2   # 控制生成图的最大深度
        

      4. 生成文档

      配置好 Doxyfile​ 后,在项目根目录下运行以下命令生成文档:

         doxygen Doxyfile
      

      Doxygen 将自动分析你的源代码,并生成包含函数调用图的 HTML 文档。

      5. 查看生成的函数调用图

      在 Doxygen 生成的文档目录中,打开 index.html​ 文件,通过浏览器访问。如果正确配置,点击某个函数时,它的调用图和调用者图将会显示在页面上。

      • 调用图 (Call Graph):显示当前函数调用了哪些其他函数。

      • 调用者图 (Caller Graph):显示哪些函数调用了当前函数。

      6. 优化图形显示(可选)

      • 调整图的布局

        DOT_GRAPH_MAX_NODES = 50  # 控制图形中的最大节点数,防止图形过于复杂
        DOT_TRANSPARENT = YES     # 使图形背景透明(更易嵌入到网页)
        
      • 函数聚类
        如果你想让相关函数聚集在一起,可以启用函数聚类选项:

        DOT_CLUSTERING = YES
        

      7. 示例调用图

      如果配置成功,生成的调用图可能看起来像这样:

         +--------+    +----------+    +---------+
         | func A | -->| func B    | -->| func C  |
         +--------+    +----------+    +---------+
      

      8. 调试常见问题

      • 调用图未生成:确保 HAVE_DOT​ 设置为 YES​ 并且系统中安装了 Graphviz。

      • 生成的图为空或不完整:检查 MAX_DOT_GRAPH_DEPTH​ 设置,增加图的深度。

      • 图形显示不清晰:尝试将 DOT_IMAGE_FORMAT​ 设置为 svg​ 或其他矢量图格式。

      通过以上步骤,你可以生成函数的调用关系图,帮助你更好地理解项目中的函数调用逻辑。

实例



enum Colors {
    RED = 1,    /**< Represents the color red */
    GREEN = 2,  /**< Represents the color green */
    BLUE = 3    /**< Represents the color blue */
};


/**
 * @brief Adds two integers.
 *
 * @details This function uses simple addition and assumes the input integers are valid.
 * Special care is taken to avoid overflow by ensuring the sum stays within a valid range.
 *
 * @note This function does not check for integer overflow.
 *
 * @param a First integer
 * @param b Second integer
 * @return The sum of a and b
 */
int add1(int a, int b) {
    //! This variable stores the sum of a and b
    int result = 0; /**< The accumulated sum */

    // Add integers with overflow check
    if ((a > 0 && b > 0 && a > INT_MAX - b) || (a < 0 && b < 0 && a < INT_MIN - b)) {
        // Handle overflow case
        return -1; //!< Return error code if overflow occurs
    }

    result = a + b; //!< Perform the addition

    return result; //!< Return the result
}

int add2(int a, int b) {
    int result = 0; /**< The variable that stores the sum of a and b */

    result += a; /**< Add the value of a to the result */
    result += b; /**< Add the value of b to the result */

    return result; /**< Return the calculated sum */
}

/**
 * @brief Adds two integers.
 *
 * This function takes two integers and returns their sum.
 *
 * @param a First integer
 * @param b Second integer
 * @return The sum of a and b
 */
int add3(int a, int b) {
    //! Initialize the result variable to zero.
    int result = 0;

    //! Add the first integer to the result.
    result += a;

    //! Add the second integer to the result.
    result += b;

    //! Return the final result.
    return result;
}


/**
 * @brief Adds two integers.
 *
 * @details
 * This function uses the following local variables:
 * - `result`: Stores the sum of the two input integers.
 *
 * @param a First integer
 * @param b Second integer
 * @return The sum of a and b
 */
int add4(int a, int b) {
    int result = 0; // Local variable to store the sum

    result += a;
    result += b;

    return result;
}


/**
 * @brief Computes the average of an integer array.
 *
 * This function takes an array of integers and its size as input, and returns
 * the average of the array elements. It handles cases where the array is empty.
 *
 * @details
 * The function iterates over the array to compute the sum of its elements.
 * If the array is empty, it returns 0 to avoid division by zero.
 * 
 * Local variables used in this function:
 * - `sum`: Accumulates the sum of array elements.
 * - `i`: Loop counter for iterating through the array.
 *
 * Example usage:
 * @code
 * int arr[] = {1, 2, 3, 4, 5};
 * double avg = compute_average(arr, 5);
 * printf("Average: %f\n", avg);
 * @endcode
 *
 * @param arr The input array of integers.
 * @param size The number of elements in the array.
 * @return The average of the array elements. If the array is empty, returns 0.
 * 
 * @note The return value is of type `double` to allow for decimal averages.
 */
double compute_average(const int* arr, size_t size) {
    //! Sum of the array elements
    int sum = 0;

    //! Loop counter to iterate through the array
    size_t i;

    // If the array is empty, return 0 to avoid division by zero
    if (size == 0) {
        return 0.0;
    }

    // Sum all elements in the array
    for (i = 0; i < size; ++i) {
        sum += arr[i];
    }

    //! Return the computed average as a double
    return (double)sum / size;
}



/**
 * @brief Adds two integers.
 *
 * @details This function uses simple addition and assumes the input integers are valid.
 * Special care is taken to avoid overflow by ensuring the sum stays within a valid range.
 *
 * @note This function does not check for integer overflow.
 *
 * @param a First integer
 * @param b Second integer
 * @return The sum of a and b
 */
int add6(int a, int b) {
    int result = 0; /**< The accumulated sum */

    // Add integers with overflow check
    if ((a > 0 && b > 0 && a > INT_MAX - b) || (a < 0 && b < 0 && a < INT_MIN - b)) {
        // Handle overflow case
        return -1; //!< Return error code if overflow occurs
    }

    result = a + b; //!< Perform the addition

    return result; //!< Return the result
}



int add7(int a, int b) {
    int result = 0; /**< The variable that stores the sum of a and b */

    result += a; /**< Add the value of a to the result */
    result += b; /**< Add the value of b to the result */

    return result; /**< Return the calculated sum */
}


/**
 * @defgroup GeometricShapes Geometric Shape Calculations
 * @brief This module handles the calculations of areas for geometric shapes like circles, squares, and triangles.
 *
 * The functions in this module compute the areas of various geometric shapes by using their respective formulas.
 * @{
 */

/**
 * @brief Initializes the system to compute geometric areas.
 *
 * This function can be used to set up any necessary initial values before computing the areas of shapes.
 */
void init_area_computation(void) {
    shape_count = 0;  // Initialize shape counter
}

/** @} */  // End of GeometricShapes group



/**
 * @brief Computes the area of a circle.
 *
 * This function takes a pointer to a `Circle` structure and calculates its area using the formula:
 * @f$ Area = \pi \times radius^2 @f$.
 * 
 * @f[
 * Area = \pi \times radius^2
 * @f]
 *
 * @param[in] circle A pointer to the `Circle` structure containing the radius.
 * @return The area of the circle.
 */
double compute_circle_area(const Circle* circle) {
    return PI * circle->radius * circle->radius;
}







/**
 * @file example.h
 * @brief This file contains definitions, function prototypes, and data structures
 *        for a simple system that computes geometric shapes' areas.
 * 
 * This file demonstrates how to use Doxygen to document a C header file.
 * It includes macros, structures, function prototypes, and enumeration types.
 * 
 * @author John Doe
 * @date 2024-10-11
 */


/**
 * @def PI
 * @brief The mathematical constant Pi (3.14159...).
 *
 * This macro defines the value of Pi, which is used in geometric calculations.
 */
#define PI 3.141592653589793


/**
 * @enum ShapeType
 * @brief Defines the types of geometric shapes.
 *
 * This enumeration is used to specify the type of shape, 
 * such as a circle, square, or triangle.
 */
typedef enum {
    SHAPE_CIRCLE,   /**< Circle shape */
    SHAPE_SQUARE,   /**< Square shape */
    SHAPE_TRIANGLE  /**< Triangle shape */
} ShapeType;

/**
 * @struct Triangle
 * @brief Represents a triangle with a base and height.
 *
 * This structure stores the base and height of a triangle for area calculations.
 */
typedef struct {
    double base;   /**< The base length of the triangle */
    double height; /**< The height of the triangle */
} Triangle;




/**
 * @struct Circle
 * @brief Represents a circle with a radius.
 *
 * This structure is used to store the radius of a circle for area calculations.
 */
typedef struct {
    double radius; /**< The radius of the circle */
} Circle;

/**
 * @struct Square
 * @brief Represents a square with a side length.
 *
 * This structure stores the side length of a square for area calculations.
 */
typedef struct {
    double side_length; /**< The length of one side of the square */
} Square;



/**
 * @var shape_count
 * @brief Keeps track of the number of shapes processed.
 *
 * This global variable is incremented every time a new shape's area is computed.
 */
int shape_count = 0;


/**
 * @brief Computes the area of a square.
 *
 * This function calculates the area of a square based on its side length.
 *
 * @param[in] square A pointer to the `Square` structure containing the side length.
 * @return The area of the square.
 */
double compute_square_area(const Square* square) {
    return square->side_length * square->side_length;
}

/**
 * @brief Computes the area of a triangle.
 *
 * This function computes the area of a triangle using the formula:
 * @f$ Area = \frac{1}{2} \times base \times height @f$.
 *
 * @param[in] triangle A pointer to the `Triangle` structure containing the base and height.
 * @return The area of the triangle.
 */
double compute_triangle_area(const Triangle* triangle) {
    return 0.5 * triangle->base * triangle->height;
}

在使用 Doxygen 生成文档时,函数内的注释可以通过特定的标记来实现。Doxygen 支持在函数内部添加详细的说明,解释代码逻辑、变量用途或步骤等。这些注释将显示在生成的文档中,帮助开发者理解函数的实现细节。

以下是几种常见的函数内注释方式:

1. 使用 //!​ 或 ///

可以在函数体内直接使用 //!​ 或 ///​ 注释每个逻辑部分。例如:

好的,下面是一个全面的 C 语言项目注释示例,包含了常见的 Doxygen 注释用法,涵盖文件、函数、变量、结构体、枚举、宏定义、以及组(modules)等内容。这样你可以在实际项目中参考使用,确保所有重要元素都得到充分注释和文档化。

### 文件注释

‍‍```c
/**
 * @file example.h
 * @brief This file contains definitions, function prototypes, and data structures
 *        for a simple system that computes geometric shapes' areas.
 * 
 * This file demonstrates how to use Doxygen to document a C header file.
 * It includes macros, structures, function prototypes, and enumeration types.
 * 
 * @author John Doe
 * @date 2024-10-11
 */

宏定义注释

/**
 * @def PI
 * @brief The mathematical constant Pi (3.14159...).
 *
 * This macro defines the value of Pi, which is used in geometric calculations.
 */
#define PI 3.141592653589793

枚举类型注释

/**
 * @enum ShapeType
 * @brief Defines the types of geometric shapes.
 *
 * This enumeration is used to specify the type of shape, 
 * such as a circle, square, or triangle.
 */
typedef enum {
    SHAPE_CIRCLE,   /**< Circle shape */
    SHAPE_SQUARE,   /**< Square shape */
    SHAPE_TRIANGLE  /**< Triangle shape */
} ShapeType;

结构体注释

/**
 * @struct Circle
 * @brief Represents a circle with a radius.
 *
 * This structure is used to store the radius of a circle for area calculations.
 */
typedef struct {
    double radius; /**< The radius of the circle */
} Circle;

/**
 * @struct Square
 * @brief Represents a square with a side length.
 *
 * This structure stores the side length of a square for area calculations.
 */
typedef struct {
    double side_length; /**< The length of one side of the square */
} Square;

/**
 * @struct Triangle
 * @brief Represents a triangle with a base and height.
 *
 * This structure stores the base and height of a triangle for area calculations.
 */
typedef struct {
    double base;   /**< The base length of the triangle */
    double height; /**< The height of the triangle */
} Triangle;

全局变量注释

/**
 * @var shape_count
 * @brief Keeps track of the number of shapes processed.
 *
 * This global variable is incremented every time a new shape's area is computed.
 */
int shape_count = 0;

函数注释

/**
 * @brief Computes the area of a circle.
 *
 * This function takes a pointer to a `Circle` structure and calculates its area using the formula:
 * @f$ Area = \pi \times radius^2 @f$.
 *
 * @param[in] circle A pointer to the `Circle` structure containing the radius.
 * @return The area of the circle.
 */
double compute_circle_area(const Circle* circle) {
    return PI * circle->radius * circle->radius;
}

/**
 * @brief Computes the area of a square.
 *
 * This function calculates the area of a square based on its side length.
 *
 * @param[in] square A pointer to the `Square` structure containing the side length.
 * @return The area of the square.
 */
double compute_square_area(const Square* square) {
    return square->side_length * square->side_length;
}

/**
 * @brief Computes the area of a triangle.
 *
 * This function computes the area of a triangle using the formula:
 * @f$ Area = \frac{1}{2} \times base \times height @f$.
 *
 * @param[in] triangle A pointer to the `Triangle` structure containing the base and height.
 * @return The area of the triangle.
 */
double compute_triangle_area(const Triangle* triangle) {
    return 0.5 * triangle->base * triangle->height;
}

组(Modules)注释

为了组织代码,你可以使用 Doxygen 的 @defgroup​ 和 @addtogroup​ 标签将相关函数、结构体等归为一组,便于文档阅读。

/**
 * @defgroup GeometricShapes Geometric Shape Calculations
 * @brief This module handles the calculations of areas for geometric shapes like circles, squares, and triangles.
 *
 * The functions in this module compute the areas of various geometric shapes by using their respective formulas.
 * @{
 */

/**
 * @brief Initializes the system to compute geometric areas.
 *
 * This function can be used to set up any necessary initial values before computing the areas of shapes.
 */
void init_area_computation(void) {
    shape_count = 0;  // Initialize shape counter
}

/** @} */  // End of GeometricShapes group

main.c 中的代码示例

为了结合所有的注释,以下是一个主程序文件中使用这些函数的示例。

#include "example.h"

int main(void) {
    Circle circle = {5.0};       // Circle with radius 5.0
    Square square = {4.0};       // Square with side length 4.0
    Triangle triangle = {3.0, 6.0}; // Triangle with base 3.0 and height 6.0

    init_area_computation();

    double circle_area = compute_circle_area(&circle);
    double square_area = compute_square_area(&square);
    double triangle_area = compute_triangle_area(&triangle);

    printf("Circle Area: %f\n", circle_area);
    printf("Square Area: %f\n", square_area);
    printf("Triangle Area: %f\n", triangle_area);

    return 0;
}

其他注释标签

  1. @param​ 和 @return​:用于注释函数参数和返回值。

  2. @file​:用于文件级别的注释。

  3. @struct​ 和 @typedef​:用于结构体和类型定义。

  4. @brief​:简要描述。

  5. @details​:详细描述。

  6. @note​:给出提示或注意事项。

  7. @code​ 和 @endcode​:用于嵌入代码示例。

  8. @ingroup​:将元素添加到组中。

总结

这是一套完整的 Doxygen 注释示例,展示了如何为 C 语言中常见的元素(如文件、函数、变量、结构体、枚举、宏和组)进行注释。使用这些注释方式,可以确保生成的文档清晰、全面,方便团队协作和代码维护。


### 2. 使用 `/**<` 在变量声明中注释

如果想对函数内部局部变量进行注释的话应该怎么办

最后得到的只是写的注释,并没有给出局部变量的名字

对于函数内的变量,您可以使用 `/**<` 来直接注释变量的声明,帮助读者了解每个变量的作用:

int add(int a, int b) {
int result = 0; /**< The variable that stores the sum of a and b */

result += a; /**< Add the value of a to the result */  
result += b; /**< Add the value of b to the result */

return result; /**< Return the calculated sum */  

}


### 3. 使用 `@details` 和 `@note`

对于较为复杂的函数,可以使用 `@details` 和 `@note` 来解释函数中的特定细节或提醒:

/**

  • @brief Adds two integers.

  • @details This function uses simple addition and assumes the input integers are valid.

  • Special care is taken to avoid overflow by ensuring the sum stays within a valid range.

  • @note This function does not check for integer overflow.

  • @param a First integer

  • @param b Second integer

  • @return The sum of a and b
    */
    int add(int a, int b) {
    int result = 0; /**< The accumulated sum */

    // Add integers with overflow check
    if ((a > 0 && b > 0 && a > INT_MAX - b) || (a < 0 && b < 0 && a < INT_MIN - b)) {
    // Handle overflow case
    return -1; //!< Return error code if overflow occurs
    }

    result = a + b; //!< Perform the addition

    return result; //!< Return the result
    }


### 小结

在函数内部添加详细的注释有助于提升代码的可读性和维护性,Doxygen 支持多种注释格式,可以根据项目需求灵活选择。

如果最后生成的文档显示的公式是 `$ Area = \pi \times radius^2 $` 而不是公式的数学格式,可能是 Doxygen 没有正确识别 LaTeX 公式的标记。为了让 Doxygen 正确地显示数学公式,可以尝试以下几种解决方案:

### 1. 确保使用正确的 `@f$` 标签

Doxygen 支持 LaTeX 公式,但它需要你使用正确的标签格式。如果你想让公式显示为数学格式,应该用 `@f$` 来标记公式的开始和结束。例如:

/**

  • @brief Computes the area of a circle.

  • The area of a circle is given by the formula:

  • @f$Area = \pi \times radius^2 @f$.

  • @param[in] radius The radius of the circle.

  • @return The area of the circle.
    */
    double compute_circle_area(double radius) {
    return PI * radius * radius;
    }


在生成文档时,Doxygen 会识别 `@f$` 标签并将其转换为 LaTeX 格式,显示为:

[\\text{Area} \= \\pi \\times \\text{radius}\^2]

### 2. 使用 `@f[` 和 `@f]` 包围公式

如果公式较长或你想换行,可以使用 `@f[` 和 `@f]` 标签将整个公式包围起来,生成更加清晰的数学公式表示。例如:

/**

  • @brief Computes the area of a circle.

  • The area of a circle is calculated as:

  • @f[

  • Area = \pi \times radius^2

  • @f]

  • @param[in] radius The radius of the circle.

  • @return The area of the circle.
    */
    double compute_circle_area(double radius) {
    return PI * radius * radius;
    }


这样,公式将会被识别为块状公式,并正确渲染。

### 3. 确保 Doxygen 配置支持 LaTeX

Doxygen 需要特定的配置才能正确处理 LaTeX 公式:

* 打开 `Doxyfile`,确保以下设置启用:
  * `USE_MATHJAX = YES` 让 Doxygen 使用 MathJax 来渲染数学公式。
  * 如果没有 MathJax,你可以设置 `LATEX_OUTPUT = YES`,以确保 LaTeX 能被正确编译成 PDF 或 HTML 格式。

USE_MATHJAX = YES
MATHJAX_FORMAT = HTML


### 4. 确保 MathJax 或 LaTeX 环境可用

* 如果生成 HTML 文档并希望公式正确显示,你需要确保 MathJax 脚本能够正常加载。如果是生成 PDF,你需要 LaTeX 环境来正确编译数学公式。

### 结论

总结来说,确保使用 `@f$` 标签正确标记公式,并且检查 Doxygen 的配置文件是否启用了 MathJax 或 LaTeX 支持。

效果图

image