LearningDoxygen

From HerzbubeWiki
Jump to: navigation, search

Doxygen generates documentation in HTML, PDF and other formats from specially crafted source code comments. This wiki page is my personal summary of the Doxygen manual (see the References section), with a special bias on documenting C++ source code and the documentation being generated in HTML. Only the most important Doxygen commands are presented here, and those not in full detail. To get more information about a specific command, you should consult the "List of special commands" section of the Doxygen manual.


References


C++ language elements that can be documented

Pretty much all C++ language elements can be documented:

  • Classes, structs
  • Constructors, Desctructors, methods, operators, global functions
  • Member variables, global variables
  • Enumerations
  • Typedefs
  • Unions
  • Namespaces
  • Preprocessor macros
  • etc.

Doxygen can generate documentation for additional entitities (e.g. files), these are presented later in this document.


Basic formatting

Comment blocks

Doxygen only processes comment blocks that are specially marked up. There are several markup styles, but my personal favourite is to begin each line with 3 slashes ("///"). Several consecutive lines that all start with "///" together form a comment block:

/// line 1
/// line 2
/// line 3

/// previous empty line begins a new block

The other comment block markup styles build on the C-style multi-line comment /* [...] */. I don't like that because it interferes with one of my frequently used coding techniques where I quickly disable large parts of source code by surrounding the code with /* [...] */. This technique won't work if the source code that I want to disable contains Doxygen comment blocks marked up with /* [...] */.


Visual separation of comment blocks

To visually separate comment blocks from the surrounding code, I like to add a starting and an end line to the comment block. The 2 lines should be simple comments using 2 slashes ("//") to prevent Doxygen from parsing them.

// ***********************************************************************
/// line 1
/// line 2
// ***********************************************************************


Doxygen commands

Doxygen comments contain commands that tell Doxygen

  • What documentation should be generated
  • How the generated documentation should look like


There are several styles how a command can be marked up, but my personal favourite is the JavaDoc style where commands are prefixed with an "@" (at) character. Example:

/// @brief This is a brief description.

The other command markup style uses the "\" (backslash) character as the command prefix. My dislike for this is mostly based on "\" being the escape character in a lot of technologies that I am used to (e.g. the Unix shell, regular expressions, C/C++). Using "\" just looks unnatural to me, whereas "@" is much more agreeable to my eyes. I am irrational, I know.


Markdown

Unless you explicitly disable this in the Doxygen configuration file (the controlling tag is `MARKDOWN_SUPPORT`), you can mix Doxygen formatting with Markdown formatting. When enabled Doxygen pre-processes all comments according to the Markdown format, which allows for more readable documentation. See https://daringfireball.net/projects/markdown/ for details.


Where to place documentation

Documentation before the element (default)

Usually a comment block is placed just before the element it documents. In this case you do not have to explicitly specify what you want to document - Doxygen is clever enough to find out by itself the type and name of the element that the comment belongs to.

/// @brief This is the brief description for a class
class Foobar
{
};


Documentation after the element

In some cases it makes sense to place the documentation comment behind its element. The most frequent use cases for this are when you want to document enumeration values and member variables. To attach a comment block to a preceding element, the comment block lines must start with "///<" (note the "<" character).

class Foobar
{
private:
  int m_anInteger;              ///< @brief Brief description after a member variable
  int m_anotherInteger;         ///< Detailed description after another member variable
};


Documentation at the place of definition instead of declaration

Only for functions and methods, Doxygen lets you place the documentation of the function/method at the place where where the function/method is defined (e.g. the implementation in the .cpp file) instead of where it is declared. For instance:

---------- Foobar.h ----------
/// @brief This is the brief description for class Foobar
class Foobar
{
   void doIt();
};

---------- Foobar.cpp ----------
/// @brief This is the brief description for method doIt()
void Foobar::doIt()
{
}

Advantages:

  • Header files don't become bloated, which reduces compilation time and keeps them clear and tidy
  • Re-compilation after a documentation change is minimal, i.e. your compiler will only re-compile a single .cpp file instead of all the dependencies of the .h file where the change occurred

