Selected Article

Intro to Doxygen with C++

Posted on: 2025-09-15, Updated on: 2025-09-15 20:56:09 | Read time: 3.7 minutes

Topic(s): programming

Doxygen is a tool that you can use to automate documentation generation for software projects. This guide will focus on setting up and using Doxygen in C++ projects.

Some of the benefits and features of Doxygen are as follows:

Setting Up

To get started, you'll need to install Doxygen and (optionally) Graphviz if you want fancy class diagrams. On Fedora, you can install the needed packages with the following command:

$ sudo dnf install doxygen graphviz

You could also use the development-tools package group which installs Doxygen by default:

$ sudo dnf group install development-tools

On Debian/Ubuntu you can use:

$ sudo apt install doxygen graphviz

Once installed, you can generate a default configuration file for your project with:

$ doxygen -g Doxyfile

This creates a text file called Doxyfile that controls how Doxygen scans your source code and generates documentation. For a small project you can often leave most of the defaults alone, but you'll likely want to update a few key settings:

I'll touch more on the Doxygen configuration file and its relevant options later in this guide.

Once your configuration is ready, generate documentation by running:

$ doxygen Doxyfile

There are a number of ways to structure a software project and C++ is no different. Thankfully, it is fairly easy to configure Doxygen to find your code and other documents.

By default you'll get an DoxyDocs/html/ directory with a browsable website and a DoxyDocs/latex/ directory if you want to produce PDF documents. I'll omit instructions for using the LaTeX documentation, since most likely you won't have a LaTeX distribution installed on your system.

Navigate to the parent of the DoxyDocs/html/ directory and run the following command to open the generate HTML documentation in your web browser:

xdg-open ./DoxyDocs/html/index.html

Documenting Your Code

Doxygen picks up specially formatted comments in your source files. Instead of walking you through each, I figure it will be easiest to just show you one large example. It is possible to Doxygen comments in implementation files (.cpp, .cxx, .cc), but typically it is most important to document the interface (C++ header files: .h, .hpp, .hxx). You could use regular, non-Javadoc style comments for code that isn't part of your public API.

There are a few main comment styles that Doxygen recognizes:

You can create inline comments for member variables using //!<. You can think of the < character as indicating “document the previous element.”

Some of the most common Doxygen comment tags you'll use are:

If you document your classes and methods this way, Doxygen will generate a structured reference for you, including cross-references between files, functions, and classes.

//! BGE namespace.
namespace BGE
{
    class CommandParser; // Forward declare
    BGE_DECLARE_PTR(CommandParser);

    /**
     * @brief A class to parse and handle command-line arguments.
     */
    class CommandParser final
    {
    private: // Internal state
        std::span<std::string_view> m_arguments; //!< List of command-line arguments passed to the program.
        std::unordered_map<std::string, std::string> m_argumentMap; //!< Map of argument name to their corresponding values.
        std::string m_lastError; //!< Stores the last error message encountered during parsing or operations.

        // Bounds checking
        double m_min = std::numeric_limits<double>::lowest(); //!< Minimum allowable value for arguments.
        double m_max = std::numeric_limits<double>::max(); //!< Maximum allowable value for arguments.
        bool m_bMinSet = false; //!< Indicates whether a minimum bound has been set.
        bool m_bMaxSet = false; //!< Indicates whether a maximum bound has been set.
    public:
        /**
         * @brief Constructs a CommandParser with a given list of arguments.
         * @param arguments The command line arguments to be parsed.
         */
        explicit CommandParser(std::span<std::string_view> arguments);

        //! Default constructor.
        ~CommandParser(void) = default;

        /**
         * @brief Checks if an argument exists in the list.
         * @param name The name of the argument to check for.
         * @return true if the argument exists, false otherwise.
         */
        bool Boolean(std::string_view name) const;

        /**
         * @brief Extracts a boolean parameter from the arguments.
         * @param name The name of the parameter to extract.
         * @param bValue Reference to store the extracted boolean value.
         * @return Optional containing a boolean value if successful, empty otherwise.
         */
        std::optional<bool> Boolean(std::string_view name, bool &bValue) const;

