Doxygen documentation guidelines for AliRoot and AliPhysics

Table of contents

How to write Doxygen documentation

AliRoot Core and AliPhysics use Doxygen for documentation.

Doxygen is a way of documenting your code inside the source code itself, by factoring special comments that will be ignored by the C++ compiler.

Documenting a C++ class

A C++ class is divided in two files:

Class description

At the very beginning of your header file, put the following specially formatted comment:

/// \class AliMyClass
/// \brief This is a brief description of my class
///
/// This is a longer description of the class. This longer description is
/// formatted using the Markdown syntax (see below) and can span on multiple
/// lines.
///
/// Separate the paragraphs by leaving a blank line between them.
///
/// \author Alice User1 <alice.user1@cern.ch>, My Home Institute
/// \author Alice User2 <alice.user2@cern.ch>, My Home Institute
/// \date Mar 4, 2015

Notes:

Leave the class description inside your header file only. Do not duplicate it inside the source file!

Data members

You can append a specially-formatted comment to a ROOT class datamember for providing it with a Doxygen description.

Other specially-formatted comments in ROOT have also a special meaning for I/O: that is, in some cases they indicate how and if saving this data member when, e.g., saving the class to a .root file.

This paragraph illustrates how to write specially-formatted comments in a way that they are both compatible with ROOT’s intended behaviour and Doxygen.

Doxygen uses both //!< and ///< to introduce a data member comment. Until ROOT 5, this allowed using //!< for indicating a transient data member. ROOT 6 abruptly broke this compatibility and //!< does not mean transient anymore: we are now forced to use //!<! for introducing a Doxygen comment interpreted as transient in both ROOT 5 and ROOT 6.

The most common cases are covered. In the examples that follow, the fRoot variable is the one with the ROOT-only comment. The fDoxygen variable has the ROOT-compatible Doxygen comment (i.e. the one you should use).

Normal (non-transient) members:

Int_t fRoot;     // Description
Int_t fDoxygen;  ///< Description

Transient members:

Int_t fRoot;     //! Description
Int_t fDoxygen;  //!<! Description (note the double exclamation mark!)

Int_t fDontUseEver;  //!< Different behaviour in ROOT 5 and 6: don't use!!!

Arrays:

Int_t *fRoot;     //[fSize] Description

/// Description
Int_t *fDoxygen;  //[fSize]

Note: in this case, the ROOT comment is left alone, and the member description is prepended to the member definition.

Don’t split member on multiple files:

TTree *fRoot;     //|| Description

/// Description
TTree *fDoxygen;  //||

Also in this case the comment has to be split into a Doxygen comment and a ROOT one.

Pointer to TObject:

TObject *fRoot;     //-> Description

/// Description
TObject *fDoxygen;  //->

Comment is split here too.

Member functions

Member functions (apart some exceptions) are implemented in the source file. In Doxygen, a member function is documented like the following:

/// This is the description of this member function. It can contain Markdown
/// code.
///
/// Multiple paragraphs are split on multiple lines.
///
/// \param anInt Integer value used to do things
/// \param aTree Pointer to a valid TTree
///
/// \return A fixed number that has nothing to do with what the function does
Float_t AliMyClass::MyMemberFunction(Int_t anInt, TTree *aTree) {
  /* implementation goes here */
  return 123.45;
}

The same Markdown code can be used for formatting this comment. Please note the special Doxygen tags:

Our current convention is to place function description before method definition and not inside it.

Documenting a C++ “macro”

Suppose we have the AliMyMacro.C ROOT C++ macro. At the very beginning of the file:

/// \file AliMyMacro.C
/// \brief This is a brief description of my file, pretty much like the class
///
/// Multiple paragraphs separated by blank lines.
///
/// Considerations for documenting classes apply here too.
///
/// \author Alice User1 <alice.user1@cern.ch>, My Home Institute
/// \author Alice User2 <alice.user2@cern.ch>, My Home Institute
/// \date Mar 4, 2015

Macros are documented the same way classes are documented. The only difference:

ClassImp() and ClassDef()

The special ROOT macros ClassImp() and ClassDef() can create confusion to Doxygen.

To reduce confusion:

In the class definition:

/// \cond CLASSIMP
ClassImp(AliMyClass);  // notice the ;
/// \endcond

In the source file:

/// \cond CLASSIMP
ClassDef(AliMyClass, 0);  // notice the ;
/// \endcond

The CLASSIMP variable is used both for ClassImp() and ClassDef() definitions, it is not a typo.

Markdown

Comments are formatted using Markdown syntax. The Markdown syntax is extensively described here.

In particular:

**This text will be bold**, whereas *this will be italic*.