Disadvantages:

  • When you distribute your header files (e.g. because you are writing a library or framework), users have to consult the generated documentation and cannot look at the documentation directly inside the .h file. On the other hand, this might be seen as an advantage - relying on documented behaviour is better than looking at source code and falling into the trap of relying on an implementation detail that might be visible in a header file.


Documentation separated from element

It is possible to completely separate the documentation from the element that it belongs to. In this case a special command must be used to specify to Doxygen what should be documented. In the following example, a comment block for class Foobar has been placed in the .cpp file, which means that the command @class Foobar is required to "attach" the comment block to class Foobar.

Note: You should avoid doing this because it requires you to redundantly write element names. Despite best efforts, duplicated information always has a tendency to become out-of-sync.

---------- Foobar.h ----------
class Foobar
{
  void doIt();
};

---------- Foobar.cpp ----------
/// @class Foobar
/// @brief This is the brief description for class Foobar

/// @brief This is the brief description for method doIt()
void Foobar::doIt()
{
}


Special case @file

Files are not C++ language elements, therefore it is not possible to place a comment block before or after the element. Instead, you use the Doxygen command @file to document a file. Using the @file command without a parameter associates the documentation with the file that the @file command appears in.

Example:

---------- GlobalDefines.h ----------
/// @file
/// @brief Optional brief documentation for a file.
///
/// Because the @@file command does not specify a filename,
/// the name of the file containing the documentation block
/// (GlobalDefines.h) is automatically used for the documentation.


/// @file UniversalDefines.h
/// @brief Optional brief documentation for a file.
///
/// Although we are in GlobalDefines.h, we can document
/// another file from here. This is the only case where it
/// makes sense to specify the filename

Notes:

  • It is mandatory to document a file using @file if that file contains other documented elements that have global scope (e.g. global variables, functions, typedefs or enumerations; but also preprocessor macros). If you forget to document such a file, then the documentation of the global-scoped elements will not appear anywhere in Doxygen's output. The reason for this is simply that Doxygen requires a context for the global-scoped elements to appear in. In contrast: For members of classes and namespaces, the context in which the documentation of these members appears is the containing class or namespace.
  • "@@file" in the example above shows how to escape the "@" character


The most important commands

Brief and detailed description

All elements can have a brief and a detailed documentation. The command @brief is used to start the brief documentation, whereas the detailed documentation requires no special command. The detailed documentation is separated from the brief documentation with an empty documentation line, otherwise Doxygen would not know where the brief documentation ends and the detailed documentation starts.

Example:

/// @brief This is a brief description. It may be longer than one line, in
/// fact it continues until the next paragraph.
///
/// This is the detailed description. The empty documentation line above
/// begins a new paragraph and separates the brief from the detailed
/// description.
class Foobar
{
};


Method/Function documentation

An example is the best way to explain how a method/function documentation looks like:

/// @brief The short description.
///
/// The detailed description.
///
/// @param ccc A character.
/// @param nnn An integer.
///
/// @return A character pointer.
///
/// @exception std::out_of_range Parameter is out of range.
const char* Foobar::doIt(char ccc, int nnn)
{
}

If required, return values can also be separately documented. Instead of a single @return command you use multiple @retval commands:

/// @retval "foo" if condition 1 is true
/// @retval "bar" if condition 2 is true

If required, in/out parameters can be explicitly documented:

/// @param[out] dest The memory area to copy to.
/// @param[in]  src  The memory area to copy from.
/// @param[in]  n    The number of bytes to copy
void memcpy(void *dest, const void *src, size_t n);

Note: The @param and @retval commands enforce a highly structured, technical documentation that is often hard to read, simply because it is difficult for the person who writes the documentation to write complete sentences and formulate coherent thoughts. Personally, I prefer a less structured but more readable documentation style, which is why I usually don't use @param and @retval. As usual, this is not a hard rule - use the style that results in the best documentation!


Lists

Non-numbered lists are created by using the "-" (dash) character, numbered lists by using the "-#" (dash + hash) characters. Lists can be nested by indenting their elements to the same column. A "." (period) character ends the previous list on the same nesting level.