        /**
         * @brief Extracts an integer parameter from the arguments.
         * @param name The name of the parameter to extract.
         * @param value Reference to store the extracted integer value.
         * @return Optional containing an integer value if successful, empty otherwise.
         */
        std::optional<int> Integer(std::string_view name, int &value) const;

        /**
         * @brief Extracts a floating-point parameter from the arguments.
         * @param name The name of the parameter to extract.
         * @param value Reference to store the extracted float value.
         * @return Optional containing a float value if successful, empty otherwise.
         */
        std::optional<float> Float(std::string_view name, float &value) const;

        /**
         * @brief Extracts a double-precision floating-point parameter from the arguments.
         * @param name The name of the parameter to extract.
         * @param value Reference to store the extracted double value.
         * @return Optional containing a double value if successful, empty otherwise.
         */
        std::optional<double> Double(std::string_view name, double &value) const;

        /**
         * @brief Extracts a string parameter from the arguments.
         * @param name The name of the parameter to extract.
         * @param value Reference to store the extracted string.
         * @return Optional containing a string value if successful, empty otherwise.
         */
        std::optional<std::string> String(std::string_view name, std::string &value) const;

        /**
         * @brief Extracts a filename parameter from the arguments.
         * @param name Reference to store the extracted filename.
         * @return Optional containing the filename if successful, empty otherwise.
         */
        std::optional<std::string> Filename(std::string &name) const;

        /**
         * @brief Sets the minimum allowable value for arguments.
         * @param value The minimum value to set.
         * @return Reference to the current CommandParser instance.
         */
        CommandParser &Min(double value);

        /**
         * @brief Sets the maximum allowable value for arguments.
         * @param value The maximum value to set.
         * @return Reference to the current CommandParser instance.
         */
        CommandParser &Max(double value);

        /**
         * @brief Sets the strict minimum bound for arguments (exclusive).
         * @param value The bound value to set.
         * @return Reference to the current CommandParser instance.
         */
        CommandParser &Inf(double value);

        /**
         * @brief Sets the strict maximum bound for arguments (exclusive).
         * @param value The bound value to set.
         * @return Reference to the current CommandParser instance.
         */
        CommandParser &Sup(double value);

        /**
         * @brief Detects and counts unprocessed excess arguments.
         * @return The number of unprocessed arguments.
         */
        int ExcessArguments(void) const;

        /**
         * @brief Retrieves the last error message encountered.
         * @return String view of the last error message.
         */
        std::string_view GetLastError(void) const;
    private:
        /**
         * @brief Parses the given list of arguments and initializes the internal state.
         * @param arguments The arguments to parse.
         */
        void ParseArguments(std::span<std::string_view> arguments);
    };
} // End namespace (BGE)

Customizing Doxygen

When you first opened the Doxyfile you created, you likely got overwhelmed by the sheer size (2500+ lines) and amount of configuration options. Thankfully, the Doxygen configuration file template is quite well documented. There are relevant notes above each option with references to related options when appropriate. The Doxyfile has hundreds of options, but a few are especially useful when starting out:

I usually start with the defaults and only enable features as I need them. A smaller configuration makes Doxygen faster to run and keeps the output simple.

NOTE: Since the Doxygen configuration file is quite long, use your text editor's search feature to find relevant items. Searching for items like HTML_ or GENERATE_ can help jump around faster.

There are also numerous settings and ways to change the look and feel of Doxygen output. Here are a few common HTML look-and-feel options:

If want to use an extra CSS stylesheet, first take a look at the doxygen.css file you can see in your HTML output directory. This can give you a better idea of which elements and CSS class are used, so you can make your desired customizations.

Conclusion

img

Doxygen is one of those tools that doesn’t take long to set up, but it pays off quickly once you start documenting your project. Certainly it is quite helpful when you expect other people to use your project, but even if you’re the only one reading the docs, having an automatically generated reference can make it easier to keep track of how your code fits together. Additionally, if you ever decide to publish or share your code, having decent documentation already in place is a big win. Thanks for reading!

Resources:


Post a Comment

Click to generate a new captcha.

0 Comments