Doc Tools for C++ Libraries

July 6, 2021
Olivier Goffart and Simon Hausmann

Our GUI Toolkit, SixtyFPS, supports multiple programming languages with a shared runtime library. One of these is C++, with a modern API and documentation. To generate that documentation, we looked around for different tools that the C++ community provides. In this article we discuss three of the many tools that are out there: Hyde, Standardese, and the combination of Doxygen + Breathe + Exhale + Sphinx.

Objectives

Let's look at the following key features:

  1. There needs to be a way to write documentation for each part of a public C++ API (namespaces, classes, etc.) and integrate it into the reference.
  2. We need a way to create links, between items in the reference and to outside content. For example if a function returns a particular type, the user can click on that type to go straight to the documentation for it.
  3. It's necessary to be able to exclude private class members, selected types, or entire namespaces that are mere implementation details and not public API.
  4. The tool needs to be able to combine API documentation with conceptual content such as overviews, build instructions, or examples - into one cohesive package that can be served on the web.

Hyde

Hyde is hosted at https://github.com/adobe/hyde. Below is a screenshot of the API reference for the stlab libraries, powered by Hyde:

Screenshot of Hyde Output
Screenshot of the stlab API documentation generated by Hyde

Hyde is written in C++ itself, and is typically built from source, using CMake, and runs on macOS and Linux. The input to the tool is your C++ API, for example a header file. The output is a structure of markdown files, each with a section of YAML meta-data at the top. A site generator like Jekyll consumes these files and prepares them for serving as static HTML.

Workflow

Unlike other tools, Hyde does not extract inline documentation from your C++ code. Instead, Hyde creates a set of files upon first run, to which developers need to add documentation. As the API changes, Hyde is run again, and updates the existing files, and adds new ones for new classes for example. You can also use the validation mode to verify that the documentation structure is in sync with the C++ API - a good feature for use with continuous integration systems.

Evaluation

So how does Hyde contribute to our objectives?

Standardese

Next in line is Standardese, a tool that aims to be the "nextgen Doxygen": https://github.com/standardese/standardese. Its output is by default markdown. This is how it looks like when applied to the SixtyFPS C++ Interpreter API documentation:

Screenshot of Standardese Markdown
Screenshot of the SixtyFPS C++ Interpreter API documentation generated by Standardese

Standardese is also written in C++. While it is straight-forward to build with CMake, there is also an official Docker image (standardese/standard) that makes it very convenient to run from anywhere. The input is your C++ API as a header file and the output are plain markdown files.

Workflow

Standardese follows the more traditional approach of parsing your C++ code and extracting the documentation from comments within. Inside the comments markdown is expected, no inline HTML is supported.

Evaluation

Doxygen + Breathe + Exhale + Sphinx

Last, but not least, we're going to take a brief look at a popular combination of tools that work together: Doxygen, Sphinx, with the Breathe and Exhale extensions. Doxygen is the the "Volkswagen Beetle" under the C++ documentation tools: It's been around for many years and it's very reliable. Sphinx is the documentation generator that's very popular in the vibrant Python 🐍 community. Combined with two extensions this is what we're using for SixtyFPS at the moment:

Screenshot of Sphinx Site with Doxygen Integration
Screenshot of the SixtyFPS C++ documentation site generated by Doxygen, Sphinx and Breathe

Workflow

The setup for this combination starts at Sphinx. It is driven by a central configuration file (conf.py), comes with many plugins and different themes. The input is reStructuredText. We use the Exhale extension to automatically launch Doxygen, which parses the C++ API and produces a generic XML file structure. These XML files are consumed by the Breathe extension to produce reStructuredText. The sphinx-build command is driving this entire process, and the output is a directory structure of HTML (and CSS, etc.) that is suitable for direct serving on the web.

Doxygen does the heavy lifting of extracting the documentation from comments in the C++ code. It has its own configuration file with many ways of customizing its behavior.

Evaluation

The setup of these tools is fairly complex, many different projects need to play well together. However, so far, it is also the most flexible solution that ticks our boxes:

Conclusion

All of these tools do a very good job at supporting the latest C++ standards, as they can all use clang for parsing. They are also actively developed by their communities and they are all Open Source. Their setup differs in complexity, as well as their ability to customize the look and feel of the output. What this means for C++ library developers is that they have a decent choice of different tools available to create the best, integrated documentation packages.

We recognize as well that there are more tools out there, the above is just a set of three that we looked at a bit closer. Join us in the GitHub discussion and let us know what your experience is with documenting your C++ library, what tools you prefer and what you might have found on the horizon of upcoming tools that we should all keep an eye on.