Doxygen documentation style#

Doxygen comments in C, C++, and Java are surfaced in Sphinx using Breathe.


Sources with doxygen comment blocks must be added to the _doxygen_input_files list in //docs/ to be processed.


We are moving to the Google Developer Documentation Style Guide (GDDSG) for the English language conventions (rather than technical style for Doxygen and RST usage). Currently, most of our documentation does not adhere to the GDDSG.

See the GDDSG section on API reference code comments for English style that applies to Pigweed’s Doxygen content.

Breathe provides various directives for bringing Doxygen comments into Sphinx. These include the following:

  • doxygengroup – Documents features within a Doxygen group. Doxygen groups are created with @defgroup or @addtogroup and @{ / @}. Inidividual items can be grouped with @ingroup.

    namespace the_namespace {
    /// @defgroup your_group_name Optional group title
    /// @{
    // ... everything is added to the group
    // @}
    }  // namespace the_namespace

    Do not include namespaces in groups since Breathe does not handle them properly (see GitHub issue 772). The namespace must be specified in Sphinx instead.

    .. cpp:namespace:: the_namespace
    .. doxygengroup:: your_group_name
  • doxygenfile – Documents a source file. May limit to specific types of symbols with :sections:.

    .. doxygenfile:: pw_rpc/internal/config.h
       :sections: define, func


    Breathe currently treats C++ namespaces like typedefs, resulting in duplicate definition errors (see GitHub issue 772). Because of this, :sections: must be specified for files that define commonly used namespaces (such as pw). Consider grouping symbols with a doxygengroup instead.

  • doxygenclass – Documents a class and optionally its members.

    .. doxygenclass:: pw::sync::BinarySemaphore
  • doxygentypedef – Documents an alias (typedef or using statement).

    .. doxygentypedef:: pw::Function
  • doxygenfunction – Documents a source file. Can be filtered to limit to specific types of symbols.

    .. doxygenfunction:: pw::tokenizer::EncodeArgs
  • doxygendefine – Documents a preprocessor macro.

    .. doxygendefine:: PW_TOKENIZE_STRING


Prefer doxygengroup or doxygenfile over listing symbols individually, which is error prone and harder to maintain.

Example Doxygen comment block#

Start a Doxygen comment block using /// (three forward slashes).

/// This is the documentation comment for the `PW_LOCK_RETURNED()` macro. It
/// describes how to use the macro.
/// Doxygen comments can refer to other symbols using Sphinx cross
/// references. For example, @cpp_class{pw::InlineBasicString}, which is
/// shorthand for @crossref{cpp,class,pw::InlineBasicString}, links to a C++
/// class. @crossref{py,func,pw_tokenizer.proto.detokenize_fields} links to a
/// Python function.
/// @param[out] dest The memory area to copy to.
/// @param[in]  src  The memory area to copy from.
/// @param[in]  n    The number of bytes to copy
/// @retval OK KVS successfully initialized.
/// @retval DATA_LOSS KVS initialized and is usable, but contains corrupt data.
/// @retval UNKNOWN Unknown error. KVS is not initialized.
/// @rst
/// The ``@rst`` and ``@endrst`` commands form a block block of
/// reStructuredText that is rendered in Sphinx.
/// .. warning::
///    this is a warning admonition
/// .. code-block:: cpp
///    void release(ptrdiff_t update = 1);
/// @endrst
/// Example code block using Doxygen markup below. To override the language
/// use `@code{.cpp}`
/// @code
///   class Foo {
///    public:
///     Mutex* mu() PW_LOCK_RETURNED(mu) { return μ }
///    private:
///     Mutex mu;
///   };
/// @endcode
/// @b The first word in this sentence is bold (The).
#define PW_LOCK_RETURNED(x) __attribute__((lock_returned(x)))

Doxygen syntax#

Pigweed prefers to use RST wherever possible, but there are a few Doxygen syntatic elements that may be needed.

