libSBML C++ API
5.20.4
|
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.
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.
@
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. *
) 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. /* ...
, 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. .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. /** * 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.
/** * 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.
%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. .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. @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. * ...
@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. @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. Below are explanations of how to write documentation for the most common types of files encountered in libSBML.
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.
.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 *----------------------------------------------------------------------- -->*/
@author
entries, one per line. .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 ...
@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.) @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 = "");
.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);
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.
The descriptions above cover the basics of using Doxygen and Javadoc for libSBML documentation. What follows is a discussion of other, more involved topics.
This section discusses the special needs of libSBML functions defined outside of any classes, and symbolic constants (both enumerations and #define
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.
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.
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.
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.
@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. @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. @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 3) packages used in addition to SBML Level 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 */
@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:
.h file), when the text is specific to that file and never used outside of it; orsrc/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
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.
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.
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
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
.
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
.
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
.
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.
@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.@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. ...
@htmlinclude
to incorporate the result in the libSBML documentation. Here is a step-by-step procedure:.xml
extension in the directory docs/src/common-text/
..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: @htmlinclude
to include the .html
file produced by the previous step. See section 4.2.3 Using "@htmlinclude" for more information about using @htmlinclude
.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 < and> 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.
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.
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).
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.@ingroup
command in the way we use it to produce pages that list all the classes associated with a given SBML Level 3 package. 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.
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.
The (correct) index files produced in the first run of Doxygen are used to replace the (incorrect) index files from the second run.
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.
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.
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: 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.
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.
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.
rewrite_doc.py
(explained above), to produce the actual Python binding definitions in src/bindings/python/libsbml_wrap.cpp
. 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.)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.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.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. 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.
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.
The (correct) index files produced in the first run of Doxygen are used to replace the (dysfunctional) index files from the second run.
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.
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.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.)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.)src/bindings/java/java-files/
to a temporary directory in docs/src
.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.@internal
in method comments and omitting those methods from the output, and adding some comments to some methods (at the moment, the delete()
method).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.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.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).examples/java/
to a subdirectory in the destination output directory, along the way being modified to wrap them in HTML code.The following are some notes and warnings that did not easily fit elsewhere in this section.
@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.)