Doxygen

From FreeCAD Documentation
Revision as of 18:44, 16 July 2019 by Vocx (talk | contribs) (→‎Doxygen with Python code: Examples for the two documentation styles)
Future home of tutorial how to write doxygen for FreeCAD Source_documentation#How_to_integrate_doxygen_in_to_the_FreeCAD_source_code

Doxygen is a popular tool for generating documentation from annotated C++ sources, but it also supports other popular programming languages such as C#, PHP, Java, and Python. Visit Doxygen website to learn more about the system.

This document gives a brief introduction to Doxygen, in particular how it is used with FreeCAD to document its sources. See the Doxygen Manual for the full information on its usage.

Doxygen with C++ code

The Getting started (Step 3) section of the Doxygen manual mentions the basic ways of documenting the sources.

For members, classes and namespaces there are basically two options:

  1. Place a special "documentation block" in front of the declaration or definition of the function, member, class or namespace. For file, class and namespace members it is also allowed to place the documentation directly after the member. See section Special comment blocks to learn more about these blocks.
  2. Place a special documentation block somewhere else (another file or another location) and put a "structural command" in the documentation block. A structural command links a documentation block to a certain entity that can be documented (e.g. a function, member, class, namespace or file). See section Documentation at other places to learn more about structural commands.

Note:

  • The advantage of the first option is that you do not have to repeat the name of the entity (function, member, class, or namespace), as Doxygen will analyze the code and extract the relevant information.
  • Files can only be documented using the second option, since there is no way to put a documentation block before a file. Of course, file members (functions, variables, typedefs, defines) do not need an explicit structural command; just putting a special documentation block before or after them will work fine.

First style: documentation block before the code

Usually you'd want to document the code in the header file, just before the class declaration or function prototype. This keeps the declaration and documentation close to each other, so it's easy to update the latter one if the first one changes.

The special documentation block starts like a C-style comment /* but has an additional asterisk, so /**. The block ends with a matching */. An alternative is using C++-style comments // with an additional slash, so ///.

/**
 * Returns the name of the workbench object.
 */
std::string name() const;

/**
 * Set the name to the workbench object.
 */
void setName(const std::string&);

/// remove the added TaskWatcher
void removeTaskWatcher(void);

Second style: documentation block elsewhere

Alternatively, the documentation can be placed in another file (or in the same file at the top or bottom, or wherever), away from the class declaration or function prototype. In this case, you will have duplicated information, once in the actual source file, and once in the documentation file.

First file, source.h:

std::string name() const;
void setName(const std::string&);

Second file, source.h.dox:

/** \file source.h
 *  \brief The documentation of source.h
 *   
 *   The details of this file go here.
 */

/** \fn std::string name() const;
 *  \brief Returns the name of the workbench object.
 */
/** \fn void setName(const std::string&);
 *  \brief Set the name to the workbench object.
 */

In this case the structural command \file is used to indicate which source file is being documented; a structural command \fn indicates that the following code is a function, and the command \brief is used to give a small description of this function.

This way of documenting a source file is useful if you just want to add documentation to your project without adding real code. When you place a comment block in a file with one of the following extensions .dox, .txt, or .doc then Doxygen will parse the comments and build the appropriate documentation, but it will hide this auxiliary file from the file list.

The FreeCAD project adds several files ending in .dox in many directories in order to provide a description, or examples, of the code there. It is important that such files are correctly categorized in a group or namespace, for which Doxygen provides some auxiliary commands like \defgroup, \ingroup, and \namespace.

Example src/Base/core-base.dox; this file in FreeCAD's source tree gives a short explanation of the Base namespace.

/** \defgroup BASE Base
 *  \ingroup CORE
    \brief Basic structures used by other FreeCAD components
    
    The Base module includes most of the basic functions of FreeCAD, such as:
    - Console services: printing different kinds of messages to the FreeCAD report view or the terminal
    - Python interpreter: handles the execution of Python code in FreeCAD
    - Parameter handling: Management, saving and restoring of user preferences settings
    - Units: Management and conversion of different units

*/

/*! \namespace Base
    \ingroup BASE
    \brief Basic structures used by other FreeCAD components

    The Base module includes most of the basic functions of FreeCAD, such as:
    - Console services: printing different kinds of messages to the FreeCAD report view or the terminal
    - Python interpreter: handles the execution of Python code in FreeCAD
    - Parameter handling: Management, saving and restoring of user preferences settings
    - Units: Management and conversion of different units
*/