Example:

/// Text before the list
/// - list item 1
///   - sub item 1
///     - sub sub item 1
///     - sub sub item 2
///     . 
///     The period above ends the sub sub item list.
///     More text for the first sub item
///   .
///   The period above ends the first sub item.
///   More text for the first list item
///   - sub item 2
///   - sub item 3
/// - list item 2
///   -# numbered sub item 1
///   -# numbered sub item 2
///
/// More text in the same paragraph.


Formatting commands

Some of the most important formatting commands:

  • @a - The following word is marked up as a function/method parameter (usually the end result that the reader of the documentation sees is the same as if @e had been used, but the stylesheet in use could change this)
  • @e - The following word is marked up as emphasized
  • @b - The following word is marked up as as bold
  • @p - The following word is rendered in a non-proportional font


Paragraph commands

The following commands all work in the same way. They are used within a detailed documentation to create a new paragraph that has some special meaning.

  • @note - The paragraph contains a note that is set off from the surrounding text
  • @attention - The paragraph contains text that requires special attention (even more attention than @note)
  • @code, @endcode - The text between these commands is a code example. If the code example uses classes, methods, etc. that are documented, they are automatically linked. Also see the @example command.
  • @verbatim, @endverbatim - The text between these commands is embedded into the documentation as-is and without formatting. This is similar to @code, but no linking occurs and the text is not formatted as source code.
  • @see - The paragraph contains "see also" text. This is used to place references to other documented elements.
  • @deprecated - Marks an element as deprecated. The command may be followed with additional text that describes the circumstances of the deprecation.

Example:

/// @brief The brief description.
///
/// The detailed description.
///
/// @note A separate paragraph with a note.


Groups

Creating groups

Classes, enumerations, typedefs, preprocessor macros etc. that are somehow related to each other can be collected into groups. In the generated documentation, groups appear under the term "Module" - possibly because groups are often used in large software projects to represent the project's software modules, but this is merely my own guessing. Doxygen automatically generates an index of all groups/modules that is visible at the top-level of the documentation, thus allowing the user to quickly find, and navigate between, the available modules.

The command @defgroup is used to create a group. The group has a label ("account" in the following example) and a user-visible title ("The Account module" in the following example). The usual things such as brief and detailed documentation can then be used in the group's comment block.

Example:

/// @defgroup account The Account module
/// @brief This is the group's brief description.
///
/// This is the group's detailed description.


Add elements to a group

The command @ingroup is used to to add an element (e.g. a class) to a group. The command argument is the group's label, i.e. the word that was specified as the first argument of the @defgroup command. An element can be added to multiple groups.

/// @brief This is the class' brief description.
///
/// @ingroup account
/// @ingroup settings
///
/// This is the class' detailed description.


Nested groups

Groups can be nested by using the @ingroup command inside a @defgroup comment block. The group index that is automatically generated by Doxygen makes the group hierarchy visible by listing the groups in nested lists.

/// @defgroup account The Account module
/// @ingroup finance


Member groups

Doygen automatically groups member elements (e.g. members of a class):

  • By member type: All variables are grouped together, all methods are grouped together, etc.
  • By protection level: Variables and methods are additionally grouped by public, protected and private


In addition to this automatic grouping, member elements can be further grouped with the commands @{ and @}. The command @name is used to give a name to the group of member elements. Example:

class Foobar
{
public:
  Foobar();

  // ***********************************************************************
  /// @name Start/stop observing
  // ***********************************************************************
  //@{
  static void StartObserver();
  static void StopObserver();
  //@}
};


Pages

Creating pages

If you want to document something that is not directly related to a class, or a member, etc., then you can create a separate page and write it down there. Doxygen automatically generates an index of all pages that is visible at the top-level of the documentation, thus allowing the user to quickly find, and navigate between, the available pages.

The command @page is used to create a page. The page has a label ("page1" in the following example) and a user-visible title ("A documentation page" in the following example).

/// @page page1 A documentation page
/// @ingroup group1
///
/// This is some text on the page. It is possible to define sections to
/// provide a structure to the page, but we will cover this in a later
/// chapter.


