CPP / C++ Notes - Doxygen - Documentation Generator

Table of Contents

1 Doxygen Documentation Generator

1.1 Overview

Doxygen is a tool that can generate project documentation in html, pdf or Latex from code comments formatted with Doxygen markup syntax. The generated documentation makes easier to navigate and understand the code as it may contain all public functions, classes, namespaces, enumerations, side notes and code examples.

Supported Languages besides C++:

  • C
  • C++
  • Fortran
  • Objective-C
  • C#
  • PHP
  • Python
  • IDL (Corba, MIDL - Microsft Interface Definition Language)
  • VHDL
  • Tcl
  • D-Language (Not full support)

Online Examples of Doxygen Documentation:

Other C++ Documentation Generators:

  • Github: foonathan/standardese
  • QT5 QDoc (No well documented, lack examples.)
    • Creator: QT Company
    • "QDoc is a tool used by Qt Developers to generate documentation for software projects. It works by extracting QDoc comments from project source files and then formatting these comments as HTML pages or DITA XML documents. QDoc finds QDoc comments in .cpp files and in .qdoc files. QDoc does not look for QDoc comments in .h files."
  • NaturalDocs (Basic support for C++, full support only for C#.)
    • "Natural Docs lets you document code written in any of 20 programming languages, plus it can be easily extended for more so whatever you use, it can too. And if your project uses multiple languages, no problem! It will all be included in the same set of documentation."
    • Supported Languages: https://www.naturaldocs.org/languages/
  • Sphinx
  • ROBODoc - Official Web Site

Other Documentation Generators:

  • Pydoc - Python standard documentation generator.
  • Ddoc - Documentation Generator for D-language (Walter Bright)

See also:

1.2 Installing Doxygen

Windows:

Installation via Chocolately package manager:

$ choco install doxygen.portable --version 1.8.9.1

Installing via scoop package manager:

$ scoop install doxygen

Installing 'doxygen' (1.9.0) [64bit]
doxygen-1.9.0.windows.x64.bin.zip (22.6 MB) [==================================] 100%
Checking hash of doxygen-1.9.0.windows.x64.bin.zip ... ok.
Extracting doxygen-1.9.0.windows.x64.bin.zip ... done.
Linking ~\scoop\apps\doxygen\current => ~\scoop\apps\doxygen\1.9.0
Creating shim for 'doxygen'.
Creating shim for 'doxyindexer'.
Creating shim for 'doxysearch.cgi'.

Linux Distributions

Fedora Linux:

$ sudo dnf install doxygen.x86_64

Ubuntu or Debian Linux:

$ sudo apt-get install doxygen 

1.3 Doxygen Tags Ref Card

Tags for Documenting File

Note: Those tags should be placed at top of file.

Tag Description
@file <FILENAME> File Name
@author <AUTHOR_NAME> Author name
@brief <BRIEF> Short description
@date <DATE> Date

Example: => File: IDownloader.hpp

/** 
 *  @file   IGraphicsContext.hpp 
 *  @brief  Graphics Context Interface 
 *  @author Somebody else 
 *  @date   2012-02-20 
 ***********************************************/

class IGraphicsContext 
{
    virtual ~IGraphicsContext() = default;
    virtual void draw() const = 0;
    virtual void dawLine(const Point& p1, Point& p2) = 0;
};  

Tags for Documenting Functions, Classes, Methods and so on

Tag Description
  General Description
@brief Brief description of class or function (fits a single line)
@details Details about class or function
@author <AUTHOR NAME> Insert author name
  Function Or Method Documentation
@param <PARAM> <DESCR> Function or method parameter description
@param[in] <PARAM> <DESCR> Input parameter (C-function)
@param[out] <PARAM> <DESCR> Output paramter of C-style function that returns multiple values
@param[in, out] <PARAM> <DESCR> Parameter used for both input and output in a C-style function.
@tparam <PARAM> <DESCR> Template type parameter
@trhow <EXCEP-DESCR> Specify exceptions that a function can throw
@pre <DESCR> Pre conditions
@post <DESCR> Post conditions
@return <DESCR> Description of return value or type.
  Code Blocks
@code … <C++-Code>… @encode C++ code example.
  Miscellaneous
@remark Additional side-notes
@note Insert additional note
@warning  
@see SomeClass::Method Reference to some class, method, or web site
@li Bullet point
@todo <TODO-NOTE> TODO annotation, reminders about what is still needs to be done.
   

1.4 Doxyfile Settings

This section provides suitable settings for the Doxygen configuration file Doxyfile generated with the command $ doxygen -g or with the application DoxyWizard.

Set project name:

PROJECT_NAME           = "MyProject"

Set project description:

PROJECT_BRIEF          = "Library for loading C++ classes from C or any C-compatible FFI."

Set Input directory

  • Directory containing source code to be scanned. In this case, this directory is set to ./src which contains all source code src/main.cpp, src/class1.hpp, class1.cpp and so on. The default value of the entry INPUT is the current directory where is the Doxyfile.
# The INPUT tag is used to specify the files and/or directories that contain
# documented source files. You may enter file names like myfile.cpp or
# directories like /usr/src/myproject. Separate the files or directories with
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.

INPUT                  = ./src 

Set Output directory:

  • Set the directory where html or latex documentation will be generated.
# Generates the index.html page at ./docs/html/index.html 
OUTPUT_DIRECTORY       = ./docs 

Force code to be regarded as C++ code:

  • Explanation: Header files intended to be used by both C and C++ between the statements _ifdef __cplusplus ... #endif can be understood by Doxygen as C-code, not C++ code. So, any class, struct, namespace of function defined in this namespace will be discarded. The solution to this shortcoming is to notify Doxygen that the macro __cplusplus is defined.
# The PREDEFINED tag can be used to specify one or more macro names that are
# defined before the preprocessor is started (similar to the -D option of e.g.
# gcc). The argument of the tag is a list of macros of the form: name or
# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
# is assumed. To prevent a macro definition from being undefined via #undef or
# recursively expanded use the := operator instead of the = operator.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.

PREDEFINED             = __cplusplus

Disable Latex Documentation Generation:

  • Disabling Latex - makes the generation of documentation faster. Besides that, processing Latex requires a huge number of dependencies.
GENERATE_LATEX         = NO

Entry: Distribute group doc:

# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
# tag is set to YES then doxygen will reuse the documentation of the first
# member in the group (if any) for the other members of the group. By default
# all members of a group must be documented explicitly.
# The default value is: NO.

DISTRIBUTE_GROUP_DOC   = YES

Extract everything from source code

  • This option is useful for undestandign new code.
# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
# documentation are documented, even if no documentation was available. Private
# class members and static file members will be hidden unless the
# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
# Note: This will also disable the warnings about undocumented members that are
# normally produced when WARNINGS is set to YES.
# The default value is: NO.

EXTRACT_ALL            = YES

Source browser

  • Useful for navigating and understanding unfamiliar code.
# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
# generated. Documented entities will be cross-referenced with these sources.
#
# Note: To get rid of all source code in the generated output, make sure that
# also VERBATIM_HEADERS is set to NO.
# The default value is: NO.

SOURCE_BROWSER         = YES 

# Setting the INLINE_SOURCES tag to YES will include the body of functions,
# classes and enums directly into the documentation.
# The default value is: NO.

INLINE_SOURCES         = YES 

1.5 Example

1.5.1 Overview

Files: Gist with full Code

Getting the sample code:

$ git clone https://gist.github.com/caiorss/b04df92734c93e300658285d0b76ed07 example-doxygen 
Cloning into 'example-doxygen'...
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 4 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (4/4), done.

$ cd example-doxygen  
$ ls
Doxyfile  mathutils.hpp

Generate html documentation:

$ doxygen Doxyfile 

Notice: Output directory `./docs' does not exist. I have created it for you.
Searching for include files...
Searching for example files...
Searching for images...
Searching for dot files...
Searching for msc files...
Searching for dia files...
Searching for files to exclude
Searching INPUT for files to process...
Searching for files in directory /home/archbox/root-scripts/example-doxygen
Reading and parsing tag files
Parsing files
Preprocessing /home/archbox/root-scripts/example-doxygen/mathutils.hpp...
Parsing file /home/archbox/root-scripts/example-doxygen/mathutils.hpp...
Building group list...

... ... ... ... 

Generating file member index...
Generating example index...
finalizing index lists...
writing tag file...
lookup cache used 46/65536 hits=123 misses=47
finished...

List generated documentation:

$ ls
docs/  Doxyfile  mathutils.hpp

$ tree docs -L 2
docs
├── html
│   ├── annotated.html
│   ├── bc_s.png
│   ├── bdwn.png
│   ├── classes.html
│   ├── classMathUtils_1_1XYChart.html
│   ├── classMathUtils_1_1XYChart-members.html
│   ├── closed.png
│   ├── doc.png
│   ├── doxygen.css
  ... ... ... ... ... ... 
│   ├── tab_a.png
│   ├── tab_b.png
│   ├── tab_h.png
│   ├── tabs.css
│   ├── tab_s.png
│   └── todo.html
  ... ... ... ... ... ... 

3 directories, 62 files

Open documentation in the browser:

$ firefox docs/html/index.html 

If the project Doxyfile configuration file does not exist, a default one can be generated with Doxygen:

$ doxygen -g  # Default output file "Doxyfile"
$ doxygen -g  OutputFile.cof

1.5.2 Type Aliases

Simple type alias:

/// Mathematical function of type double
using MathFunc = std::function<double (double)>;

Output:

doxygen-alias-MathFunc.png

Figure 1: Documentation of type alis MathFunc

Templated type alias

/// Generic math function
/// @tparam T Any float-point type such as float, double or long double
template<class T>
using MathFuncGen = std::function<T (T)>;

doxygen-alias-MathFuncGen.png

Figure 2: Documentation of type alias MathFunGen

1.5.3 Enumeration MathErrorCode

Enumeration code (file: mathutils.hpp):

/// @brief Mathematical error code 
enum class MathErrorCode: std::uint32_t {
     /// Bit 0 (value 0x00 or 0) not set => Means no error 
     E_OK          = 0x00,
     /// bit 0 (value 0x01 or 1) means that an error of any type happened
     E_ERROR       = 0x01,
     /// bit 1 (value 0x02 or 2) Overflow error 
     E_OVERFLOW    = 0x02,
     /// bit 2 (value 0x04 or 4) Undeflow error 
     E_UNDERFLOW   = 0x04,
     /// bit 3 (value 0x08 or 8) Not a number
     E_NAN         = 0x08,
     /// bit 4 (value 0x10 or 16) Root, series or algorithm result doesn't converge.
     E_CONVERGENCE = 0x10,
     /// bit 5  (value 0x20 or 16) Maximum iterations reached 
     E_MAX_ITER    = 0x20   
};  

Output:

doxygen-enum-MathErrorCodeA.png

Figure 3: Doxygen enumeration MathErrorCode - A

doxygen-enum-MathErrorCodeB.png

Figure 4: Doxygen enumeration MathErrorCode - B

1.5.4 Function NewtonSolver

File: mathutils.hpp

/** @brief Contains non-linear equations solvers */
namespace MathUtils::Solvers{
    // Note: Nested namespaces are only available in C++17.
    using namespace MathUtils::Base;

    /**
     *  @brief Solves non-linear equation with Newton method.
     *
     *  @details
     *   Solves a non-linear equation using the Newton method which uses the  
     *   function and its derivate function for finding a suitable approximation 
     *   to the equation root. 
     *
     *  @see   MathUtils::Base::MathFunc
     *  @see   https://en.wikipedia.org/wiki/Newton%27s_method
     *  @todo  Implement unit test with lots of test cases.
     * 
     *  @param fun  Non-linear function f(x)
     *  @param dfun Derivative of non-linear function df(x) = d/dx f(x)
     *  @param x0   Initial guess 
     *  @param eps  Tolerance for stopping criteria. 
     *  @return     Equation result object containing result and error code.
     */
    MathResult
    NewtonSolver(MathFunc fun, MathFunc dfun, double x0, double eps);

   ... ... ...      ... ... ...      ... ... ...      ... ... ... 

Output:

doxygen-function-solver1.png

Figure 5: Documentation generated for function NewtonSolver

1.5.5 Templated Function GenericNewtonSolver

File: mathutils.hpp

/** @brief Contains non-linear equations solvers */
namespace MathUtils::Solvers{
   ... ....    ... ....    ... .... 

   ///  @brief Solves non-linear equation with Newton method.
   ///
   ///  @tparam T   Any float-point type such as float, double or long double
   ///  @param fun  Non-linear function f(x)
   ///  @param dfun Derivative of non-linear function df(x) = d/dx f(x)
   ///  @param x0   Initial guess 
   ///  @param eps  Tolerance for stopping criteria. 
   ///  @return     Equation result as a float point type T.
   ///
   ///  @details
   ///  Solves non-linear equation using Newton method. This function needs two
   ///  functions, the function to be solved @p fun and its derivate @p dfun
   /// 
   ///  @note     The function f(x) must be continues and differentiable.
   ///  @warning  Throws NonCoverge exception when the root is not found.
   /// 
   ///  @see NewtonSolver
   ///  @see https://en.wikipedia.org/wiki/Newton%27s_method    
   ///
   ///  Example: 
   ///  @code 
   ///    // Solve f(x) = x^2 - 25.0 , df(x) = 2x around x0 = 10.0
   ///    auto fun = [](double x){ return x * x -  25.0 };
   ///    auto dfun = [](double x){ return 2 * x; }
   ///     
   ///    double root = GenericNewtonsolver(fun, dfun, 10.0, 0.001);
   ///    std::cout << "Root = " << root << std::endl;
   ///  @endcode
   ///  
  template<typename T>  
  auto GenericNewtonSolver(MathFuncGen<T> fun, MathFuncGen<T> dfun, T x0, T eps) -> T;

} // --- End of Namespace  MathUtils::Solvers ----//

Output:

doxygen-fun-GenericNewtonSolver1.png

Figure 6: Documentation of function GenericNewtonSolver - part 1

doxygen-fun-GenericNewtonSolver2.png

Figure 7: Documentation of function GenericNewtonSolver - part 2

1.5.6 C-Function daxpy

/**  @brief C++ implementation of Fotran BLAS daxypy       
     Computes the equation ys[i] <- xs[i] * alpha + beta     

     @note Function with C-linkage. 

     @param[in]      n      Array size. Size of xs and ys
     @param[in]      xs     Input  array xs
     @param[in, out] ys     Output array ys    
     @param[in]      alpha  Linear coefficient 
     @return         Void 
  */
extern "C"
auto daxpy(size_t n, double const* xs, double* ys, double alpha, double beta) -> void;

Output:

doxygen-fun-daxpy1.png

Figure 8: C-Function daxpy

1.5.7 Class XYChart

/// @brief Class for plotting cuves, equations and differential equations.
/// @author Ghost Author 
class XYChart{
public:
    /// @brief Construct plot object with a given dimension.
    ///
    /// @pre The chart size must not be negative. 
    ///
    /// @param width  Initial XYChart width
    /// @param height Initial XYChart length
    /// 
    XYChart(double width, double length);

    /// Class destructor 
    virtual ~XYChart() = default;

    /// @brief Clear chart
    /// @details Clear all drawings and plots in the chart area.
    virtual void clear();

    /// @brief Add curve x[i], y[i] to chart
    ///
    /// @pre  Precondition: the arrays x[] and y[] must have size n.
    /// @post There are no post conditions.
    /// 
    /// @param n  array size
    /// @param x  array of x-coordinates values 
    /// @param y  array of y-coordinates values 
    /// @return   Void
    ///
    /// @details
    /// Plot the curve compriseds of points P[i] = (X[i], Y[i]),
    /// where i = 0, 1, 2... n - 1.
    ///
    void addCurve(size_t n, const double x[], const double y[]);

    /// Copy constructor 
    XYChart(Plotter const&) = delete;
    /// Copy-assignment operator 
    XYChart& operator=(XYChart const&) = delete;
private:
};

Output:

doxygen-class-XYChart1.png

Figure 9: Documentation of class XYChart - part 1

doxygen-class-XYChart2.png

Figure 10: Documentation of class XYChart - part 2

Constructor

/// @brief Construct plot object with a given dimension.
///
/// @pre The chart size must not be negative. 
///
/// @param width  Initial XYChart width
/// @param height Initial XYChart length
/// 
XYChart(double width, double length);

Output:

doxygen-class-XYChart3.png

Figure 11: Documentation of class XYChart - Constructor - part 3

Method addCurve

/// @brief Add curve x[i], y[i] to chart
///
/// @pre  Precondition: the arrays x[] and y[] must have size n.
/// @post There are no post conditions.
/// 
/// @param n  array size
/// @param x  array of x-coordinates values 
/// @param y  array of y-coordinates values 
/// @return   Void
///
/// @details
/// Plot the curve compriseds of points P[i] = (X[i], Y[i]),
/// where i = 0, 1, 2... n - 1.
///
void addCurve(size_t n, const double x[], const double y[]);

doxygen-class-XYChart4.png

Figure 12: Documentation of class XYChart - Member function addCurve - part 3

Created: 2022-04-28 Thu 17:00

Validate