Another example is the file src/Gui/Command.cpp. Before the implementation details of the Gui::Command methods, there is a documentation block that explains some details of the command framework of FreeCAD. It has various \section commands to structure the documentation. It even includes example code enclosed in a pair of \code and \endcode keywords; when the file is processed by Doxygen this code example will be specially formatted to stand out. The \ref keyword is used in several places to create links to named sections, subsections, pages or anchors elsewhere in the documentation. Similarly, the \see or \sa commands print "See also" and provide a link to other classes, functions, methods, variables, files or URLs.

Example src/Gui/Command.cpp

/** \defgroup commands Command Framework
    \ingroup GUI
    \brief Structure for registering commands to the FreeCAD system
 * \section Overview
 * In GUI applications many commands can be invoked via a menu item, a toolbar button or an accelerator key. The answer of Qt to master this
 * challenge is the class \a QAction. A QAction object can be added to a popup menu or a toolbar and keep the state of the menu item and
 * the toolbar button synchronized.
 *
 * For example, if the user clicks the menu item of a toggle action then the toolbar button gets also pressed
 * and vice versa. For more details refer to your Qt documentation.
 *
 * \section Drawbacks
 * Since QAction inherits QObject and emits the \a triggered() signal or \a toggled() signal for toggle actions it is very convenient to connect
 * these signals e.g. with slots of your MainWindow class. But this means that for every action an appropriate slot of MainWindow is necessary
 * and leads to an inflated MainWindow class. Furthermore, it's simply impossible to provide plugins that may also need special slots -- without
 * changing the MainWindow class.
 *
 * \section wayout Way out
 * To solve these problems we have introduced the command framework to decouple QAction and MainWindow. The base classes of the framework are
 * \a Gui::CommandBase and \a Gui::Action that represent the link between Qt's QAction world and the FreeCAD's command world. 
 *
 * The Action class holds a pointer to QAction and CommandBase and acts as a mediator and -- to save memory -- that gets created 
 * (@ref Gui::CommandBase::createAction()) not before it is added (@ref Gui::Command::addTo()) to a menu or toolbar.
 *
 * Now, the implementation of the slots of MainWindow can be done in the method \a activated() of subclasses of Command instead.
 *
 * For example, the implementation of the "Open file" command can be done as follows.
 * \code
 * class OpenCommand : public Command
 * {
 * public:
 *   OpenCommand() : Command("Std_Open")
 *   {
 *     // set up menu text, status tip, ...
 *     sMenuText     = "&Open";
 *     sToolTipText  = "Open a file";
 *     sWhatsThis    = "Open a file";
 *     sStatusTip    = "Open a file";
 *     sPixmap       = "Open"; // name of a registered pixmap
 *     sAccel        = "Shift+P"; // or "P" or "P, L" or "Ctrl+X, Ctrl+C" for a sequence
 *   }
 * protected:
 *   void activated(int)
 *   {
 *     QString filter ... // make a filter of all supported file formats
 *     QStringList FileList = QFileDialog::getOpenFileNames( filter,QString::null, getMainWindow() );
 *     for ( QStringList::Iterator it = FileList.begin(); it != FileList.end(); ++it ) {
 *       getGuiApplication()->open((*it).latin1());
 *     }
 *   }
 * };
 * \endcode
 * An instance of \a OpenCommand must be created and added to the \ref Gui::CommandManager to make the class known to FreeCAD.
 * To see how menus and toolbars can be built go to the @ref workbench.
 *
 * @see Gui::Command, Gui::CommandManager
 */

Doxygen markup

All Doxygen documentation commands start with a backslash \ or an at-sign @, at your preference. Normally the backslash \ is used, but occasionally the @-sign is used to improve readability.

The commands can have one or more arguments. In the Doxygen manual the arguments are described as follows.

  • If <sharp> braces are used the argument is a single word.
  • If (round) braces are used the argument extends until the end of the line on which the command was found.
  • If {curly} braces are used the argument extends until the next paragraph. Paragraphs are delimited by a blank line or by a section indicator.
  • If [square] brackets are used the argument is optional.

