Doxygen style guide#
pigweed.dev
uses Doxygen to auto-generate C and C++ API references
from code comments in header files. These specially formatted comments are
called Doxygen comments. This style guide shows you how to format Doxygen
comments and other related documentation.
Quickstart#
Auto-generating an API reference on pigweed.dev
requires interacting with
a few different tools. This section provides an overview of when you interact
with each tool, using pw_i2c
as an example.
Annotate your header file using Doxygen syntax. All of the comments that start with triple slashes (
///
) are Doxygen comments. Doxygen ignores double slash (//
) comments.Example: //pw_i2c/public/pw_i2c/device.h
Include the API reference content into a reStructuredText file using Breathe directives. Breathe is the bridge between Doxygen and Sphinx, the documentation generator that powers
pigweed.dev
. See Overview for more explanation.Example: //pw_i2c/reference.rst
Add your header file’s path to the
_doxygen_input_files
list in//docs/BUILD.gn
. The docs build system throws a “symbol not found” errors if you forget this step.Example: //docs/BUILD.gn
API reference writing style#
Follow the guidance in API reference code comments.
Doxygen comment style#
This section explains how you should style the comments within header files that Doxygen converts into API references.
Special command syntax#
Special commands like @code
and @param
are the core annotation
tools of Doxygen. Doxygen recognizes words that begin with either backslashes
(\
) or at symbols (@
) as special commands. For example, \code
and
@code
are synonyms. Always use the at symbol (@
) format.
Yes
/// @param[out] dest The memory area to copy to.
No
/// \param dest The memory area to copy to.
Structural commands#
Doxygen structural commands like @struct
, @fn
, @class
, and @file
associate a comment to a symbol. Don’t use structural commands if they’re not
needed. In other words, if your Doxygen comment renders correctly without the
structural command, don’t use it.
Code examples#
Use @code{.cpp}
followed by the code example followed by @endcode
.
Yes
/// @code{.cpp}
/// #include "pw_kvs/key_value_store.h"
/// #include "pw_kvs/flash_test_partition.h"
///
/// ...
/// @endcode
Omit or change {.cpp}
if your code example isn’t C++ code.
Yes
/// @code
/// START + I2C_ADDRESS + WRITE(0) + TX_BUFFER_BYTES + STOP
/// START + I2C_ADDRESS + READ(1) + RX_BUFFER_BYTES + STOP
/// @endcode
Parameters#
Use @param[<direction>] <name> <description>
for each parameter.
Yes
/// @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.
Put a newline between the parameters if you need multi-line descriptions.
Yes
/// @param[out] dest Lorem ipsum dolor sit amet, consectetur adipiscing
/// elit, sed do eiusmod tempor incididunt ut labore et dolore magna...
///
/// @param[in] src The memory area to copy from.
///
/// @param[in] n The number of bytes to copy.
The direction annotation is required.
No
/// @param dest The memory area to copy to.
/// @param src The memory area to copy from.
/// @param n The number of bytes to copy.
<direction>
must be specified and the value must be either in
or
out
.
Preconditions#
Use @pre <description>
.
Yes
/// @pre Description of a precondition that must be satisifed before
/// invoking this function.
Deprecated features#
Use @deprecated <description>
.
Yes
/// @deprecated This function, class, or other entity is deprecated. Use
/// the replacement instead.
pw_status codes#
Use the following syntax when referring to pw_status
codes:
Yes
@pw_status{...}
Replace ...
with a valid pw_status
code. See
Quick reference.
Doxygen converts this alias into a link to the status code’s reference documentation.
Don’t use this syntax for functions or methods that return a set of
status codes. Use pw-status-codes
. See Functions and methods that return pw::Status codes.
Functions and methods that return pw::Status codes#
Use pw-status-codes
to present the set of codes and descriptions as a
two-column table:
Yes
/// @returns @rst
///
/// .. pw-status-codes::
///
/// <code>: <description>
///
/// <code>: <description>
///
/// @endrst
Example:
Yes
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: The bulk read was successful.
///
/// RESOURCE_EXHAUSTED: The remaining space is too small to hold a
/// new block.
///
/// @endrst
Each
<code>
must be a valid status code. The part before the colon must be plaintext.Each
<description>
should explain further what the code means in this particular scenario. The description must be a single paragraph. It can use inline reStructuredText features such as code formatting and cross-references.pw-status-codes
needs to be wrapped in@rst
and@endrst
because it’s a reStructuredText directive and Doxygen doesn’t natively support reST. The implementation is at//pw_docgen/py/pw_docgen/sphinx/pw_status_codes.py
.
Yes
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Data successfully written to ``buffer``.
///
/// RESOURCE_EXHAUSTED: The remaining space is too small to hold a
/// new block. See :ref:`module-pw_example-troubleshooting`.
///
/// @endrst
It’s OK to use reStructuredText features like code formatting and cross-references within the descriptions. The status code itself must be plaintext.
No
/// @returns @rst
///
/// .. pw-status-codes::
///
/// RESOURCE_EXHAUSTED: The remaining space is too small to hold a
/// new block.
///
/// @endrst
For items that span multiple lines, don’t use whitespace like this.
Use fully namespaced names#
In general, write out the full namespace to Pigweed classes, methods, and
so on. If you’re writing a code sample, and that code sample clearly shows
where the item comes from via a using
statement, you don’t need to use
full namespacing.
Discussion
Pigweed has over 160 modules. It can be overwhelming for beginners to figure out where an item is coming from.
Single comment block for multiple symbols#
Use @def <symbol>
followed by the comment block.
Yes
/// @def PW_ASSERT_EXCLUSIVE_LOCK
/// @def PW_ASSERT_SHARED_LOCK
///
/// Documents functions that dynamically check to see if a lock is held, and
/// fail if it is not held.
Cross-references (x-refs)#
X-refs in Doxygen comments#
For C or C++ x-refs, use one of the following aliases:
Alias |
reStructuredText equivalent |
---|---|
|
|
|
|
|
|
|
|
For all other x-refs, use Pigweed’s custom basic alias,
@crossref{<domain>,<type>,<identifier>}
. <domain>
must be a valid
Sphinx Domain and <type>
must be a valid type within that domain.
@crossref
can be used with any domain.
Avoid Doxygen x-refs#
Always use Pigweed’s custom aliases for x-refs unless you have specific reasons not to do so. Pigweed’s x-ref aliases are built on top of Sphinx. Doxygen provides its own features for x-refs but they should be avoided because Sphinx’s are better:
Sphinx x-refs work for all identifiers known to Sphinx, including those documented with directives like
.. cpp:class::
or extracted from Python. Doxygen references can only refer to identifiers known to Doxygen.Sphinx x-refs always use consistent formatting. Doxygen x-refs sometimes render as plaintext instead of code-style monospace, or include
()
in macros that shouldn’t have them.Sphinx x-refs can refer to symbols that haven’t yet been documented. They will be formatted correctly and become links once the symbols are documented.
Using Sphinx x-refs in Doxygen comments makes x-ref syntax more consistent within Doxygen comments and between reStructuredText and Doxygen.
Cross-references in reST to Doxygen symbols#
After you’ve used Doxygen to generate API references, you can link to those symbols from your reStructuredText with standard Sphinx x-ref syntax.
Yes
:cpp:class:`pw::sync::BinarySemaphore::BinarySemaphore`
In the Sphinx docs the reference documentation for x-ref syntax is provided in the domain docs:
Embedded reStructuredText#
To use reStructuredText (reST) within a Doxygen comment, wrap the reST
in @rst
and @endrst
.
Breathe#
This section provides guidance on how Breathe should and shouldn’t be used
when authoring pigweed.dev
docs.
Overview#
After you annotate your header comments as Doxygen comments, you need to
specify where to render the API reference within the pigweed.dev
docs.
The reStructuredText files distributed across the main Pigweed repo are
the source code for pigweed.dev
. Updating these .rst
files is how
you surface the API reference on pigweed.dev
. Doxygen doesn’t natively
interact with Sphinx, the documentation generator that powers
pigweed.dev
. Breathe is the bridge and API that enables pigweed.dev
and Doxygen to work together.
doxygenclass#
OK to use. doxygenclass documents a class and its members.
Yes
.. doxygenclass:: pw::sync::BinarySemaphore
:members:
Classes that are a major part of a Pigweed module’s API should have their
own section so that they’re easy to find in the right-side page nav on
pigweed.dev
.
Yes
.. _module-pw_<name>-reference:
=========
Reference
=========
.. pigweed-module-subpage::
:name: pw_<name>
...
.. _module-pw_<name>-reference-<class>:
-------------------
pw::<name>::<class>
-------------------
.. doxygenclass:: pw::<name>::<class>
:members:
doxygenfunction#
OK to use. doxygenfunction documents a single function or method.
Yes
.. doxygenfunction:: pw::tokenizer::EncodeArgs
doxygendefine#
OK to use. doxygendefine documents a preprocessor macro.
Yes
.. doxygendefine:: PW_TOKENIZE_STRING
doxygengroup#
doxygengroup lets you manually mark a set of symbols as belonging to the same conceptual group.
doxygengroup
is OK to use when a simple
doxygenclass-based organization
doesn’t work well for your module.
To create a group, annotate your Doxygen comments with @defgroup,
@addtogroup, and @ingroup. You can wrap a set of contiguous comments
in @{
and @}
to indicate that they all belong to a group.
Yes
/// @defgroup <name> <description>
/// @{
/// ...
/// @}
Don’t include namespaces in doxygengroup
because Breathe doesn’t handle
them correctly. See issue #772.
Yes
.. cpp:namespace:: my_namespace
.. doxygengroup:: my_group
:content-only:
:members:
doxygentypedef#
OK to use. doxygentypedef documents a typedef
or using
statement.
Yes
.. doxygentypedef:: pw::Function
doxygenfile#
Don’t use doxygenfile. Use doxygengroup instead.
Disabled auto-generated #include
statements#
Note
This is an FYI section. There’s no prescriptive rule here.
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
forpw::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 butpigweed.dev
frequently usesdoxygenclass
,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.
Comment syntax#
Use the triple slash (
///
) syntax.Yes