Nested pages

Similar to groups, pages can be hierarchically nested. The command used for this is @subpage. The command appears in the documentation of the parent page and refers to the label of the child page.

Note: Subpages do not appear in the page index that is automatically generated by Doxygen, i.e. that index only lists top-level pages.

Example:

// ***********************************************************************
/// @page page1 A documentation page
///
/// This topic is divided into the following sections:
/// - @subpage intro
/// - @subpage advanced "Advanced usage"
///
/// @note The @@subpage command always creates a visible text reference,
/// it is not possible to use the command just for the purpose of creating
/// a page hierarchy "in the background".
// ***********************************************************************

// ***********************************************************************
/// @page intro Introduction
///
/// This page introduces the user to the topic.
// ***********************************************************************

// ***********************************************************************
/// @page advanced Advanced Usage
///
/// This page is for advanced users.
// ***********************************************************************


The Main page

Every Doxygen project can have exactly one (optional) main page. This page is shown when the user navigates to the start page (index.html) of the generated documentation.

The command @mainpage is used to define the main page. The main page has a user-visible title, but no label.

Example:

/// @mainpage The Foo Project
///
/// This is the main page of the Foo project.


Structuring a page

Pages with a lot of text need to be structured. The following commands can be used to provide a hierarchical structure to a page. The commands can be used not only in documentation blocks that were defined with the @page command, but also in any other documentation block that leads to the creation of its own page (e.g. groups, classes, namespaces, files, etc.). The following commands are listed in descending hierarchical order:

  • @section
  • @subsection
  • @subsubsection
  • @paragraph

All structuring commands have a label ("section1-page1" in the following example) and a user-visible title ("An example section" in the following example).

/// @page page1 A documentation page
///
/// @section section1-page1 An example section
/// bla bla bla
///
/// @subsection subsection1-page1 The first subsection
/// bla bla bla
///
/// @subsubsection subsubsection1-page1 The first subsubsection
/// bla bla bla
///
/// @paragraph paragraph1-page1 The first paragraph
/// bla bla bla

Note: Labels must be unique across the entire Doxygen project so that the @ref command can be used to create an unambiguous link to the structuring element. It therefore makes sense to choose label names that refer to their context. For instance, "section1-myclass" labels the structuring element "section1" which appears in the context of the class "MyClass".


Links

Classes, structs and files

Doxygen automatically generates links to classes, structs and files whose names it finds in a documentation block. Obviously, the referenced class, struct or file must have been documented.


Functions

Doxygen automatically generates links to functions and methods if the functions/methods are written in a manner that is similar to the way how they are called in the source code.

Examples:

/// function1(int, char, const std::string&)
/// - Refers to a member function in the same class or a base class, if one exists
/// - OR refers to a global function (only if no member function of the same name exists)
/// - Note that the argument types must match exactly
///
/// function2()
/// - As above, for functions with no arguments
/// - OR refers to a single function without overloads, even if that function has arguments
/// - OR, if there are overloads, refers to one of those overloads (Doxygen chooses which one)
///
/// MyClass::function3() const
/// - Refers to a function in the specified class (or namespace)
/// - Note that modifiers (e.g. const, volatile) must match
///
/// ::function4()
/// - Refers to a global function
///
/// #function4()
/// - Refers to a global function if one exists
/// - OR refers to a member function in the same class or a base class (only if no global function of the same name exists)


Variables, typedefs, enumerations, preprocessor macros, namespaces

Doxygen automatically generates links to these elements if they are written in a manner that is similar to how functions/methods are written (with the obvious exception that overloads, arguments and modifiers are not relevant here):

  • Elements within the same context (e.g. within the same class) either do not require a prefix, or possibly the prefix "#"
  • Elements within a different context (e.g. within a different class) required the prefix "<context>::"
  • Special case: If the other context is the global context, the prefix to use is "::"


Examples:

/// @file foo.h
/// @brief We are documenting a file, therefore we are now in the global context
///
/// A link to a member variable of a class
/// - MyClass::m_protectedMemberVariable
///
/// A link to a member function of a class
/// - MyClass::protectedMemberFunction()
///
/// A link to a global enumeration
/// - ::GlobalEnumeration
/// - OR #GlobalEnumeration
///
/// A link to a value of a global enumeration
/// - ::GlobalEnumerationValue1
/// - OR #GlobalEnumerationValue1
///
/// A link to an in-class enumeration
/// - MyClass::MyClassEnumeration
///
/// A link to a value of an in-class enumeration
/// - MyClass::MyClassEnumerationValue1
///
/// A link to a global variable
/// - ::globalCounter
/// - OR #globalCounter
///
/// A link to a global function
/// - globalFunction()
/// - OR ::globalFunction()
/// - OR #globalFunction()
///
/// A link to a preprocessor macro
/// - ::A_GLOBAL_DEFINE
/// - OR #A_GLOBAL_DEFINE
///
/// A link to a typedef
/// - ::TypedeffedChar
/// - OR #TypedeffedChar
///
/// A link to a namespace
/// - ToplevelNamespace
///
/// A link to a namespace member
/// - ToplevelNamespace::namespaceCounter


/// @class MyClass
/// @brief We are documenting a class, therefore we are now in a class context
///
/// A link to a member variable of the same class
/// - #m_protectedMemberVariable
///
/// A link to a member function of the same class
/// - protectedMemberFunction()
///
/// A link to a global enumeration
/// - ::GlobalEnumeration
/// - OR #GlobalEnumeration
///
/// A link to a value of a global enumeration
/// - ::GlobalEnumerationValue1
/// - OR #GlobalEnumerationValue1
///
/// A link to an in-class enumeration of the same class
/// - #MyClassEnumeration
///
/// A link to a value of an in-class enumeration of the same class
/// - #MyClassEnumerationValue1
///
/// A link to a global variable
/// - ::globalCounter
/// - OR #globalCounter
///
/// A link to a global function
/// - globalFunction()
/// - OR ::globalFunction()
/// - OR #globalFunction()
///
/// A link to a preprocessor macro
/// - ::A_GLOBAL_DEFINE
/// - OR #A_GLOBAL_DEFINE
///
/// A link to a typedef
/// - ::TypedeffedChar
/// - OR #TypedeffedChar
///
/// A link to a namespace
/// - ToplevelNamespace
///
/// A link to a namespace member
/// - ToplevelNamespace::namespaceCounter
///
/// A link to a global function or a member function of the same name
/// - duplicateFunction()        -> member function
/// - ::duplicateFunction()      -> global function
/// - #duplicateFunction()       -> member function


The @ref command

The @ref command is used to create links to almost any documented element within a Doxygen project.

Although you could use @ref to create links to source code entities (e.g. classes, functions, etc.) there is not much point in doing so because, as described in the previous sections, Doxygen automatically creates links to source code entities if you follow certain rules how to write the entity names. The main use of @ref therefore is to create links to documentation elements that are not source code entities, such as groups, pages, sections, and others.

@ref might also be useful if you want to link to a source code entity, but you want the link to be displayed with a custom-defined text.

Examples:

/// Create a reference to group1, the link text used is the title of the group
/// - @ref group1
///
/// Create a reference to page1, the link text is custom-defined (instead of the title of the page)
/// - @ref page1 "a custom-defined link text"


Other special commands

@todo

The @todo command creates a paragraph within a documentation block that describes a TODO item. Doxygen automatically generates an index of all TODO items and places a link to that index into the top-level "Related Pages" list, under the name of "Todo List".

Example:

/// @todo This is the description of a TODO item.
/// The text may span multiple lines.


@bug

The @bug command works exactly the same as the @todo command, but it allows to document bugs. A link to the generated bug index is placed into "Related Pages" under the name of "Bug List".


@example

Smaller code examples can be embedded into a documentation block using the @code/@endcode commands. If a code example becomes too large, however, it is better to move the code into a separate file and instead place a reference to that file into the documentation block. The command to use here is @example, but some rules need to be observed:

  • In the Doxyfile configuration file the parameter "EXAMPLE_PATH" must point to the folder that contains the example files
  • All example files must be placed in that folder, or one of its subfolders
  • The @example command references the example file relative to "EXAMPLE_PATH"
  • The @example command must be placed inside its own comment block, it cannot be part of another block. The documentation in the @example block, taken together with the example code in the external file, results in a new page.