Some of the most common keywords used in the FreeCAD documentation are

  • \defgroup <name> (group title) , see \defgroup, and Grouping.
  • \ingroup (<groupname> [<groupname> <groupname>]), see \ingroup, and Grouping.
  • \addtogroup <name> [(title)], see \addtogroup, and Grouping.
  • \author { list of authors }, see \author; indicates the author of this piece of code.
  • \brief { brief description }, see \brief; briefly describes the function.
  • \file [<name>], see \file; documents a source or header file.
  • \page <name> (title), see \page; puts the information in a separate page, not directly related to one specific class, file or member.
  • \package <name>, see \package; indicates documentation for a Java package (but also used with Python).
  • \fn (function declaration), see \fn; documents a function.
  • \section <section-name> (section title), see \section; starts a section.
  • \subsection <subsection-name> (subsection title), see \subsection; starts a subsection.
  • \namespace <name>, see \namespace; indicates information for a namespace.
  • \cond [(section-label)], and \endcond, see \cond; defines a block to conditionally document or omit.
  • \a <word>, see \a; displays the argument in italics for emphasis.
  • \param [(dir)] <parameter-name> { parameter description }, see \param; indicates the parameter of a function.
  • \return { description of the return value }, see \return; specifies the return value.
  • \sa { references }, see \sa; prints "See also".
  • \note { text }, see \note; adds a paragraph to be used as a note.

Doxygen with Python code

Doxygen works best for statically typed languages like C++. However, it can also create documentation for Python files.

There are two ways to comment Python:

  1. The Pythonic way, using "docstrings", that is, a pair of triple quotes ''' immediately after the class or function definition.
  2. The Doxygen way, putting comments before the class or function definition; in this case double pound signs ## should start the comment, and then single pound signs can be used in subsequent lines.

Note:

  • The first option is preferred to comply with PEP8, PEP257 and most style guidelines for writing Python (see 1, 2). However, in this way Doxygen special commands don't work.
  • The second option isn't the traditional Python style, but it allows you to use Doxygen's special commands like \param and \var.

First style: Pythonic documentation

One docstring at the beginning to explain the general contents of this module (file). Then docstrings inside the function, class, and class method definitions. In this way, Doxygen will extract the documentation and present it as is.

'''@package docstring
Documentation for this module.
More details.
'''
def func():
    '''Documentation for a function.
    More details.
    '''
    pass
class PyClass:
    '''Documentation for a class.
    More details.
    '''
   
    def __init__(self):
        '''The constructor.'''
        self._memVar = 0
   
    def PyMethod(self):
        '''Documentation for a method.'''
        pass

Second style: documentation block before the code

The documentation blocks start with a double pound sign. One at the beginning to explain the general content of this module (file). Then blocks before the function, class, and class method definitions, and one block after a variable. In this way, Doxygen will extract the documentation, recognize the special commands @package, @param, and @var, and format the information accordingly.

## @package pyexample
#  Documentation for this module.
#
#  More details.
## Documentation for a function.
#
#  More details.
def func():
    pass
## Documentation for a class.
#
#  More details.
class PyClass:
   
    ## The constructor.
    def __init__(self):
        self._memVar = 0
   
    ## Documentation for a method.
    #  @param self The object pointer.
    def PyMethod(self):
        pass
     
    ## A class variable.
    classVar = 0;
    ## @var _memVar
    #  a member variable

Parsing of documentation blocks

The text inside a special documentation block is parsed before it is written to the HTML and LaTeX output files. During parsing the following steps take place:

  • Markdown formatting is replaced by corresponding HTML or special commands.
  • The special commands inside the documentation are executed. See section Special Commands for an overview of all commands.
  • If a line starts with some whitespace followed by one or more asterisks (*) and then optionally more whitespace, then all whitespace and asterisks are removed.
  • All resulting blank lines are treated as a paragraph separators. This saves you from placing new-paragraph commands yourself in order to make the generated documentation readable.
  • Links are created for words corresponding to documented classes. If the word is preceded by a %-sign, then sign will be removed and the word won't be linked.
  • Links to members are created when certain patterns are found in the text. See section Automatic link generation for more information.
  • HTML tags that are in the documentation are interpreted and converted to \LaTeX equivalents for the \LaTeX output. See section HTML Commands for an overview of all supported HTML tags.

FreeCAD doxygen

FC doxygen formatting

The FC project has chosen the following method for it's doxygen comment blocks: As it's special char of choice

  • \note ex. \note added in FreeCAD 0.17

Note: Please also read: https://github.com/FreeCAD/FreeCAD/blob/master/src/Doc/doctips.dox