Lei Mao bio photo

Lei Mao

Machine Learning, Artificial Intelligence, Computer Science.

Twitter Facebook LinkedIn GitHub   G. Scholar E-Mail RSS

Introduction

In my previous blog post, I discussed how to create documentations for Python development using Sphinx. For creating documentations for C/C++ development, Doxygen is more widely used and technically easier to use. I have created a trivial Triangle C++ library, which is equivalent to the Triangle Python library I used for the Sphinx Python documentation blog post, and used Doxygen for creating documentations.


Unlike Sphinx which uses several reStructuredText files and source code for creating documentations, all the documentation content generated using Doxygen seems to be only from the source code. In this blog post, I would like to briefly describe how to create documentations using Doxygen and host it on Read the Docs.

Triangle C++ Library

The C++ trianglelib could be found in the Doxygen C++ TriangleLib on my GitHub. The documentation corresponding to this project could be found on Read the Docs.


The installation of the library and the building of the documentation could be found in the READMEs in the repository.

Notes

Doxyfile Configurations

There are a couple of things in the Doxyfile that might or must be configured.

Variable Description
PROJECT_NAME Project name.
PROJECT_NUMBER Project version number.
PROJECT_BRIEF One sentence description about the project.
OUTPUT_DIRECTORY The output directory for the documentation builds.
FULL_PATH_NAMES Set to NO.
INPUT The directory for the source code to be documented. Usually it only contains header files.
RECURSIVE Whether recursively go through the INPUT.
GENERATE_XML Set to YES if we would like to have Sphinx-styled documentations.

C++ Docstrings

The Doxygen C++ docstrings are not complicated. VS Code extension Doxygen Documentation Generator could also be used for generating the docstring template.

/**
 * @brief Triangle class used for triangle manipulations.
 */
class Triangle
{
public:
    /**
     * Create a new Triangle object of side lengths 1, 1, and 1.
     * @brief Default constructor.
     * @see Triangle(const double a, const double b, const double c)
     * @see Triangle(const Triangle& triangle)
     */
    Triangle();
    /**
     * Create a new Triangle object from side lengths.
     * @brief Constructor.
     * @param a The Length of triangle side a.
     * @param b The Length of triangle side b.
     * @param c The Length of triangle side c.
     * @see Triangle()
     * @see Triangle(const Triangle& triangle)
     */
    Triangle(const double a, const double b, const double c);
    /**
     * Construct a new Triangle object from another Triangle object.
     * @brief Copy constructor.
     * @param triangle Another Triangle object.
     * @see Triangle()
     * @see Triangle(const double a, const double b, const double c)
     */
    Triangle(const Triangle& triangle);

    /**
     * @brief Get the length of side a.
     * @return The length of side a.
     */
    double getSideA() const;

    /**
     * @brief Get the length of side b.
     * @return The length of side b.
     */
    double getSideB() const;

    /**
     * @brief Get the length of side c.
     * @return The length of side c.
     */    
    double getSideC() const;

    /**
     * @brief Get a vector of the Triangle objects whose side lengths have been rotated.
     * @return A vector of Triangle objects.
     */
    std::vector<Triangle> rotations() const;

    /**
     * @brief Assignment overloading.
     * @param triangle Another Triangle object.
     * @return The reference to the current Triangle object.
     */ 
    Triangle& operator=(const Triangle& triangle);
    
    /**
     * @brief Equivalence overloading.
     * @param triangle another Triangle object.
     * @return Whether the two Triangle objects are the same.
     */     
    bool operator==(const Triangle& triangle) const;

    /**
     * @brief Determine if the Triangle object is equivalent to the other.
     * @param triangle Another Triangle object.
     * @return Whether the two Triangle objects are the same.
     */ 
    bool isEquivalent(const Triangle& triangle) const;
    /**
     * @brief Determine if the Triangle object is similar to the other.
     * @param triangle Another Triangle object.
     * @return Whether the two Triangle objects are similar.
     */ 
    bool isSimilar(const Triangle& triangle) const;
    /**
     * @brief Determine if the Triangle object is quilateral.
     * @return Whether the Triangle objects is equilateral.
     */ 
    bool isEquilateral() const;
    /**
     * @brief Determine if the Triangle object is isosceles.
     * @return Whether the Triangle objects is isosceles.
     */ 
    bool isIsosceles() const;

    /**
     * @brief Get the perimeter of the Triangle object.
     * @return The perimeter of the Triangle object.
     */ 
    double perimeter() const;
    /**
     * @brief Get the area of the Triangle object.
     * @return The area of the Triangle object.
     */ 
    double area() const;

    /**
     * @brief Create a new scaled Triangle object.
     * @return A new scaled Triangle object.
     */ 
    Triangle scale(const double factor) const;

private:
    /**
     * Lengths of side a, b, and c.
     */ 
    double mA, mB, mC;
};

/**
 * @brief Create a Triangle object
 * @param a The Length of triangle side a.
 * @param b The Length of triangle side b.
 * @param c The Length of triangle side c.
 * @return A Triangle object.
 */
Triangle createTriangle(const double a, const double b, const double c);

/**
 * @brief Determine if the three lengths provided could form a valid Triangle object.
 * @param a The Length of triangle side a.
 * @param b The Length of triangle side b.
 * @param c The Length of triangle side c.
 * @return true if the three lengths provided could form a valid Triangle object.
 * @return false if the three lengths provided could not form a valid Triangle object.
 */
bool isTriangle(const double a, const double b, const double c);

Main Page

Create a main page description somewhere in the source code that Doxygen reads.

/** 
 * @mainpage Triangle Library Documentation
 * @section intro_sec Introduction
 * This is the Triangle C++ library for C++ Documentation Tutorial.
 * @section install_sec Installation
 *
 * @subsection install_dependencies Installing Dependencies
 * Do somethings ...
 * @subsection install_library Installing Library
 * Do somethings ...
 * @subsection install_example Installing Examples
 * Do somethings ...
 */

Sphinx Configurations

Sphinx is not required for Doxygen documentation generation. However, if we want to host the Doxygen documentations on Read the Docs for free, we have to use Sphinx to generate the Doxygen-styled documentation.


We need to create an empty Sphinx project, and add the following Python code to the Sphinx conf.py.

import subprocess
subprocess.call('make clean', shell=True)
subprocess.call('cd ../../doxygen ; doxygen', shell=True)
html_extra_path = ['../../doxygen/build/html']

It is nothing special but asking the OS to call doxygen to generate the Doxygen documentation HTML and copy it to the Sphinx build directory.

Version Control

As far as I can see, the Doxygen documentation hosted on Read the Docs has limited support for version control. I was only able to switch versions by changing the documentation URL, and there is no version control widget, which is usually seen in the Sphinx documentation hosted on Read the Docs, generated.

  • https://doxygen-c-trianglelib.readthedocs.io/en/latest/
  • https://doxygen-c-trianglelib.readthedocs.io/en/v1.0/
  • https://doxygen-c-trianglelib.readthedocs.io/en/v1.1/

Themes

As far as I know, Doxygen does not have as many themes as Sphinx has.

Final Remarks

Comparing with Sphinx, Doxygen is relatively simpler to use. This is because, although Doxygen supports reStructuredText and Markdown, it is not required to deal with them during documentation generation. However, without spending too much effort investigating the advanced features of Doxygen, the Doxygen documentation does not look as comprehensive as the Sphinx documentation.

References