Doxygen Tutorial (C/C++

When I returned to programming a few years ago, I noticed that open source developers were tending to fall into two main groups: those that use Doxygen to generate development documentation, and those that documented very little. So I started to look at Doxygen but was quickly put off by two major flaws. The Doxygen documentation, both the official reference documentation and various howtos and tutorials, missed something for the beginner. They tended to merely explain the commands and concepts, but did not give a proper lead in for a new user. Secondly the examples that I looked at appeared as simple lists of file, class, member, variable names and a few natty diagrams. To me they conveyed nothing of the intent of the program or any explanation of its internal workings.

This is basically a failure of some open source developers, not of Doxygen. Some speak of "self-documenting code", however there is really no such thing. Meaningful choices of names for entities goes a long way towards helping make the code readable, but it stops short of describing the purpose of entities, the way blocks of code work, and the reasons for decisions that were made (most important to the reader). Here I intend to show how I use Doxygen, displaying the extent of its capabilities, and to do it in a way that demonstrates what I believe to be good documentation practice. I only use C and C++, but you should be able to follow this even if you use other languages.

As well as command line Doxygen, I consider DoxyWizard to be quite important for providing an intuitive and easy to use GUI interface. Although the configuration file and command line usage of Doxygen is well documented, a new user needs to have a basic overall appreciation of what Doxygen is doing before it makes any sense.

Installation

Refer to any of the existing tutorials and howtos to find out how to install Doxygen and DoxyWizard. Most distributions provide both of these.

Getting Started

Find a simple program consisting of perhaps a source and header file and no Doxygen markup. The one I used from my collection to develop this tutorial is called "solarpower". Open DoxyWizard. The first tab allows you to enter the working directory, so fill this in first. Then click on the Wizard button. Give a meaningful name and version number (which will appear as headings in the final document) and set the two directories; the first to point to your source code directory and for the second just make it the same as the working directory (or create a new "docs" directory). Doxygen will place subdirectories to hold the documentation: "html" for the html files etc.

In the Mode tab, choose to document all entities and to include cross referenced source code. Choose the optimization for your language. In the Output tab, if you choose to use the dot tool you will get some really natting looking dependency graphs. You must have the GraphViz package installed for this.

Now go back to the first tab and save the configuration. Doxygen offers the file Doxyfile, which I prefer to use as I always know immediately what it is when I see it. Now click the Start button. Doxygen will run and create the documentation output. Point a browser to the file index.html in the html subdirectory and you will see what Doxygen does without any effort on the developer's part to control it. The author probably understand what it all means but no-one else will.

The first thing you see on opening index.html is the "Main Page" tab showing your project name and version and nothing else. There should also be a Files tab. This shows links to the generated documentation for the files and to the source code. There may be some additional files that Doxygen picked up from the source directory and that you don't want included. You would need to explicitely exclude these using the DoxyWizard expert tool. There are other tabs that will appear to allow guidance around the documentation. What Doxygen can do to an undocumented program is to identify the various entities in your program and present them in a digestible manner. However to produce real documentation, the developer must provide comments in the code, and appropriate markup to allow Doxygen to pull out these comments and place them with the associated entities to guide the reader into an understanding of the code. If you have already placed good quality comments in your code you are 90% of the way there, otherwise there is a bit of work to be done.

Providing an Introduction

The first thing a new reader wants to see when viewing documentation is a brief and comprehensive summary of the program's purpose, the authors, dates and various other valuable information. To do this, open your main file and add a comment at the very top with this information (you have already done this anyway as part of your commenting of the code - right?). Now to make Doxygen use it on the main tab enter the following markup constructs:
  • /** or //! at the beginning of the comment. If you use the C++ comment convention then you can use the second form, but either are acceptable. If you are using a Doxygen-smart editor such as Kate, then the colour of the text should change.
  • @mainpage immediately following. You can add a string after this as a title in place of the project name that was entered in DoxyWizard. This instructs Doxygen to put the comment on the main tab.
  • @version if you prefer to have it here rather than in the Doxyfile.
  • @author whoever
  • @date whenever
  • @note Placed anywhere this will add a note keyword in bold if desired.
After these put a description of the program's purpose. To make sure the description does not get attached to the directive just before it, use the directive @detail or leave a blank line. Now run Doxygen again and observe the changes. You are now on the way to having some quality documentation.

Including Comments

As mentioned above, adding an extra * to the /* or a ! to the // comment delimiter will cause Doxygen to associate the comment with the next defined entity. These comments can be placed before and in the middle of a block of code such as a function.

If you look at a page generated by Doxygen for a simple source file, you will see at the top a list of includes and a dependency graph generated from these. Underneath that will be a list of the functions that Doxygen found in the file. Detailed documentation for each function appears following that list.

The first step to improving this is to add a brief comment to each function in the list. Just above the function add a comment, and immediately following the /** or //! delimiter, add the directive:

@brief Description of the function

When Doxygen is run, this description will appear underneath the corresponding function in the function list, and also in the detailed documentation for the function.

Now underneath the @brief directive, leave a blank line and add a detailed description of what the function does. Also add the following optional directives (omit them if there are no parameter or return value):

@param[in] parameter Description of parameter constraints etc.
@return Description of the return value.

This will add more information to the detailed function descriptions. You can also include other Doxygen comments in the body of the function and they will appear in the detailed function description.

A useful directive is:

@todo Description of something to be done to improve the code.

This is added to the detailed description, but it also causes a new top-level tab to be added to your html document called "Related Pages". In this will be a link to a ToDo list that presents all the @todo comments you have added throughout the code in a big block, the only disadvantage being the depression it causes on seeing how much there is still to be done.

Beware

Doxygen still has some problems, as evidenced by the existence of over 600 uncorrected reported bugs. So you may find some problems with using it. One thing I discovered is that Doxygen markup is normally expected to appear in the header files. Much of it can be placed in the source file, but not all. Therefore it is probably better to aim at documenting the header files as a matter of standard practice. I personally chose not to do that because I wanted to include comments inside the code.

Groupings

Rather than have all your code files appear in a bunch under the "Files" tab, you can cause them to appear as groupings under a new tab called "Modules". To do this add a comment somewhere at the top of the appropriate file with the directive:

@defgroup groupname Description

This will cause the Modules tab to appear and an entry showing the group description. You can then add entities such as files, classes, functions, variables etc to the group by adding the directive:

@ingroup groupname

into a comment for that entity. This gives the flexibility to group entities independently of the files in which they reside, and to give them more meaningful names and descriptions.

Classes

Classes are grouped under a separate tab from Files and Modules. Doxygen pulls out the class definitions, member functions and variables separately from purely local functions which are documented in the Modules.

Examples

Examples can be found by looking at the code that I have placed on this site. Each of the packages are extensively documented according to the principles I have given here. Once you have made a start it should be easy enough to simply read through the directive reference in the Doxygen documentation to get a good idea of what else can be done with the tools.

Once you get something going, read Doxygen's user and reference manual to round out your knowledge. It is well written and easily digestible. Doxygen will not do everything but is just enough to produce that very much needed development documentation that should be provided with every project.

Documentation Principles

If you are proud of your creation and want the world to benefit from it, but fail to document your code, you are basically wasting a lot of your time. When you come back to it later, or when another person wants to take over after your untimely decease, much of the work you have done will be obscure and a huge amount of work will be needed to get to the starting point.

I consider my approach to documentation to be adequate without going to the extreme lengths necessary in a large team project.. As code is written, comments are added to explain the purpose of each segment, constraints on variables, lists of parameters and return values and their meaning, and anything else that could help a reader to understand what is going on. This is as important for the programmer as for any future developer. While Doxygen markup could be added as code is written, it is not necessary at that point as the code could change substantially. It is better to wait until the code is reasonably stable and the segment can be viewed in its entirety.
 


First created 4 September 2007
Last modified
13 September 2007
Ken Sarkies 2007