Example:

---------- Doxyfile ----------
EXAMPLE_PATH = ./examples

---------- DoxygenExampleDefinitions.h ----------
/// @file
/// @brief Pseudo header file that does not contain code but serves as
/// a container for Doxygen example documentation blocks. To reference
/// the example from somewhere else, you reference to this pseudo
/// header file.
/// 
/// @example Example1.cpp
/// This is an example of how to use the YourClass class.

---------- examples/Example1.cpp ----------
int main(int argc, char** argv)
{
  YourClass yc;
  yc.doIt();
  
  return 0;
}


Doxyfile configuration

Default configuration

The traditional name of the Doxygen configuration file is

Doxyfile 

The configuration file is a text file that can be edited with any text editor. There are several ways how a new Doxyfile with a default configuration can be created:

  • Doxywizard
    • Run the Doxywizard application
    • Settings -> Reset to factory defaults
    • File -> Save as...
    • Custom settings can be made on the "Expert" tab
  • Doxygen command line utility
    • Run this command: doxygen -g
    • This generates a file named Doxyfile in the current working directory


Diagrams

On its own, Doxygen is capable of creating simple text-based class diagrams. With the help of the additional software GraphViz, Doxygen can generate additional graphics-based diagrams, optionally in UML style. Drawing graphics-based diagrams, however, requires more CPU power, so it may easily take 2-3 times as long to generate a documentation set.

To enable GraphViz support in Doxygen, the Doxyfile parameter "HAVE_DOT" must be set to "Yes".


Important configuration options

The most important Doxyfile configuration options in a new project are:

  • Project
    • PROJECT_NAME
    • OUTPUT_DIRECTORY
  • Build
    • EXTRACT_PRIVATE (if you want private members to be also included in the documentation)
    • EXTRACT_STATIC (if you want static members to be also included in the documentation)
    • SORT_GROUP_NAMES (if you want groups to be sorted alphabetically instead of in the order of their appearance)
  • Input
    • INPUT
    • INPUT_ENCODING (the default is UTF-8)
    • RECURSIVE
    • EXAMPLE_PATH
    • USE_MDFILE_AS_MAINPAGE
  • Index
    • ALPHABETICAL_INDEX
  • HTML
    • GENERATE_HTML
    • HTML_DYNAMIC_SECTIONS
    • GENERATE_TREEVIEW
  • LaTex
    • GENERATE_LATEX
  • Preprocessor
    • ENABLE_PREPROCESSING
  • External
    • TAGFILES
    • GENERATE_TAGFILE
  • Dot
    • CLASS_DIAGRAMS
    • HAVE_DOT
    • UML_LOOK
    • DOT_PATH


Ambiguities in the Doxygen manual

Not sure if the following points are still true, they were written many years ago...

  • The Doxygen manual has this to say about the @subpage command: "Each page can be the sub page of only one other page and no cyclic relations are allowed, i.e. the page hierarchy must have a tree structure.". Actually, it is possible to refer to a sub-page from more than one parent page - at least the reference to the sub-page correctly appears in the parent page. The only error that I know about: When the user navigates to the sub-page, the breadcrumb trail shows the parent page that was parsed last during the documentation run.
  • The Doxygen manual has this to say about the @section, @subsection, @subsubsection and @paragraph commands: "This command only works inside related page documentation and not in other documentation blocks!". This description is misleading, as it implies that structuring commands can only be used in @page documentation blocks. This is corroborated by the fact that structuring examples are only made for the @page context. In fact, structuring commands can be used in any documentation block that leads to the creation of its own page (e.g. groups, classes, namespaces, files, etc.).
  • The Doxygen manual does not mention whether a page can be added to a group using the @ingroup command. If you do it, the page no longer appears in the index of all pages. Instead, the content of the page is shown inline on the module page. It is not clear whether this is intentional or by accident. Regardless, I consider this to be a bug.