Sphinx

Sphinx is a documentation tool that is commonly used for writing code documentation (especially for python projects). It uses restructured text as the format for writing the documentation and compiles it into HTML, LaTeX/PDF, … It can also highlight code syntax.

Tip

These course notes are all written using Sphinx

Despite its python origins, sphinx can be used with Doxygen via Breathe to allow for nice looking sphinx documentation to provide the C++ documentation Doxygen generates.

Setting It Up

We can install Sphinx locally via:

pip3 install sphinx sphinx_rtd_theme breathe --user

Tip

On the MathLab machines, python 2 is the default, which is why we are using pip3 here, to ensure that we get python 3.

Tip

For some reason, the MathLab machines don’t include ~/.local/bin in your Unix path, so we need to manually add it via:

export PATH=~/.local/bin:$PATH

Now we want to change our code documentation from our handwritten index.html to a site generated by Sphinx. We’ll take over the docs/ directory:

cd docs/
rm index.html

Then, in the docs/ directory:

sphinx-quickstart

Answer the following:

  • Separate source and build directories (y/n) [n]: : answer y

  • Project name: : answer “C++ Array”

  • Author names(s): : answer “PHY 504”

  • Project release []: : just hit enter

  • Project language [en]: : just hit enter

You should now have the following files:

build/
make.bat
Makefile
source/

you can delete make.bat.

To test things out, do:

make html

Then you can view the default page via:

google-chrome build/html/index.html

Customizing our page

There are two important files in source/

  • conf.py : this controls the configuration of Sphinx

  • index.rst : this is the ReST file that will become index.rst.

Configuration

Let’s start by changing the configuration a bit:

  • in the extensions section, change it to read:

    extensions = ["breathe"]
    
  • change html_theme to be:

    html_theme = "sphinx_rtd_theme"
    

Index

Let’s have the index.rst page link to a page showing how the library works.

Create a file using.rst with the following content:

***********
Using Array
***********

``Array.H`` provides a simple 2-d contiguous array.  We can use it as:

.. code:: c++

   #include <iostream>

   #include "array.H"

   int main() {

       // create a 10x10 array

       Array x(10, 10);

       for (std::size_t row=0; row < x.nrows(); ++row) {
           for (std::size_t col=0; col < x.ncols(); ++col) {
               x(row, col) = static_cast<double> (10*row + 100*col + 13);
           }
       }

       std::cout << x << std::endl;

       std::cout << "x.min() = " << x.min() << std::endl;

       // create a 4x3 array but fill it by looping over a flattened
       // view

       Array y(4, 3);

       double c{0};
       for (auto &e : y.flat()) {
           e = c;
           c += 1;
       }

       std::cout << y << std::endl;

Then add to index.rst just after the contents using, so it reads like:

.. toctree::
   :maxdepth: 2
   :caption: Contents:

   using

Let’s add what we’ve do so far to our git:

git add Makefile source/conf.py source/index.rst source/using.rst
git commit

We now need to change our GitHub action to build this new site and copy it over to the gh-pages branch.

In the .github/workflows/gh-pages.yml file, change the sections:

- name: Build Doxygen
  run: |
       mkdir docs
       doxygen Doxyfile

- name: Deploy
  uses: peaceiris/actions-gh-pages@v3
  with:
    github_token: ${{ secrets.GITHUB_TOKEN }}
    publish_dir: ./docs
    keep_files: true

to

- name: Build Sphinx
  run: |
       cd docs
       make html
       cd ..
       mkdir -p out
       mv docs/build/html/* out/

- name: Deploy
  uses: peaceiris/actions-gh-pages@v3
  with:
    github_token: ${{ secrets.GITHUB_TOKEN }}
    publish_dir: ./out
    keep_files: true

This does 3 things:

  • It switches to building the sphinx pages via make html

  • It creates a top-level directory called out/ and puts all of the web site there

  • It instructs the “Deploy” process to copy out to gh-pages now

Tip

Commit and push these changes and in a minute or two, the project webpage should be regenerated to reflect the Sphinx layout.

Using Doxygen with Sphinx

Now we’ll try to combine Doxygen and Sphinx.

Tip

The Sphinx breathe extension allows us to incorporate Doxygen documentation into Sphinx sites.

  1. Move Doxyfile into docs/ and change the following:

    • change OUTPUT_DIRECTORY to doxy_files

    • change INPUT to ../

    • Turn off HTML and turn on XML – Breathe works off of the XML output.

  2. Update our conf.py to include Breathe and also run Doxygen for us. Here’s the updated conf.py:

    # Configuration file for the Sphinx documentation builder.
    #
    # This file only contains a selection of the most common options. For a full
    # list see the documentation:
    # https://www.sphinx-doc.org/en/master/usage/configuration.html
    
    # -- Path setup --------------------------------------------------------------
    
    # If extensions (or modules to document with autodoc) are in another directory,
    # add these directories to sys.path here. If the directory is relative to the
    # documentation root, use os.path.abspath to make it absolute, like shown here.
    #
    # import os
    # import sys
    # sys.path.insert(0, os.path.abspath('.'))
    
    import subprocess
    
    # run doyxgen
    
    subprocess.call("cd ..; doxygen", shell=True)
    
    # -- Project information -----------------------------------------------------
    
    project = 'C++ Array'
    copyright = '2022, PHY 504'
    author = 'PHY 504'
    
    
    # -- General configuration ---------------------------------------------------
    
    # Add any Sphinx extension module names here, as strings. They can be
    # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
    # ones.
    extensions = ["sphinx.ext.autodoc", "breathe"]
    
    # Add any paths that contain templates here, relative to this directory.
    templates_path = ['_templates']
    
    # List of patterns, relative to source directory, that match files and
    # directories to ignore when looking for source files.
    # This pattern also affects html_static_path and html_extra_path.
    exclude_patterns = []
    
    
    # -- Options for HTML output -------------------------------------------------
    
    # The theme to use for HTML and HTML Help pages.  See the documentation for
    # a list of builtin themes.
    #
    html_theme = 'sphinx_rtd_theme'
    
    # Add any paths that contain custom static files (such as style sheets) here,
    # relative to this directory. They are copied after the builtin static files,
    # so a file named "default.css" will overwrite the builtin "default.css".
    html_static_path = ['_static']
    
    
    breathe_projects = { "cxx_array": "../doxy_files/xml/" }
    breathe_default_project = "cxx_array"
    
  3. Create a doxygen_files.rst in source/ with the following:

    Doxygen Files
    =============
    
    .. doxygenindex::
       :project: cxx_array
    
  4. Update index.rst by adding the following:

    .. toctree::
       :maxdepth: 1
       :caption: API
    
       doxygen_files
    

We don’t need to do any changes to our GitHub workflow. We should be able to just add these new files / changes, commit, and push, and the website will be updated.