libSBML C++ API  5.20.2
Documentation conventions for libSBML

1. Introduction

This document is a collection of guidelines for libSBML authors to follow when writing documentation for libSBML code.

LibSBML's application programming interface (API) is documented using a combination of tools. For almost all languages (C++, C#, C, Python, and others), the cornerstone of the approach is the open-source software tool Doxygen; for Java, we use Javadoc instead. We write the documentation in source code and auxiliary files in a way that both Javadoc and Doxygen can process more or less equally, which requires that programmers and documentation authors follow various conventions described in the rest of this document. In addition, we use various home-grown scripts and programs to massage the output of SWIG to produce something that can be fed to the Doxygen and Javadoc-based processs.

2. Basic guidelines for libSBML

The guidelines presented in this section are oriented towards explaining how to organize code comments such that Doxygen and Javadoc can produce good output, yet simultaneously make the comments in the libSBML code files be readable on their own.

  • Although Doxygen keywords/tags can be prefixed with either @ or \\, Javadoc only understands keywords prefixed with @. Consequently, always use the @ prefix for keywords so that they will be understood by both Doxygen and Javadoc.
  • The main types of Doxygen comments consist of a C-style comment block beginning with two asterisks (*) characters, as in the following example:
    /**
     * Comments that start with two asterisks within which commands
     * understood by Doxygen will begin with the character @.
     */ 
    
    Another type of Doxygen comment, used to document enumeration members, begins with /*!< . If your code documentation does not appear inside a comment block that begins with /** or the more rarely-needed /*!< , then it will be ignored by Doxygen. This may or may not be what you want, depending on the intention behind the comment.
  • Comments that begin with one asterisk (i.e., /* ... , or two forward slashes (i.e., // ...) are not processed by Doxygen and not entered in the formatted user guide. You can use such comments normally to comment the code for other developers.
  • Doxygen comment blocks can appear at the beginning of a file, in front of a class declaration, in front of method declarations, in front of function declarations, and in front of data structure definitions.
  • Doxygen reads both .h and .cpp files. If a class member (i.e., a method or data member) has /** comment blocks in both the .h and .cpp files, the text is combined in the final output for that class member. This frequently leads to accidentally duplicated text in the final output, and generally is a maintenance headache. To avoid this, and to simplify maintenance of documentation, only put documentation comments in the .h files.
  • Please write in complete sentences, with correct English grammar and punctuation. Do not treat new lines as new sentences or beginnings of different comments. Here is an example of what should be avoided:
    /**
     * creates a foo object
     * given arg is the template
     */
    
    The text above doesn't end sentences with periods, doesn't begin sentences with capitals, doesn't form complete sentences, etc. When Doxygen is used to generate HTML documentation from this, it turns into one long run-on paragraph, and it's unreadable.
  • We use a feature of Doxygen that makes it use the first sentence of a documentation comment as the "brief" description of the entity being described (which may be a class, a method, a class data member, a function, a typedef, etc.). This means that the first sentence up to a period or a blank line will be pulled out separately and used as a one-line summary in certain contexts by Doxygen. The following is an example:
    /**
     * This is the brief description.  After the first sentence, even if
     * you continue writing in the same paragraph, the output nevertheless
     * is split after the first sentence such that everything else is part of
     * the detailed description and not the brief one-sentence description.
     * This example would produce two paragraphs in the formatted output:
     * one paragraph containing the first sentence, and the rest of the
     * text in the second paragraph.
     *
     * If you also have a third paragraph separated by a blank line in the
     * comment, like this, then this third paragraph becomes a third paragraph
     * in the output.  This part is what most people would expect would happen.
     */
    
    Consequently, to emphasize this and remind people that this is going to happen when the API documentation is generated, it is better to format the comment such that there is a paragraph break after the first sentence, as follows:
    /**
     * This is the brief description.
     *
     * This is the beginning of the detailed description....
     */
    
    The visual split in the source makes it more obvious what's going to happen.
  • Doxygen automatically turns entity names it recognizes in text into links to the definition of that entity. This is usually what you want to have happen; for example, when describing the Model class, you may mention classes such as Species and Compartment, and those should be turned into convenient links to their definitions in the API documentation. However, sometimes you don't want that to happen. To prevent Doxygen from linking a word, put a percentage sign (%) in front of it, as in %Model. Doxygen will remove the percentage sign and leave the rest of the word unlinked, resulting in the plain word Model appearing in the finished document.
  • Sometimes methods are meant to be part of the internal implementation and not advertised to users of the library. To make Doxygen ignore methods, wrap their declarations in the .h files with the comment
    /** @cond doxygenLibsbmlInternal */
    
    at the beginning and
    /** @endcond */
    
    at the end of the block. This is merely a convention used in libSBML and not something that Doxygen defines; we simply use the normal Doxygen conditional test operator @cond and give it a symbol we never define: "doxygenLibsbmlInternal". The symbol name is chosen to suggest the purpose. Note: if there are multiple methods to be marked in this way, wrap them individually, placing the @cond and @endcond pairs immediately before and after each method. This makes it much more likely that a reader will notice what is happening in the source files. The alternative approach (putting single @cond and @endcond pairs around a group of methods) makes it much harder to determine which methods are marked as internal in a file.
  • If an entire file should be omitted from the user documentation, use the same @cond doxygenLibsbmlInternal method but put the conditional near the top of the file and the @endcond at the very end of the file. In other words, the top of your file should look like this example:
    /**
     * @cond doxygenLibsbmlInternal
     *
     * @file    ExpatAttributes.cpp
     * @brief   Creates new XMLAttributes from "raw" Expat attributes.
     * ...
    
  • Always put a @class declaration in every file for every class, even if they are marked as internal using the @cond doxygenLibsbmlInternal method described above. Due to the way our documentation toolchain works, in order for Doxygen and Javadoc to see the markers we insert to indicate internal classes and methods, it is necessary for classes to have an @class declaration even if a file has the @cond doxygenLibsbmlInternal guards around it. In other words, the file still needs to have the @class definition for things to work. The easiest convention to adopt is simply to always put the @class and @sbmlbrief pairs in every class, no matter what. If the file is for internal code, then also put the @cond doxygenLibsbmlInternal around the entire contents inside. The use of @sbmlbrief and @class is discussed further in Section 3.1 Guidelines for .h files below.
  • Do not use @retval for describing return values; instead, use @return because (1) it is what Javadoc uses and (2) the narrative form of @return lets you provide more contextual information and other details in describing the return value(s) of a method or function.
  • Please try to limit the lengths of lines in all files to 79 characters long or less. This makes code and documentation generally easier to read and edit in different software tools. Sometimes it's too difficult to avoid a long line, and then it's okay, but generally it's possible to reformat code in such away as to keep things to 79 characters.
  • Please write sentences with two (2) spaces after the terminating period, not one. This makes the resulting text easier to read during editing, compared to when sentence-ending periods are followed by only one space. (Note that this concerns the readability and editability of source code, not the appearance of rendered output. The finished typeset output will not have two spaces after every sentence-ending period; it will have one or slightly more than one, depending on the output format produced. The reason two-spacing is important for the source is that most people use monospaced fonts in their text editors and IDEs, and when using monospaced fonts, the ends of sentences are much easier for human eyes to pick out when two-spacing is used. Further, text editing programs such as Emacs and vi have special features to recognize sentences based on this pattern, and proficient users of those editors can make use of sentence-oriented editing commands. This is a convention that some people disagree with. Please use this convention for libSBML anyway.)

3. Guidelines for different file types

Below are explanations of how to write documentation for the most common types of files encountered in libSBML.

3.1 Guidelines for .h files

It is important to note that the documentation of global functions, variables, typedefs, and enums will only be included in the output of Doxygen if the file they are in is also documented.

  • Here is a template header file suitable for use when creating a new .h file for libSBML (and in fact, it's the same for .cpp files, too). Of course, you should substitute appropriate content for the text in square brackets ([ and ]) below. Note also that the Doxygen keywords @file, @brief and @author are not followed by colon (':') characters.
    /**
     * @file    [filename]
     * @brief   [succinct description of what's in this file]
     * @author  [author's name]
     * 
     *<!---------------------------------------------------------------------------
     * This file is part of libSBML.  Please visit http://sbml.org for more
     * information about SBML, and the latest version of libSBML.
     *
     * Copyright (C) 2019 jointly by the following organizations:
     *     1. California Institute of Technology, Pasadena, CA, USA
     *     2. University of Heidelberg, Heidelberg, Germany
     *
     * Copyright (C) 2013-2018 jointly by the following organizations:
     *     1. California Institute of Technology, Pasadena, CA, USA
     *     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
     *     3. University of Heidelberg, Heidelberg, Germany
     *
     * Copyright (C) 2009-2013 jointly by the following organizations: 
     *     1. California Institute of Technology, Pasadena, CA, USA
     *     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
     *  
     * Copyright (C) 2006-2008 by the California Institute of Technology,
     *     Pasadena, CA, USA 
     *  
     * Copyright (C) 2002-2005 jointly by the following organizations: 
     *     1. California Institute of Technology, Pasadena, CA, USA
     *     2. Japan Science and Technology Agency, Japan
     * 
     * This library is free software; you can redistribute it and/or modify it
     * under the terms of the GNU Lesser General Public License as published by
     * the Free Software Foundation.  A copy of the license agreement is provided
     * in the file named "LICENSE.txt" included with this software distribution
     * and also available online as http://sbml.org/software/libsbml/license.html
     *----------------------------------------------------------------------- -->*/
    
  • When more than one author should be acknowledged for a given file, use multiple @author entries, one per line.
  • A .h file will typically have a class declaration in it. The normal, plain Doxygen way that one would document a class (but we do not do it this way) is to put a comment block immediately in front of the class declaration in the file. However, we have to do it differently because of how our files are used to generate output for multiple language bindings. Thus, for the documentation of classes, please put the documentation in the file header rather that ahead of the class itself in the file. The following example illustrates this procedure (and note how more than one class can be described in the header):
    /**
     * @file    Compartment.h
     * [...]
     *
     * @class Compartment
     * @sbmlbrief{core} Implementation of SBML's %Compartment construct.
     *
     * A compartment in SBML represents a bounded space in which species 
     * are located.  Compartments do not necessarily have to correspond to
     * ....
     *
     * <!-- ------------------------------------------------------------ -->
     * @class ListOfCompartments
     * @sbmlbrief{core} Implementation of SBML's %ListOfCompartments
     * construct.
     * 
     * The various ListOf___ classes in SBML are merely containers used for
     * ....
     */
    
    #ifndef Compartment_h
    #define Compartment_h
    ...
    
  • Use the special keyword @sbmlbrief to indicate the SBML Level 3 package to which a class belongs. This keyword takes one argument, a label for the package; for SBML Level 3 Core code, use the label "core". Place the keyword immediately on the line after each @class declaration in the .h file, and then write a brief one-sentence description of the class after the keyword. The example file fragment above demonstrates this. (As you might guess from its name, the keyword @sbmlbrief is something defined by libSBML's documentation-production system and not a standard Doxygen command.)
  • For each method or data member in the class definition, include a comment block ahead of it, making sure to provide at least a brief description. If it takes parameters, use @param to describe the parameters. If it's a method and the method returns a value, also use @return to describe the returned value. If you also need to refer to the parameters in the textual description of the method, use the @p command. The following example illustrates this:
    /**
     * Creates a new CompartmentType, optionally with the given @p id and
     * @p name attribute values.
     *
     * In SBML, identifiers are required for CompartmentType objects;
     * however, the identifier does not have to be set at the time of
     * creation of the object, and instead can be set using the setId()
     * method on the SBase parent class.
     *
     * @param id a string, the identifier of this CompartmentType instance
     * @param name a string, the optional name of this
     */
    CompartmentType (const std::string& id = "", const std::string& name = "");
    
  • Please try to leave 2 blank lines between method declarations and other items in the definitions of classes. This makes it easier for the eye to spot transitions between method definitions. Here is an example taken from a class definition in a .h file:
    class LIBSBML_EXTERN CompartmentType : public SBase
    {
    public:
    
      /**
       * Creates a new CompartmentType, optionally with the given @p id and @p
       * name attribute values.
       *
       * In SBML, identifiers are required for CompartmentType objects;
       * however, the identifier does not have to be set at the time of
       * creation of the object, and instead can be set using the setId()
       * method on the SBase parent class.
       *
       * @param id a string, the identifier of this CompartmentType instance
       * @param name a string, the optional name of this
       */
      CompartmentType (const std::string& id = "", const std::string& name = "");
    
    
      /**
       * Destroys this CompartmentType.
       */
      virtual ~CompartmentType ();
    
    
      /**
       * Copy constructor; creates a copy of this CompartmentType.
       */
      CompartmentType(const CompartmentType& orig);
    

3.2 Guidelines for .cpp files

The .cpp files can be handled very similarly to the .h files described above. You may use the same header template shown in the previous section about .h files, and all the same guidelines apply.

As noted above, when the API manual is generated by Doxygen, it will use the comments from the .h file as the source of the documentation for the class and methods. It is therefore unnecessary to repeat the class or other descriptions placed in the .h file. However, do provide normal comments (using either the single-asterisk form or the double-slash form of C++ comments) about the code so that in the future, you and others would read the file can better understand what the code is doing.

4. Some important common situations

The descriptions above cover the basics of using Doxygen and Javadoc for libSBML documentation. What follows is a discussion of other, more involved topics.

4.1 Pure functions and constants

This section discusses the special needs of libSBML functions defined outside of any classes, and symbolic constants (both enumerations and #define constants).

4.1.1 Referring to libSBML constants

It's often important to refer to constants such as enumeration values and #define'd symbolic constants. It's very useful to have the names of the constants in the formatted documentation be linked to their definitions, rather than being merely set in a typewriter-style font. However, not only does Doxygen fail to do this automatically, but the link targets need to be different for the different programming languages such as Python, C# and Java. Handling this using plain Doxygen commands leads to a complex and unmaintainable combination of repeated @if clike ... @endif @if java ... @endif @if python ... @endif.

To make it easier to name and link constants consistently, we developed a simple-to-use Doxygen macro that is recognized and treated specially by src/bindings/swig/swigdoc.py. This macro is named @sbmlconstant and takes two required arguments:

@sbmlconstant{symbol,type}

The type is the name of the enumeration (if any) where the symbolic value is defined, and symbol is the name of the value. Note that the symbol appears first in the macro. Here follows an example:

@sbmlconstant{AST_MINUS, ASTNodeType_t}

If the value is a #define constant and not located inside an enumeration, then omit the type argument value; however, leave the comma regardless. For example:

@sbmlconstant{L3P_COLLAPSE_UNARY_MINUS,}

(The need for the comma is because Doxygen does not support optional arguments in alias/macro definitions. Rather than define two separate forms, it seems simpler to have only one—i.e., @sbmlconstant—and simply remember to leave the second argument empty if necessary.)

Finally, sometimes you will want to refer the enumeration type itself rather than a specific value, for example to say something along the lines of "the values are drawn from the enumeration X". Unfortunately, this poses a portability problem, because the enumerations do not explicitly exist outside of C and C++. The simplest way around this problem is to conditionalize the text such that in the case of clike, the text mentions the enumeration name, and otherwise, the text describes integer constants more generally. The following is an example:

   * This uses integer type codes, which may come from
   * @if clike the enumeration #ASTNodeType_t@else the set
   * of static integer constants whose names begin with the prefix
   * AST_ @endif.

In the example above, when the condition is not satisfied (meaning, @if clike is false and thus C/C++ documentation is not being generated), the text above will result in the output "This uses integer type codes, which may come from the of static integer constants whose names begin with the prefix AST_". Such a description works for Java, Python and other languages equally, and while it is not as specific as possible, it is better than attempting to a list all the alternatives explicitly.

4.1.2 Referring to libSBML pure functions

Some functions in libSBML are defined outside of any class. This poses a special challenge for creating hyperlinks, because the names of the functions and their references are different for Python and Java from the basic C, C++ and C# versions. To stop the unreadable and unmaintainable insanity of repeated @if clike ... @endif @if java ... @endif @if python ... @endif (especially because the Java case required explicit HTML a elements and full argument lists, with fully qualified data types), we developed another custom Doxygen macro that is recognized and treated specially by src/bindings/swig/swigdoc.py.

The macro is named @sbmlfunction; it takes the name of the libSBML function, followed by a comma, followed by a list of arguments to the function. The list of arguments is mandatory; if the libSBML function in question takes no arguments, then simply leave the list empty, but keep the comma. In addition, when writing the function name, omit the leading SBML_ part that appears in the function's C/C++ definition; the prefix it will be added automatically for C++ and C# and omitted from the other languages, where libSBML function names are written without the SBML_ part.

The following illustrates the syntax for the case of a function that takes no arguments:

@sbmlfunction{name,}

where name is the name of a libSBML function that takes no arguments. If the function does take arguments, use the arguments as they appear in the Java API. The following is an example of a function that takes a single argument:

@sbmlfunction{name, arg1type}

If the function takes more than one argument, use commas quoted with a backslash to separate multiple arguments from each other. In other words, functions that take multiple arguments should be written like this:

@sbmlfunction{name, arg1type\, arg2type\, ...}

Again, use the argument data types that appear in the Java version of the API. (I.e., use String instead of char *, etc.) Here are two real examples:

@sbmlfunction{parseL3Formula, String}
@sbmlfunction{parseL3FormulaWithSettings, String\, L3ParserSettings}

The data types do not have to be fully qualified. Line breaks may be used to split long lines.

The reason the Java types are used is because the argument list is only used for producing the Java API documentation—in order for the correct hyperlinks to be made, the documentation toolchain (specifically, Javadoc) needs the argument list. (It is not required for the other language API documentation, and is actually ignored when producing non-Java manuals.)

This macro is currently only usable for pure functions in libSBML. It is not designed nor tested for use with methods on classes or other situations.

4.2 Reusing common text

One often encounters the need to repeat the same text in different places in the documentation, such as to add a detail to each method where the detail may be relevant. In software documentation, unlike in non-technical prose or creative writing, it is often better to repeat text—or refer to a common section—everywhere that it might be relevant, because a reader does not normally read class and method documentation linearly: they jump to a method description from elsewhere. This means that the descriptions need to be reasonably self-contained. However, repeating information by copy-pasting text leads to a maintenance nightmare, requiring any updates or changes to be made in multiple places. We avoid this in libSBML by writing common text as reusable blocks, then using text inclusion mechanisms to insert the common text where it is needed.

A surprising limitation of Doxygen is that it only provides two mechanisms for copying repeated text: @htmlinclude, and the @copydoc/@copybrief/@copydetails set of commands. The former has the limitation that the content is not processed by Doxygen at all: it is inserted raw, and @ commands are not interpreted. This means that cross-references are not performed, conditionals are not expanded, etc. Conversely, the latter set of commands can be used to reuse text with Doxygen commands in it, but the commands are oriented towards use in the context of method and data member documentation, and in other contexts have unfortunate behaviors with respect to how they treat the first sentence of the text inside them.

We use both mechanisms, i.e., @htmlinclude and @copydetails (and more rarely, @copydoc) in libSBML, but do so with conventions to work around the behaviors of the latter set of commands.

4.2.1 Using "@copydetails"

Experienced Doxygen users may be initially confused by our use of @copydetails, because strictly speaking, we are not using it exactly as intended. The Doxygen command @copydetails is actually intended for copying the "non-brief" part of the documentation of an object, such as a class, for use in documenting multiple similar objects. It can also be used as a general means of copying text fragments if certain conventions are followed. As mentioned above, compared to @htmlinclude, it has the advantage that Doxygen commands inside the fragment are processed normally, including the automatic linking of cross-reference to classes, methods, and other objects. Consequently, we have resorted to using @copydetails in combination with some conventions to achieve what we need.

  • To define a block of text to be reused, use the @class command and give the class a name that begins with the prefix doc_. Separate the class declaration with a blank line. Here is an example:
    /**
     * @class doc_what_is_listof
     *
     * @par
     * The various ListOf___ classes in SBML are merely containers used for
     * organizing the main components of an SBML model.  ...
     */
    
    We configure Doxygen to ignore symbols that begin with the string doc_, so these class definitions will never really be defined in the formatted output—they are fake class declarations used simply so that we can employ @copydetails elsewhere.
  • Note the use of @par in the example above. This is a hack to force Doxygen to treat the rest of the text as the "detail" portion of a class documentation. Make sure to put @par on a line by itself, or it will not work properly. Special cases: if your text block begins with @note or @warning or similar, you do not need to put the @par first.
  • For readability in the source code file, if you have more than one @class doc_... definition, separate them with an HTML comment consisting of a line of dashes. Example:
    /**
     * @class doc_what_are_sbmlnamespaces
     *
     * @par 
     * The SBMLNamespaces object encapsulates SBML Level/Version/namespaces
     * information.  It is used to communicate the SBML Level, Version, and
     * (in Level&nbsp;3) packages used in addition to SBML Level&nbsp;3
     * Core.  A common approach to using libSBML's SBMLNamespaces facilities
     * is to create an SBMLNamespaces object somewhere in a program once,
     * then hand that object as needed to object constructors that accept
     * SBMLNamespaces as arguments.
     *
     * <!-- ------------------------------------------------------------ -->
     * @class doc_what_is_SBMLDocument
     *
     * @par
     * LibSBML uses the class SBMLDocument as a top-level container for
     */
    
  • To use the text, that is, to insert a text block somewhere in the body of a documentation string, use the command @copydetails followed by the name of the (fake) documentation class. Here is an example:
     * @class ListOfCompartments
     * @sbmlbrief{core} Implementation of SBML Level 2's %ListOfCompartments
     * construct.
     * 
     * @copydetails doc_what_is_listof
    

Finally where should you put these @class definitions for creating reusable text blocks? Use one of the following two locations:

  1. An individual file where references to the block are made (such as a .h file), when the text is specific to that file and never used outside of it; or
  2. The file src/sbml/common/common-documentation.h, when the text is something to be reused in multiple other files.

In general, the use of @copydetails is preferable to the use of @htmlinclude described below, but in some situations you need to resort to the latter command. In some other situations, you may want to copy the entire method documentation for methods that are repeated on every class; for this, you can use @copydoc, described next.

 * @class ListOfCompartments
 * @sbmlbrief{core} Implementation of SBML Level 2's %ListOfCompartments
 * construct.
 * 
 * @copydetails doc_what_is_listof

4.2.2 Using "@copydoc"

As mentioned above, the Doxygen @copydetails command is actually intended for reusing the "details" portion of a method or other member documentation. If you use @copydoc instead, Doxygen will treat the first sentence of the documentation as a "brief" explanation and the rest as the "details". The effect is the following: in summary lists, it only prints the first sentence, and in every other context, it prints the first sentence separated from the rest of the text with a paragraph break. This paragraph-separated behavior is undesirable when you want to reuse text fragments for general purposes. However, sometimes you really do this behavior, in particular to reuse the entire method documentation from one method to another. That is a situation where @copydoc is perfect.

An example of where @copydoc is useful is in the definition of renameSIdRef() virtual methods that are present on many libSBML classes. For this case, we first define one common documentation block in the file src/sbml/common/common-documentation.h mentioned above:

 * @class doc_renamesidref_common
 *
 * Replaces all uses of a given @c SIdRef type attribute value with another
 * value.
 *
 * @copydetails doc_what_is_sidref
 *
 * This method works by looking at all attributes and (if appropriate)
 * mathematical formulas in MathML content, comparing the referenced
 * identifiers to the value of @p oldid.  If any matches are found, the
 * matching values are replaced with @p newid.  The method does @em not
 * descend into child elements.
 *
 * @param oldid the old identifier
 * @param newid the new identifier

Notice how the block above is complete, and includes such things as the definition of parameters with @param. (If return values and other information were appropriate, those would be included as well.) Then, for the definition of renameSIdRef() in each class where it appears, we use @copydoc as follows:

  /**
   * @copydoc doc_renamesidref_common
   */
  virtual void renameSIdRefs(const std::string& oldid, 
                             const std::string& newid);

Of course, for this to make sense, the block of text must match the methods exactly, right down to the use of the same parameter names (oldid and newid in the example above), the return values, the purpose of the method, and so on.

4.2.3 Using "@htmlinclude"

The @copydetails and @copydoc methods described above works well for most situations, except when you need to use significant HTML commands for special formatting. Some HTML commands will either be intercepted by Doxygen, or else it may become very awkward to write the HTML as comments in a .h file. In those cases, using Doxygen's @htmlinclude can be a better option.

The @htmlinclude command takes a single argument, the name of a file. This file must be placed in a preconfigured location; we use the directory docs/src/common-text/ to store files for use with this command. Here is an example of the use of @htmlinclude:

 * The list of possible types is quite long, because it covers all the
 * mathematical functions that are permitted in SBML. The values are shown
 * in the following table:
 *
 * @htmlinclude astnode-types.html

The file will be included in-line at the location where the reference is made in a documentation string.

It is worth reiterating that normal Doxygen processing is not performed inside the contents of the file included through this mechanism. Cross-references will not be made, the Doxygen @ commands will be ignored, etc. For most cases, it is preferable to use the @copydetails approach described in the previous section.

4.3 Links

Most of the time, you can rely on Doxygen's ability to connect a written reference to a class or method to the definition of that class or method. In a few cases, however, you must write an explicit @link ... @endlink command. The syntax of this Doxygen command consists of the target of the link, optionally followed by a name to be used for the link.

In libSBML, the most common situation where an explicit link is needed is in references to enumeration values such as method/function return codes. In those cases, to create a link, use the name of the enumeration (e.g., OperationReturnValues_t), followed by a pound sign (#), followed by the enumeration member, optionally followed by a space and then a name for the link. If the optional space and name are omitted, the name of the link is made the same as the full name of the target; this is generally not desirable because the result is more difficult to read.

Here is an example, drawn from the documentation of the return type of a method on the Compartment class. In these cases, the name of the link is given as simply the name of the enumeration member without the enumeration prefix:

  /**
   * Sets the value of the "id" attribute of this Compartment.
   *
   * The string @p sid is copied.
   *
   * @copydetails doc_id_syntax
   *
   * @param sid the string to use as the identifier of this Compartment
   *
   * @return integer value indicating success/failure of the
   * function.  The possible values
   * returned by this function are:
   * @li @link OperationReturnValues_t#LIBSBML_OPERATION_SUCCESS LIBSBML_OPERATION_SUCCESS @endlink
   * @li @link OperationReturnValues_t#LIBSBML_INVALID_ATTRIBUTE_VALUE LIBSBML_INVALID_ATTRIBUTE_VALUE @endlink
   */
virtual int setId (const std::string& sid);

Another situation that calls for explicit links involves the non-C++ languages. There, it is common to need to refer to a constant defined on the class or package libsbml. Here is an example:

* @if python LibSBML attaches an identifying
* code to every kind of SBML object.  These are known as <em>SBML type
* codes</em>.  In the Python language interface for libSBML, the type
* codes are defined as static integer constants in the interface class
* @link libsbml@endlink.  @endif

4.4 Conditional text

Speaking of non-C++ languages, it very often happens that one needs to adapt the documentation for something based on the programming language. We have configured Doxygen to define different symbols depending on the language for which the output is being generated; these symbols can be used with Doxygen's @if command to introduce text conditionally. The following table lists the symbols defined for different languages:

Language Symbols defined
C conly, clike, doxygenCOnly, doxygenCLikeOnly
C++ cpp, clike, doxygenCppOnly
C# csharp, notclike, doxygenCsharpOnly
Java java, notclike
Perl perl, notclike, doxygenPerlOnly
Python python, notclike, doxygenPythonOnly

Important: Doxygen removes the white space surrounding the text inside the conditional and after the @endif. This is highly problematic in most situations, because it produces run-together text in the output. We believe this is a bug and have reported it to the Doxygen developers, but as of version 1.8.6, the behavior persists. To avoid the problem, use the following hack: unless the next character after @endif is a punctuation character or it is the end of the text block, put the sequence @~ after the @endif. In other words, write @endif@~ in the input, rather than a bare @endif.

4.5 Notes and warnings

We use two Doxygen commands to produce text that is highlighted in the output in certain ways, to call attention to special issues. These commands do not take any arguments and should be placed before the paragraph of the text to be highlighted.

To call out something special about a class, function, file or other entity, such as a behavior that should be brought to the attention of users or a note about API changes, please use the @note command. This formats the next paragraph with the heading "Note:".

To make a stronger statement, for example to warn users about potentially error-provoking situations or backward-incompatible changes in the API, use the @warning command. This formats the following paragraph with the heading "Warning:". Important: due to limitations in our documentation pipeline (in particular, in the use of Javadoc), the desired formatting can currently only be achieved through the use of an additional explicit bit of HTML code. Specifically, please wrap the paragraph with an HTML <span> element that puts the paragraph contents inside the CSS class "warning". The following example fragment illustrates this:

 * @class doc_warning_typecodes_not_unique
 *
 * @warning <span class="warning">The specific integer values of 
 * the possible type codes may be reused by different Level 3
 * package plug-ins.</span>

As a convention, please put @note blocks after other text such as parameter lists and general explanations. Put @warning blocks after any @note blocks, but put @warning blocks before @see blocks, and put @see very last in documentation. Sometimes there are exceptional situations were it's better to put warnings higher in the documentation of a class or method, but in most cases, the sequence should be: @note, @warning, and @see.

4.6 Figures

Including images and other figures is a relatively simple matter. Copy the file to the directory docs/src/common-graphics/, and then refer to it in the text using the Doxygen command @image. This command takes three arguments: the output type for which the image is to be used, the name of the file, and a text string constituting the caption to be placed under the image. Here is an example:

 * @image html model-qualifiers.png "Model qualifier relationships"
 * @image latex model-qualifiers.png "Model qualifier relationships"

Since we may at some point generate latex output, always use two @image commands when you use it: once with html and once with latex.

4.7 Code and verbatim text

Putting fragments of sample code in the documentation is always helpful for readers. Doing it in a way that produces text with syntactic elements highlighted makes the text more readable. Doxygen can perform syntax coloring on code fragments written in C++, C#, C, Java, and Python, but not other languages, and (particularly unfortunate for libSBML), not for XML either. Here is the approach used in the libSBML documentation for the different cases in order to cope with this limitation.

  • For code written in C++, C#, C, Java, and Python, enclose the code in Doxygen's @code/@endcode construct. Indicate the language as an option to @code in curly braces, using standard filename extensions. For example: @code{.py} for Python, @code{.java} for Java, etc.
  • Provide different versions of the code for different languages. Conditionalize them using the standard @if construct. Here is an example:
    @if cpp
    @code{.cpp}
    ... C++ version ...
    @endcode
    @endif
    @if java
    @code{.java}
    ... Java version ...
    @endcode
    @endif
    @if python
    @code{.py}
    ... Python version ...
    @endcode
    @endif
    ... etc. ...
    
  • For XML (which is not one of types recognized by Doxygen natively), we have to use an entirely different approach: store the content in a file that is processed by a syntax coloring tool, and then use @htmlinclude to incorporate the result in the libSBML documentation. Here is a step-by-step procedure:
    1. Save the XML content in a file with a .xml extension in the directory docs/src/common-text/.
    2. Obtain the Python-based syntax highlighting application Pygments and use it to perform syntax coloring on the .xml file. Save the result to another file with the same basename but the extension .html in the directory docs/src/common-text/. Here is a general command line for using the program pygmentize provided by the Pygments distribution:
      pygmentize -f html -o outputfile.html intputfile.xml
    3. Finally, use the Doxygen command @htmlinclude to include the .html file produced by the previous step. See section 4.2.3 Using "@htmlinclude" for more information about using @htmlinclude.

5. Commonly-used commands

The following is a summary of the Doxygen commands we have found useful so far in documenting libSBML. This is only intended as a quick orientation; they are illustrated in the other sections above, and the complete details of their definitions and use can be found online at the Doxygen website.

Command Meaning
@author Names the author of the entity being described (a file, a class, etc.).
@brief Provides a one-sentence description of the entity being described (a file, a class, etc.).
@bug Formats the following paragraph with the heading "Bugs:". Useful to indicate that something is known to be a problem in some part of the code. As a convention, please put @bug blocks at the end of a documentation block, for uniformity in the API documentation.
@c Puts the following word in typewriter ("code") font. To style more than one word, use <code>the words</code>. If you need to put something that contains HTML tags in typewriter font, use the <code>the words</code> form, and use the HTML character codes &lt; and&gt; to embed the opening '<' and '>' characters inside the words.
@code{.x} ... @endcode Formats the text as code in the programming language indicated by a filename extension .x. For example, @code{.py} interprets the contents as Python code. See section 4.7 Code and verbatim text above for more information about how to use this.
@class Declares that the following documentation block refers to the named class. Useful only when the block does not immediately precede the class definition (e.g., when it's at the beginning of the file).
@copydetails Copies the "detail" portion of the documentation of the given symbol. Please see Section 4.2.1 Using "@copydetails" for more information.
@copydoc Copies the entire documentation of the given symbol—both the one-sentence brief lead-in explanation and the detailed body. Please see Section 4.2.2 Using "@copydoc" for more information.
@em Puts the following word in italic font, for emphasis. To put multiple words in italics, use <em>the words</em>.
@enum Defines an enumeration. Otherwise identical to @class.
@file Defines the name of the current file.
@htmlinclude Insert the contents of the named file. The file can contain HTML formatting instructions.
@if ... symbol @else ... @endif Makes content visible depending on whether the symbol immediately following the @if is defined. If it is defined, the text after the symbol and before either the @else (if it is present) or the @endif is used in the output. Important: As noted above in Section 4.4 Conditional text, Doxygen removes the white space surrounding the text inside the conditional and after the @endif. This is problematic in most situations, because it produces run-together text in the output. We believe this is a bug and have reported it, but as of Doxygen version 1.8.6, the behavior persists. To avoid the problem, use the following hack: unless the next character after @endif is a punctuation character or it is the end of the text block, put the sequence @~ after the @endif. In other words, write @endif@~ in the input, rather than a bare @endif.
@li Starts (or continues) a bullet list. You can insert the first @li in a comment, and the item will continue until a paragraph break or the next @li command. (Note: even though Doxygen will also recognize hyphens at the beginning of a line as starting a list item, avoid using that approach in favor of the @li command.
@p Puts the following word in typewriter ("code") font. This form is preferred when the word is a parameter to a method or function.
@param Declares a parameter to a method or function. The first word following @param will be the name of the parameter, and the rest of the text (up to a period or blank) will be used as the description.
@n Forces a newline, like HTML's <br>.
@note Formats the following paragraph with the heading "Note:". Useful to call out something special about a class, function, file or other entity, such as a behavior that should be brought to the attention of users or a note about API changes compared to previous versions of the software or SBML.
@return Declares the return value from a method or function.
@sbmlbrief Special command defined for libSBML; see Section 3.1 Guidelines for .h files for more information.
@sbmlconstant Special command defined for libSBML; see Section 4.1.1 Referring to libSBML constants for more information.
@sbmlfunction Special command defined for libSBML; see Section 4.1.2 Referring to libSBML pure functions for more information.
@see Formats a reference to another entity in the documentation. Commonly used to refer to related classes or methods. Always put @see blocks at the very end of a documentation block, both for uniformity in the API documentation and to avoid a bug in our Javadoc-based document production pipeline.
@warning Formats the following paragraph with the heading "Warning:". This is a stronger statement than @note, and is useful to call attention to backward-incompatible changes or potentially error-provoking situations. As a convention, please put @warning blocks after @note blocks in documentation, and please wrap them with an HTML span element with the CSS class "warning". (See discussion in Section 4.5 Notes and warnings.)

Many HTML commands will work in comments for Doxygen. For example, a common one is the a tag for linking text to a URL, as in <a href="http://sbml.org">home page</a>. Unfortunately, many (most?) HTML commands will not work. For those situations, you may have to resort to using @htmlinclude'ed raw HTML files.

6. LibSBML's documentation-generation process

The sequence of events in generating the finished, formatted user documentation is complex. However, it can be useful to have a general sense for how it works, to help find problems when the output produced is not what's expected. This section summarizes the sequences of events for the different types of documentation.

6.1 Generating C++ and C docs

The steps below are executed by the Makefile located in the directory docs/src/. They are invoked by the command make cpp-manual (for C++) or make c-manual (for C).

  1. The process first generates a CSS stylesheet (css/libsbml-package-stylesheet.css) to define formatting rules tailored for each class defined by each Level 3 package extension for libSBML. This is done by the Python program css/generate-pkg-stylesheet.py. This program works by walking down the libSBML package source code directory, examining every .h file looking for @class statements, and collecting the list of class names, then producing a .css file with rules for every class found. The rules define the color symbols associated with every SBML Level 3 package class in the libSBML API documentation.
  2. Next, Doxygen is executed twice. This double run of Doxygen is necessary to use the @ingroup command in the way we use it to produce pages that list all the classes associated with a given SBML Level 3 package.
    1. In the first run of Doxygen, the definition of the macro @sbmlbrief is altered so that it invokes the Doxygen command @addindex with the name of the each libSBML Python class. The results of this run are a number of JavaScript files produced by Doxygen (files like navtreeindex.js, navtree.js, etc.). These files are saved aside temporarily while the next step is performed.

    2. In the second run of Doxygen, the definition of @sbmlbrief is reverted to its normal form, in which it invokes the Doxygen command @ingroup. This produces the pages in the section titled "Level 3 Extensions" in the final documentation.

    3. The (correct) index files produced in the first run of Doxygen are used to replace the (incorrect) index files from the second run.

  3. Finally, a number of unmodified additional files are copied to the destination directory: CSS style files, JavaScript files, image files, and so on.

Without the double run of Doxygen described above, the left-hand table of contents produced by Doxygen is dysfunctional. If you encounter a broken table of contents, then it may indicate something went wrong in the two-step process described above.

6.2 Generating Python docs

The process for generating the Python API documentation is more involved than the one for C++ and C documentation described above, though some parts are the same. The process for Python begins before you run make python-manual in the docs/src/ directory: it begins with the process involving the execution of SWIG. For completeness, the sequence below encompasses this.

  1. Before the documentation can be produced—that is, before the remaining steps below can be executed—the Python language interface code for libSBML must be generated. This process is triggered by a regular make or cmake at the top level of the libSBML source code directory. Unlike the other language bindings, however, the process for Python has extra complexity because two kinds of output have to be produced: one for use with Doxygen to generate the API documentation, and one for creating plain-text comment strings embedded with the Python code, which users will see when they use Python's interactive help facilities. The steps involved can be summarized like this:
    1. The Python program rewrite_pydoc.py in the subdirectory src/bindings/python/doc-converter/ is executed. This Python program reads all the libSBML source code files, copies the class and method comments found therein, performs pattern matching and substitution in the text of those comments to produce versions that follow Python documentation conventions, and finally, produces the file that will ultimately be used by SWIG when it creates the real language interface code.

    2. The Python program src/bindings/swig/swigdoc.py is executed. Like the previous program, it also reads all the libSBML source code files, copies the class and method comments found therein, performs pattern matching and substitution in the text of those comments; however, it produces a different, temporary file that is fed to SWIG only to produce output for the next step.

    3. SWIG is executed once on the temporary file from the previous step to produce the file src/bindings/python/libsbml-doxygen.py. This will be the file used read by Doxygen to produce the formatted API documentation.

    4. SWIG is executed a second time on the output from rewrite_doc.py (explained above), to produce the actual Python binding definitions in src/bindings/python/libsbml_wrap.cpp.
  2. The remaining steps below to produce the formatted API documentation output are executed by the Makefile located in the directory docs/src/. They are invoked by the command make java-manual. (Note that the steps above are always performed during a build of libSBML, regardless of whether you generate documentation.)
  3. The make python-manual process first generates a CSS stylesheet (css/libsbml-package-stylesheet.css) to define formatting rules tailored for each class defined by each Level 3 package extension for libSBML. This is done by the Python program css/generate-pkg-stylesheet.py. This program works by walking down the libSBML package source code directory, examining every .h file looking for @class statements, and collecting the list of class names, then producing a .css file with rules for every class found. The rules define the color symbols associated with every SBML Level 3 package in the libSBML API documentation.
  4. Next, a substitution step is performed on the file produced by SWIG. This substitution step is implemented by the Python program pythondocpreprocessor.py in docs/src/. This program reads files found in docs/src/python-substitutions (each file is named after a libSBML Python class), and also reads the file libsbml-doxygen.py previously produced by SWIG in the src/bindings/python/ directory (as described above). For each file in the substitutions directory, the program takes the contents of that file and uses the comment strings found therein instead of the comment strings found for that same class in the SWIG-produced libsbml-doxygen.py file. If a subtitution file exists for a class but is empty, then this has the effect of deleting that class from the documentation produced. This admittedly complicated step has two roles: it adds documentation for classes only defined in the language bindings that we could not find another way to document directly (e.g., for classes ASTNodeList, CVTermList, etc.), and second, it omits some internal classes from the API documentation.
  5. Next, the make python-manual process in docs/src/ runs Doxygen twice. This double run of Doxygen is necessary to use the @ingroup command in the way we use it to produce pages that list all the classes associated with a given SBML Level 3 package.
    1. In the first run of Doxygen, the definition of the macro @sbmlbrief is altered so that it invokes the Doxygen command @addindex with the name of the each libSBML Python class. The results of this run are a number of JavaScript files produced by Doxygen (files like navtreeindex.js, navtree.js, etc.). These files are saved aside temporarily while the next step is performed.

    2. In the second run of Doxygen, the definition of @sbmlbrief is reverted to its normal form, in which it invokes the Doxygen command @ingroup. This produces the pages in the section titled "Level 3 Extensions" in the final documentation.

    3. The (correct) index files produced in the first run of Doxygen are used to replace the (dysfunctional) index files from the second run.

  6. Finally, a number of unmodified additional files are copied to the destination directory: CSS style files, JavaScript files, image files, and so on.

6.3 Generating Java docs

The process for the Java API documentation is different from all the others because it does not use Doxygen; instead, it uses Javadoc, the common Java documentation-generation tool. In principle we could use Doxygen for Java as well, but the output produced by Doxygen is different in appearance and structure than what Javadoc produces. We felt that using Javadoc would provide something closer to what Java developers are accustomed to seeing, and therefore would be better for Java developers.

The process for generating the Java API documentation actually begins before you run make java-manual in the docs/src/ directory: it begins with the process involving the execution of SWIG. For completeness, the sequence below encompasses this.

  1. Before the documentation can be produced—that is, before the remaining steps below can be executed—the Java bindings files for libSBML must be generated. This process is triggered by a regular make or cmake at the top level of the libSBML source code directory. It will invoke SWIG at some point, but before it invokes SWIG, it will run the custom Python program src/bindings/swig/swigdoc.py. This Python program reads all the libSBML source code files, copies the class and method comments found therein, performs pattern matching and substitution in the text of those comments to produce versions that follow Javadoc conventions, and writes the modified results to the file src/bindings/java/javadoc.i. This file will be read by SWIG when it runs. When SWIG produces the actual Java files that it writes in src/bindings/java/java-files/, it uses the comment strings in this file as the source of the documentation strings attached to the Java class and method definitions.
  2. The remaining steps below to produce the formatted API documentation output are executed by the Makefile located in the directory docs/src/. They are invoked by the command make java-manual. (Note that the steps above are always performed during a build of libSBML, regardless of whether you generate documentation.)
  3. The make java-manual process first generates a CSS stylesheet (css/libsbml-package-stylesheet.css) to define formatting rules tailored for each class defined by each Level 3 package extension for libSBML. This is done by the Python program css/generate-pkg-stylesheet.py. This program works by walking down the libSBML package source code directory, examining every .h file looking for @class statements, and collecting the list of class names, then producing a .css file with rules for every class found. The rules define the color symbols associated with every package and written in places such as the left-hand list of class names in the Javadoc output. (This complicated process is necessary because Javadoc provides no other hooks to modify the appearance of class description pages.)
  4. The Java files previously produced by SWIG for the Java API are copied from their location in src/bindings/java/java-files/ to a temporary directory in docs/src.
  5. The Java files located in docs/src/java-substitutions/ are copied into the same temporary directory as the previous step, overwriting some of the files originally created by SWIG. These substitutions are necessary for various reasons, including the inability to attach documentation to some types of objects produced by SWIG. The files in docs/src/java-substitutions/ do not contain any Java code, only comments. Two points are important to note. First, the comments are in Javadoc format, not in Doxygen format, because the next step will feed the files as-is to Javadoc. Second, if the original source code changes, the substitution files must be modified by hand to account for the changes. This is an obvious maintenance problem, but we currently have no better solution.
  6. Next, Javadoc is executed on the contents of the temporary directory mentioned in the previous step, to generate the basic HTML output files to the destination directory. Javadoc is invoked with a custom doclet that implements features not available in the default Javadoc doclet, such as skipping internal SWIG methods with a certain name, detecting the tag @internal in method comments and omitting those methods from the output, and adding some comments to some methods (at the moment, the delete() method).
  7. A number of unmodified additional files are copied to the destination directory: CSS style files, JavaScript files, image files, and so on.
  8. A number of additional HTML files are copied from docs/src/ to the destination directory, but using a procedure that prepends a header, appends a footer, and performs substitutions on variables in the files (for the title and the libSBML version number) to produce their final version in the output directory. These files are for the front page of the API documentation, installation procedures, etc.; basically, content that is not class or method documentation.
  9. The HTML page that lists the libSBML SBML Level 3 extensions is generated using a Python program, docs/src/generate-extensions-summary.py. The file is generated by rewriting an HTML page generated by Javadoc. The transformations include adding the color codes for different Level 3 packages.
  10. All of the HTML files in the output directory are modified to insert a directive to include the sbml.js JavaScript file and to rewrite some of the text in the files (e.g., to remove the word "Package", which is a Java term that has a different meaning for SBML).
  11. Finally, the Java example files are copied from examples/java/ to a subdirectory in the destination output directory, along the way being modified to wrap them in HTML code.

7. Miscellaneous Doxygen notes

The following are some notes and warnings that did not easily fit elsewhere in this section.

  • The doxygen command @internal is (according to the doxygen documentation) supposed to let you flag things as internal implementation code, such that it is not put in the finished documentation. This would be great if we could use it, but I (MH) have been unable to make this work. (Yes, there is a configuration flag, and yes, I've tried setting it both ways.)