Sphinx and CMake: Beautiful Documentation For C++ Projects

by eric. 2 Comments

Let’s face it, documentation for (most) developers is boring and more often than not this is reflected in the quality of a project’s documentation. This is often a barrier that prevents adoption of otherwise well crafted projects in wide-spread production use. In this article we’ll take a look at how to integrate a documentation generator called Sphinx into an existing CMake based project for documentation that is regenerated each time you build the source.

Sphinx is a handy Python based utility that can take plain text documents and generate beautiful documentation in rich formats such as HTML or PDF with just a minimal amount of markup to indicate things like headers or code blocks. The Restructured Text format, the simple markup format used in the plain text documents, is very simple to use and allows anyone, including non-developers to help contribute to documentation efforts. For an example of Sphinx generated documentation check out the SWGANH project documentation.

The CMake tool makes creating and building C/C++ applications across multiple platforms a snap. In this guide I assume that you already have an existing CMake based project where you want to integrate documentation.

Generating a Sphinx configuration

To get started lets create a directory to store the documentation at and an intial document for testing things out. From the root of your project create a docs folder with a test.rst file inside. Add the following to the test.rst file.

Next open a command prompt and navigate to the docs directory that was just created. You can also shift+right click on the directory and choose “Open command window here”. The run the following to create the initial configuration and index file.

sphinx-quickstart

Choose all the default options and enter your project name and author when prompted. Once this has been completed you can remote the make.bat and Makefile that were generated, we will handle this process through CMake (optionally you can choose No for the last two questions to prevent these from being generated). You can also remove the “_” prefixed directories as these are not needed currently either.

Finally open the index.rst file that was generated and edit to add the test document previously created to the documentation index.

Now lets get the CMake project ready to build the documentation.

Finding the Sphinx executable

In order to do anything with Sphinx your project build needs to know where to find it. In CMake terms, this means a call to find_package.

In order to properly find the package you need to create a script as there is no official support for this yet. Below is an example of what this script should look like.

Save this to a file called FindSphinx.cmake in the same location as any other custom CMake scripts you may be using. If you are not using any custom CMake scripts then I suggest creating a “cmake” directory in the project root and adding the file there. You will then need to make CMake aware of this new directory when loading scripts by adding the following to your top level script (just after the project command).

You can now use the find_package command to find the Sphinx executable.

Note that the REQUIRED flag is optional. For now though, do not add this command, we’ll take care of that in the next section.

Creating a Sphinx Target

Now its time to create a CMakeLists.txt in the docs directory that will direct CMake on how to use Sphinx to generate the documentation.

This script sets a few variables for optionally specifying a theme and the theme directory (more on this shortly). It also sets a few directories based on Sphinx conventions, you can change these to taste.

The real meat of the script is in the configure_file and add_custom_target commands. The add_custom_target command uses the Sphinx executable that was previously found to generate html documentation. This is simply invoking the command line Sphinx build tool, so you can update this command to suit your specific needs (such as also generating PDF documentation). Be sure to update the name of the target from my_project_docs to something appropriate for your project.

With the configure_file command CMake allows the ability of copying a file from the source directory to the binary directory, as well as allowing the replacement of CMake variables within the text by encasing the variable name in @@ (e.g. @variable_name@). We will use this capability to dynamically generate a conf.py for Sphinx, allowing users to configure “everything” via CMake.

Rename the the conf.py file that was generated previously to conf.py.in and update the following lines.

Then remove the sections of the configuration for LaTeX and manual page output and save the file.

That’s it! You will now find a my_project_docs project (or whatever you have renamed the docs target to) that will generate documentation for you on each build whenever changes have been made.

You can navigate to (ROOT_BINARY_DIR)/html/index.html (or /html/Debug/index.html on Visual Studio platforms) to view the generated documentation.

Building Boost.Python for Python 3.2

by eric. 1 Comment

Boost.Python is an excellent tool for exposing C++ code to Python. Building Boost with support for the latest version of Python is not that difficult but as most unix systems ship with Python 2.7 or earlier the default options are generally not sufficient.

To start out, make sure that you have the latest version of Python installed. On Ubuntu or debian based environments this is as simple as running the following command.

sudo apt-get install python3-dev

Download and unpack the latest version of Boost then run the following command to bootstrap the Boost build and let it know the appropriate version of python to use.

./bootstrap.sh --with-python=python3.2

Now that the environment is ready you can build boost by simply running the b2 command.

./b2
sudo ./b2 install

Due to a bug in the bootstrap.sh file the Python root is not detected. For builds using the Ubuntu package version of Python this is not a problem, however, if you have installed Python to a non-standard location then you may get compile errors. In that case open up the project-config.jam file and add the path to the Python root as in the example below.

python : 3.2 : /usr ;

That’s all there is to it! The following shows an example python module generated via Boost.Python. Save the below text to a file called greet_binding.cpp.

Compile the example code with the following options. (Based on Ubuntu’s packaged Python 3.2)

g++ greet_binding.cpp -I/usr/include/python3.2 -I/usr/local/include -lboost_python3 -lpython3.2mu -o greet.so -shared

Now the newly built module is ready to use. To test it out start an instance of the python console and run the following.

>>> import greet
>>> greet.say_greeting("Eric")
Hello, Eric!

Installing Jenkins on Ubuntu Server

by eric. 0 Comments

Jenkins is an excellent platform for managing automated builds and getting started on Ubuntu Server is a snap. This guide covers the setup of Jenkins as well as how to use the default Ubuntu Apache web-server installation as a front-end to make URL’s nicer.

Installing Jenkins

Installing Jenkins itself is pretty straightforward using default package system:

sudo apt-get install jenkins

After the installation completes you can access the Jenkins installation at http://SERVER_IP:8080/

 Configuring Apache

With Jenkins now running lets do something to hide the port at the end. Maybe somewhere down the road you’ll want to change the port that Jenkins runs on (as 8080 is a commonly used port), hiding this detail away allows for changes in the future without anyone needing to update their bookmarks.

In this example http://builds.mydomain.com is the target URL where Jenkins should be accessed. First, create a new available site to configure Apache to route requests for this domain to Jenkins.

sudo touch /etc/apache2/sites-available/builds-mydomain

Open this file and add the following configuration.

<VirtualHost *:80>
    ServerName builds.mydomain.com

    ProxyPass / http://localhost:8080/
    ProxyPassReverse / http://localhost:8080/
    ProxyRequests Off

    <Proxy http://localhost:8080/*>
        Order deny,allow
        Allow from all
    </Proxy>
</VirtualHost>

Using mod_proxy Apache is able to forward requests back and forth via the specified ServerName entry. After saving the configuration enable the site and then reload the Apache configuration.

sudo a2ensite builds-mydomain
sudo service apache2 reload

There you have it, a simple setup for a powerful continuous integration server!