[This is a link](http://aliceinfo.cern.ch/).

* This is
* A list
  * with a sublist
  * of other items

![This is an image](image.png)

## This is a title for a section

### This is a title for a subsection

#### This is a title for a subsubsection

Images from ROOT macros

In ROOT it was possible to generate images from ROOT macros on the fly by using the Begin_Macro ... End_Macro block.

If you are working in a file named MODULE/SUBMODULE/AliMyClass.cxx, first create a subdirectory called imgdoc:

mkdir MODULE/SUBMODULE/imgdoc

In there, create a macro file named AliMyClass_cxx_whateveryouwant.C, and fill it with the content of the ROOT macro block.

Replace the macro block with:

![Whatever you want](AliMyClass_cxx_whateveryouwant.png)

In practice you are inserting an image that has the same name of the macro, but the .png extension in place of .C.

Do not use absolute paths there. Only point to the image file name with no path at all.

To generate the file, load the AliRoot environment (i.e. you must have AliRoot working in your path), go to the MODULE/SUBMODULE/imgdoc directory and run:

cd <AliRootSource>/MODULE/SUBMODULE/imgdoc
alidoxyimg.sh AliMyClass_cxx_whateveryouwant.C

The corresponding updated .png file will be created.

Remember to git add and commit both the macro file and the generated image! If editing the macro, regenerate the image.

LaTeX formulas

ALICE Doxygen documentation uses MathJax for rendering formulas natively in the browser: this means that formulas can be inserted in the code in the native LaTeX syntax, and no intermediate image will be generated.

Doxygen supports two types of LaTeX blocks. Inline formulas are written on a single line:

... \f$ latex_formula_goes_here \f$ ...

Formulas can be written in a separate block (clearer for long formulas):

\f[
...
...
...
\f]

Colored code blocks

It is possible to add code snippets to your documentation by fencing your code block with three tildes:

~ ~ ~
my code
my code
my code
~ ~ ~

Code blocks will be syntax-colored if you specify the file format. For C++, for instance:

~ ~ ~{.cxx}
void MyClass::MyClass(int a, float b, const char *s)
  // code goes here
}
~ ~ ~

Note that there is no space between tildes (i.e. ~~~, not ~ ~ ~)!

Generate the documentation

Before pushing any documentation change, you might want to check how it looks on your local computer.

Generating Doxygen documentation is easy, and the tools you need are very straightforward to install.

Install required tools

Apart from the usual build tools, you will need:

On Ubuntu/Debian:

sudo aptitude install doxygen graphviz

On OS X with Homebrew (no sudo here):

brew install doxygen graphviz

Run Doxygen

You don’t even need to compile AliRoot or ROOT to install the documentation.

If you follow the installation instructions schema, once your environment is loaded (the alice-env.sh file):

Now, inside the build directory, run:

make doxygen

Doxygen documentation will be generated in the build directory under doxygen/html. Open doxygen/html/index.html with a web browser to read the documentation.

If you get the error:

$> make doxygen
make: *** No rule to make target `doxygen'.  Stop.

it means that CMake did not find Doxygen and Graphviz installed on your system. If you have installed them and you still get the error, remove the build directory and run CMake from scratch.

If you want the documentation to be installed in your AliRoot Core installation directory (i.e. $ALICE_ROOT), type:

make install-doxygen

Open $ALICE_ROOT/doxygen/index.html to browse the documentation.

Convert existing documentation to Doxygen

In order to help converting the existing comments to Doxygen, by especially taking into consideration special ROOT data member comments, we provide a very spartan tool called thtml2doxy.py.

Prerequisites for thtml2doxy.py

In order to use this tool, you need to have AliRoot Core installed (i.e. with make install) and an environment properly set. If you follow the installation instructions then you are set.

The conversion tool uses the Python bindings of libclang, which must be installed on your system.

The tool has been solely tested using LLVM 3.5 on Ubuntu 14.04, and libclang has been installed like this:

sudo aptitude install libclang1-3.5 libclang-common-3.5-dev python-clang-3.5

Getting the scripts without having AliRoot

There are two conversion scripts needed for the conversion:

You can get them from the CERN Git web interface without downloading or installing the full AliRoot.

Note: you need a CERN account to access the above links. If you do not have one, you can clone the public AliRoot Core Git repository:

git clone http://git.cern.ch/pub/AliRoot.git

Scripts will be in the doxygen/ subdirectory.

How to use it: an example

We are assuming that AliRoot has been installed. Let’s take a couple of files as examples:

First off, move to their directory in the source code:

cd "$ALICE_ROOT/../src/TPC/TPCcalib"

Look at the beginning of the .cxx file:

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
//  Base class for the calibration components using
//  as input TPCseeds and ESDs
//  Event loop outside of the component
//
//
// Base functionality to be implemeneted by component
/*
   //In some cases only one of this function to be implemented
   virtual void     Process(AliESDEvent *event)
   virtual void     Process(AliTPCseed *track)
   //
   virtual Long64_t Merge(TCollection *li);
   virtual void     Analyze()
   void             Terminate();
*/
// Functionality provided by base class for Algorith debuging:
//  TTreeSRedirector * cstream =  GetDebugStreamer() - get debug streamer which can be use for numerical debugging
//



//  marian.ivanov@cern.ch
//

Now run the conversion tool:

thtml2doxy.py -I$ALICE_ROOT/include AliTPCcalibBase.cxx AliTPCcalibBase.h

The two files have been modified in place. Your directory is under version control with Git, so you can:

Do not commit immediately without checking what has changed! You’ll likely need to amend some of the automatic conversions!

We immediately notice that the new header looks like this:

/// \class AliTPCcalibBase
/// \brief  Base class for the calibration components using
///
/// as input TPCseeds and ESDs
/// Event loop outside of the component
///
/// Base functionality to be implemeneted by component
///
///  //In some cases only one of this function to be implemented
///  virtual void     Process(AliESDEvent *event)
///  virtual void     Process(AliTPCseed *track)
///
///  virtual Long64_t Merge(TCollection *li);
///  virtual void     Analyze()
///  void             Terminate();
///
/// Functionality provided by base class for Algorith debuging:
/// TTreeSRedirector * cstream =  GetDebugStreamer() - get debug streamer which can be use for numerical debugging



//  marian.ivanov@cern.ch
//

In particular:

After a couple of manual edits, we make it look like this:

/// \class AliTPCcalibBase
/// \brief Base class for the calibration components using as input TPCseeds and ESDs
///
/// Event loop outside of the component
///
/// Base functionality to be implemeneted by component
///
/// ~~~{.cxx}
/// // In some cases only one of this function to be implemented
/// virtual void     Process(AliESDEvent *event);
/// virtual void     Process(AliTPCseed *track);
///
/// virtual Long64_t Merge(TCollection *li);
/// virtual void     Analyze();
/// void             Terminate();
/// ~~~
///
/// Functionality provided by base class for Algorith debuging:
///
/// ~~~{.cxx}
/// TTreeSRedirector * cstream =  GetDebugStreamer() - get debug streamer which can be use for numerical debugging
/// ~~~
///
/// \author Marian Ivanov <marian.ivanov@cern.ch>

We have:

thtml2doxy.py takes as many files as you want as input. Remember to always specify the “include path” -I$ALICE_ROOT/include, as this is required by libclang.

As you can see from the example, the original documentation did not have a clear convention, so a fully automated conversion is not possible. However, the conversion tool saves you some time.

In fact, if you run git diff, you’ll realize how the member functions comments are converted correctly, the \cond CLASSIMP ... \endcond has been added, and all data members have their description properly formatted.

Images from ROOT macros

With ROOT’s THtml it was possible to insert a special macro block generating an image. ROOT internally processed the macro, and the resulting HTML contained the image only.

Whenever thtml2doxy.py finds a block in the form (case insensitive):

BEGIN_MACRO
...
END_MACRO

the macro is extracted to an external file in the directory imgdoc under the current path.

If the input file is, i.e., AliTPCGGVoltError.h, all macros found in the file will be extracted to imgdoc/AliTPCGGVoltError_h_<uuid>.C.

The code block corresponding to the macro will be substituted with a pointer to a static image, in Markdown format:

![Picture from ROOT macro](AliTPCGGVoltError_h_<uuid>.png)

See how to insert images from ROOT macros for more information.

LaTeX blocks from ROOT macros

LaTeX blocks in the form (case insensitive):

BEGIN_LATEX
...
END_LATEX

are also automatically converted to the corresponding Doxygen Markdown format. The special ROOT “pound sign” syntax (i.e. #sigma) is automatically converted to the native LaTeX syntax (\sigma).

Adding your directories and images to Doxygen

AliRoot Doxygen is configured to look in a list of directories for files to convert. Each single directory has to be specified, and the lookup is non-recursive.

During the transition period, where not all the documentation has been converted to Doxygen, this method helps us generating only the documentation for the files that were actually converted to Doxygen.

To include your directory to the Doxygen documentation, edit the file doxygen/Doxyfile.in and add your module’s directory to the INPUT variable, e.g.:

INPUT = @CMAKE_SOURCE_DIR@/doxygen \
        @CMAKE_SOURCE_DIR@/TPC \
        @CMAKE_SOURCE_DIR@/TPC/Attic \
        @CMAKE_SOURCE_DIR@/TPC/Base/test \
        @CMAKE_SOURCE_DIR@/TPC/Cal \
        @CMAKE_SOURCE_DIR@/TPC/CalibMacros \
        @CMAKE_SOURCE_DIR@/TPC/DA \
        @CMAKE_SOURCE_DIR@/TPC/fastSimul

If you have images to add in the imgdoc directory under your module’s directory, you should add it to the image search path in the same file:

IMAGE_PATH = @CMAKE_SOURCE_DIR@/picts \
             @CMAKE_SOURCE_DIR@/TPC/TPCbase/imgdoc

Probably you do not have push permissions for the doxygen directory, so just open a JIRA ticket and attach the patch created with git format-patch to the issue.