1. 1. Proposal for Doxygen usage

Version as of 22:16, 25 Aug 2019

to this version.

View current version

In order to finally have a real development manual we need to automate the process of generating a cross-linked index of functions. doxygen can do that, but it requires special format comments in all the header files. It would also be good to check which functions are used only from their own C file, (i.e. test whether they can be made static).

• In general, spend time explaining WHY, not how. Explain the algorithm you use for your fancy new sort algorithm and provide a reference to it, rather than writing "go through all elements" before the for-loop. Most programmers will figure out the latter after a minute anyway :-)

Some parts of the source already contain Doxygen comments (thread_mpi and selection libraries, and some nonbonded kernel stuff). Autoconf also generates an input file for Doxygen in the root of the tree, but the contents of the file could be improved by only specifying the necessary options.

This project should start with deciding where we want different kinds of comments to appear. Points to consider:

• What to document in the source, and what to document separately, e.g., in a wiki? For the high-level design, it could be easier to write the design on the wiki, and later use that as part of the documentation, so a line should be drawn somewhere on what belongs to the wiki and what belongs to the source code.
• We probably want at least the brief description in the header files. How about other API documentation like longer descriptions and parameter lists? In the header files or source files? Having them in the header makes the header a complete description of the API, but then 90% of the lines in the header can easily be comments. Having them in the source has them close to the actual implementation, and is more consistent for static functions that can only be documented in the source.
• Comments that describe how things are implemented but do not influence the API should probably go into the source file, and perhaps marked with \internal so that they can be excluded from the documentation.
• We probably want at least two different levels of documentation generated from the source: public API documentation and full documentation for Gromacs developers. If these two suffice, it is probably easiest to use \internal for comments that are not part of the public API. One should probably write guidelines for where to put the \internal command; for example, setting the documentation for a file to be completely internal actually excludes also all functions in that file without explicitly specifying the command for each of them, and we might or might not want to use that.
• What style of Doxygen comments to use? Most of the existing comments now use Qt style comments (/*! */, \command), but the selection code uses JavaDoc comments (/** */, @command) for brief comments with JAVADOC_AUTOBRIEF turned on, because //! doesn't work in C89. Mixed comments work without problems, but consistency would be a good thing.
• How to organize the documentation? Doxygen allows for documentation pages that are not directly associated with any files, so these should have some common structure across the whole source. Labels on these pages are also global, which means that they should be carefully named. Currently, the main page is generated from include/mainpage.h. Doxygen also makes it possible to define groups that can contain functions, classes, files etc., in practice anything that you can document with Doxygen, and these groups can also contain documentation. Functions, typedefs etc. can belong to only one group, but classes, files, and other compound objects can belong to multiple groups. This makes groups particularly useful for C++ code, where there are only few functions outside classes. We could have, e.g., a group for each module, and a separate group for all public API functions.

## Proposal for Doxygen usage

Here's a proposal of how things could be done (for C++, some of the grouping stuff doesn't work that well for C code). Feel free to comment and/or add things.

General things:

• Use the Qt-style comments, like this:
/*! \brief
* Performs a simple operation.
*
* \param[in] value  Input value.
* \retval 0 on success.
*
* Detailed description.
*/
int function(int value);

• If there is only a brief description, it can be specified with "//! Brief description."
• After adding a significant amount of comments, run it through doxygen with all the different settings (setting files generated by cmake at the root of the build tree) to see that the result is what you want. Pay attention to warnings that Doxygen generates when you run it, but notice that in order to hide some things from the public API documentation, it may be necessary to accept some warnings when using these settings (Doxyfile-user in particular).

How to document classes, functions etc:

• Document the usage of all elements in the header file where they are defined if there is one. Implementation-specific comments that don't influence how the function is used should go into the the source file, with an \internal tag in the beginning of the comment block.
• For every entity that is part of the public API, add a \inpublicapi command at the end of the documentation block. For entities that are designed to be used outside their module within the library, but that users would not normally use, put a \inlibraryapi command at the end and \libinternal in the beginning. For intra-module entities, put \internal in the beginning. These commands are redefined in the different configuration files to generate a group containing the public API, and to control whether to generate documentation for the intra-library API. There are also conditional sections called libapi and internal for use with \if and \cond. For top-level entities, add a \ingroup module_MODULENAME at the end (see more instructions about documenting modules at the end). Example:

/*! [\[lib]internal] \brief
* Brief description.
*
* More details.
*
* [\in(public|library)api]
* \ingroup module_MODULENAME
*/
class SimpleClass
• If there is a lot of entities in the same file that should all be added, you can use (should go inside all namespace declarations to work properly):
/*! \addtopublicapi
* \{
*/

<declarations>

/*!\}*/
• There is a similar construct \addtolibraryapi, but that should be used with care, as it can easily add unintended functions to be visible in the public API docs. TODO: figure out how it should be used to not to cause that.
• Classes appear always in Doxygen documentation, even if their enclosing file is not documented. So start the documentation blocks of classes that are not part of the public API with \internal or \libinternal.
• For base classes, the API classification (\inpublicapi/\inlibraryapi) should be based on where the class is meant to be subclassed. The visibility (\internal/\libinternal), in contrast, should reflect the API classification of derived classes such that the base class documentation is always generated together with the derived classes.
• For classes that are meant to be subclassed and have protected members, the protected members should only appear at the documentation level where the class is meant to be subclassed. E.g., if a class is meant to be subclasses only within a module, the protected members should only appear in the documentation generated from Doxyfile, but not from Doxyfile-lib or Doxyfile-user. This can be accomplished using \cond with the defined section names internal and libapi (TODO: this causes warnings in some situations, even though the generated documentation is as it should be, figure out if there is a better way). Notice that \cond does not work properly inside //! comments, at least in Doxygen 1.7.3. Example of what works:
protected:
/*! \cond internal */

<declarations>

//! \endcond


How to document files:

• In each file, add a comment block that describes the contents of the file right after the copyright notice. Mark the block with the \internal or \libinternal tag if it is not part of the public API (mark all source files with \internal as well). Format the comment block like this:
/*! [\[lib]internal] \file
* \brief
* Brief description of the file.
*
* More details on the file if needed.
*
* \author Author Name <author.name@email.com>
* [\in(public|library)api]
* \ingroup module_MODULENAME
*/
• Following the logic for base classes, the API classification (\inpublicapi/\inlibraryapi) should be based on where the header is meant to be directly included. The visibility (\internal/\libinternal) should reflect the API classification of any headers that indirectly cause the header to be included. Hence, any installed headers (i.e., headers indirectly included by public API headers) should not have a \internal/\libinternal specifier.
• All source and test files should be documented with \internal in the beginning.
• When you make significant modifications to a file, you should add an \author line for yourself.

Documenting modules:

• For each module, decide on a header file that is the most important one for that module. In that header, add a documentation block like this (replace NAME with the directory name of the module, and group_utilitymodules with the proper group for the module):
/*! \defgroup module_NAME Title of the module
* \ingroup group_utilitymodules
* \brief
* Brief description of the module.
*
* Detailed description of the purpose and API of the module.
* Should link to the header files and the most important functions/classes
* in the module.
*
* \author Author Name <author.name@email.com>
*/
• For all compound entities (in doxygen terminology: classes, files, namespaces) that belong to the module, add a \ingroup module_NAME to the end of the documentation block. This can't be done for functions, typedefs or enums that are part of the public API, because these can only belong to one group.