Common Doxygen commands for use within a comment block:

  • @rst To start a reStructuredText block. This is a custom alias for \verbatim embed:rst:leading-asterisk. This must be paired with @endrst.

  • @code Start a code block. This must be paired with @endcode.

  • @param Document parameters, this may be repeated.

  • @pre Starts a paragraph where the precondition of an entity can be described.

  • @post Starts a paragraph where the postcondition of an entity can be described.

  • @return Single paragraph to describe return value(s).

  • @retval Document return values by name. This is rendered as a definition list.

  • @note Add a note admonition to the end of documentation.

  • @b To bold one word.

Doxygen provides structural commands that associate a comment block with a particular symbol. Example of these include @class, @struct, @def, @fn, and @file. Do not use these unless necessary, since they are redundant with the declarations themselves.

One case where structural commands are necessary is when a single comment block describes multiple symbols. To group multiple symbols into a single comment block, include a structural commands for each symbol on its own line. For example, the following comment documents two macros:

/// Documents functions that dynamically check to see if a lock is held, and
/// fail if it is not held.


Pigweed provides Doxygen aliases for creating Sphinx cross references within Doxygen comments. These should be used when referring to other symbols, such as functions, classes, or macros.

The basic alias is @crossref, which supports any Sphinx domain. For readability, aliases for commonnly used types are provided.

  • @crossref{domain,type,identifier} Inserts a cross reference of any type in any Sphinx domain. For example, @crossref{c,func,foo} is equivalent to :c:func:`foo` and links to the documentation for the C function foo, if it exists.

  • @c_macro{identifier} Equivalent to :c:macro:`identifier`.

  • @cpp_func{identifier} Equivalent to :cpp:func:`identifier`.

  • @cpp_class{identifier} Equivalent to :cpp:class:`identifier`.

  • @cpp_type{identifier} Equivalent to :cpp:type:`identifier`.


Use the @ aliases described above for all cross references. Doxygen provides other methods for cross references, but Sphinx cross references offer several advantages:

  • Sphinx cross references work for all identifiers known to Sphinx, including those documented with e.g. .. cpp:class:: or extracted from Python. Doxygen references can only refer to identifiers known to Doxygen.

  • Sphinx cross references always use consistent formatting. Doxygen cross references sometimes render as plain text instead of code-style monospace, or include () in macros that shouldn’t have them.

  • Sphinx cross references can refer to symbols that have not yet been documented. They will be formatted correctly and become links once the symbols are documented.

  • Using Sphinx cross references in Doxygen comments makes cross reference syntax more consistent within Doxygen comments and between RST and Doxygen.

Create cross reference links elsewhere in the document to symbols documented with Doxygen using standard Sphinx cross references, such as :cpp:class: and :cpp:func:.

- :cpp:class:`pw::sync::BinarySemaphore::BinarySemaphore`
- :cpp:func:`pw::sync::BinarySemaphore::try_acquire`

Status codes in Doxygen comments#

Use the following syntax when referring to pw_status codes in Doxygen comments:


Replace YOUR_STATUS_CODE_HERE with a valid pw_status code.

This syntax ensures that Doxygen links back to the status code’s reference documentation in pw_status.


The guidance in this section only applies to Doxygen comments in C++ header files.

Disabled auto-generated #include statements#

Doxygen and Breathe have the ability to auto-generate #include statements for class references. These have been disabled because:

  • The auto-generated paths are inaccurate. E.g. the #include for pw::string::RandomGenerator was generated as #include <random.h> when it should be #include "pw_random/random.h".

  • The auto-generation is not consistent. They seem to only get generated when using the doxygennamespace directive but frequently uses doxygenclass, doxygenfunction, etc.

In the future, if it’s decided that these #include statements are needed, there is a way to manually override each one. The code block below shows how it’s done. This approach wouldn’t be great because it adds a lot of noise to the header files.

/// @class RandomGenerator random.h "pw_random/random.h"``

See b/295023422.