Documenting SpiNNaker C Code using Doxygen
We use Doxygen to translate special comments in our C code into our online documentation trees.
Doxygen is very complicated, but we only use a subset of it. The configuration
file for the Doxygen build is called Doxyfile
, and is huge and complex; we
try to turn off most of the features.
Documented files
We configure Doxygen to make documentation from all files with the extensions
*.c
, *.h
, *.md
(good for auxiliary pages) and *.dox
.
The *.dox
files should contain a single C-style documentation comment, and
are places for putting code information that doesn’t fit anywhere else. For
example, they can be used to provide the front page of the documentation tree,
or to contain directory level documentation if there isn’t an obvious other
file to put them in. Note that *.dox
files do not appear in the file tree.
Documentation comment format
All Doxygen documentation (in C) is placed in a comment like this (common):
//! ...
or like this (uncommon):
/*!
* ...
*/
Or like this (very uncommon in our code):
/**
* ...
*/
Directives
All directives (within a documentation comment) start with either \
or @
(you can use either; we commonly use backslash). The main ones you need to
know are:
-
\file
— Every*.c
and*.h
file needs one of these. Probably followed by a\brief
directive to provide a short description of the file. -
\brief
— A short description of something, usually a function, macro, variable, structure, etc. Lasts until the next block-level directive or a blank doc-comment line. Under normal circumstances, this should be a short sentence. -
\details
— The long description of something. Can be multiple paragraphs. Paragraphs are basically in Markdown format. -
\param
— Describes a parameter to a function or macro. Optionally followed by[in]
,[out]
, or[in,out]
to say what the parameter is doing ([in]
is probably the normal case). That is then followed by the name of the parameter (which must match the declaration) and an optional colon (:
); the colon is strongly recommended for clarity.For example, this might document an argument
int foo
:\param[in] foo: This is the primary foo thing in consideration.
-
\return
— Describes the result of the function or macro. Functions that havevoid
as their result type must not have a\return
directive!
Bare documentation comments without any directive are treated as \brief
if
they are a single line, and are treated as \details
otherwise.
Inline directives
We don’t use many directives, but here are some useful ones:
-
\a
— The next word is an argument. See also\p
. -
\p
— The next word is a parameter. See also\a
. -
\c
— The next word is to be in typewriter font. Normally it is easier to use markdown-style backticks. -
\f$
— Marks the start and end of some inline mathematical content. The part inside should be in LaTeX format. -
\f[
…\f]
— Contains a long-format formula in LaTeX format.
Note that Doxygen is apparently poor at recovering from typos in formulæ.
Rare directives
You won’t see these so much.
-
\mainpage
— Used to provide content for the main page of the documentation tree. Obviously, there should only be one of these per repository! By convention, this is usually in a file calledmainpage.dox
, but that’s just for our convenience. -
\dir
— Used to describe a whole directory. Only appears once at most in that entire directory. -
\section
— Starts a section in the documentation. Not that useful when incorporated into pages that actually document code, but may be useful in auxiliary pages (such as the main page). -
\name
— Introduces a section of declarations within a file. The declarations themselves are then surrounded by\{
and\}
. Useful in long files with many declarations and some natural grouping, but where a file has few declarations it is unnecessary. -
\note
— Marks a paragraph as worthy of note to the user. -
\warning
— Marks a paragraph as particularly worthy of note! -
\todo
— Marks something that’s perhaps unfinished. These are also called out to a separate summary file. -
\bug
— Marks something that’s outright wrong. These are also called out to a separate summary file. If putting one of these in, make sure you have also filed an Issue on Github! -
\cond
…\endcond
— Used to hide things from Doxygen’s output. Try to avoid using these! -
\internal
— Used to hide things from Doxygen’s output. -
\author
,\copyright
,\date
— Fairly obvious things for the file header material.
Cross references
You link to a function definition by using its name with ()
immediately afterwards.
You link to a macro by preceding it with #
.
You link to a source file by just mentioning it including extension. You do not need to include any part of the path unless the name is ambiguous; don’t create ambiguous filenames!
You link to other global symbols (e.g., enumeration values, types) by
preceding them with ::
(which sort of makes sense in a C++ way).
Writing style
Every public symbol should have a \brief
description. In our general style,
symbols are public unless excluded by the Doxyfile
’s EXCLUDE_SYMBOLS
configuration file. We normally document static
symbols and symbols starting
with one or more underscores (_
).
Functions should have their brief description begin with a present tense immediate active verb. Thus, instead of:
This function frobnicates the mome-raths.
or:
Frobnicates the mome-raths.
use:
Frobnicate the mome-raths.
Macros that are used like functions should follow the same rules.
Things that work like enumerations should be enumerations, and not just big
collections of #define
s! (Unless it is impossible for type reasons.)
Do not describe the type of arguments or return values in documentation comments. The documentation tool picks up the type just fine from the declaration itself.
Predefined macros
We disable most C macro processing when loading in source files, but we do
enable some. In particular, we define the symbol DOXYGEN
when building and
you can use that to hide things from the processing tool that confuse it
(notably including __attribute__(...)
annotations).
The configuration of that is controlled by the PREDEFINED
configuration value
in the Doxyfile
. An example setting there is:
PREDEFINED = DOXYGEN=1 \
NO_INLINE= \
UNIMPLEMENTED=
This provides default empty definitions for the NO_INLINE
and UNIMPLEMENTED
macros, which are defined like this in an appropriate C file:
#ifndef DOXYGEN
#define NO_INLINE __attribute__((noinline))
#define UNIMPLEMENTED __attribute__((deprecated("Not implemented")))
#endif // DOXYGEN
The standard pattern of #ifndef
/#define
guards for a whole file do not need
to be documented (and should not be).
Documentation Deployment
Our documentation deployments are driven automatically on Github (using Travis to do much of the work) and, for Python only, on ReadTheDocs (which also stores old versions).
The core of our Github/Travis deployment rules are based on
this blog comment
(!) with some adaptations. Essentially, we run Doxygen as part of the build, and
then we assemble the output into the right directory with minimal extra work.
The magic token required for publishing from Travis to Github is placed in the
GITHUB_TOKEN
environment variable by the configuration settings on Travis
(no, it’s not in the repository) only for the master
branch. If you want to
test how your documentation changes look, you should run Doxygen locally; there
is no capacity to do test deployments on a per-branch/PR basis.