tree: 78992f4e9b9d5d028dcca6c808790e609465d6a9 [path history] [tgz]
  1. clangdoc/
  2. cmd/
  3. docgen/
  4. e2e_test/
  5. BUILD.gn
  6. clang_doc.gni
  7. clang_doc_generate_source.py
  8. clang_doc_invoke.py
  9. cpp_docgen.gni
  10. OWNERS
  11. README.md
tools/cppdocgen/README.md

C++ document generator

This is an experimental tool to generate markdown documentation from C++. It consumes .yaml output from clang-doc and formats markdown for serving on fuchsia.dev.

It is not yet hooked up to the build by default. It is invoked using the cpp_docgen() GN template in cpp_docgen.gni. A full example is in the e2e_test directory.

Comment formatting

This tool (via clang-doc) reads the comments above functions, classes, structs, defines, enums, etc. and uses these as the documentation for those entities. These comments are called “docstrings.”

The docstrings can be formatted with either // or ///. They must immediately precede the definition with no blank lines to be counted as documentation for that definition.

The contents of the comments is treated as markdown and, to a first approximation, simply copied to the output. The markdown will be converted to HTML by Google devsite, so all devsite markdown features are available, including inline HTML.

// This is the docstring for the function.
//
// More documentation. Some **bold** and *italic* markdown. You can also have
// things like [normal markdown links](https://www.google.com).
void MyFunction();

The following sections describe the limited processing that the docgen tool does.

Headings

Markdown headings (lines that start with #) are adjusted to appear at the correct level of hierarchy within the document.

// Automatically synchronizes the cardinal grammeter
//
// # Errors
//
// This section is formatted by devsite as a definition list.
//
// ZX_ERROR_NO_RESOURCES
// : This error indicates the turbo encabulator was full.
//
// ZX_ERR_CANCELED
// : One of the six hydrocoptic marzel vanes requested a cancelation.
zx_status_t SynchronizeCardinalGrammeter();

In this example, the # Errors line will be converted to ### Errors to fall correctly under the automatically generated level 2 heading for the function name. So most headings in docstrings should be level 1 markdown headings.

The exception is if the first line of a docstring starts with a level 1 heading. This heading will be promoted to be the title for the entity rather in place of the generated title (see “Setting the title” below).

Links

Normal markdown links are supported and interpreted by devsite:

  • [Google](https://www.google.com/)
  • [FIDL wire format](/docs/reference/fidl/language/wire-format)

The docgen tool can automatically create links to named entities in the same library by enclosing the name in square brackets and providing no link destination (the part in parenthesis) after the square brackets:

  • See [SynchronizeCardinalGrammeter()] to synchronize.

The doc generateor will look for a symbol (which could be a function, class, define, etc.) called SynchronizeCardinalGrammeter in one of the headers being documented. If found, it will be linked to the correct destination and formatted as code.

  • Anything after an opening parenthesis will be ignored when doing name lookup so you can include them for function calls and even include parameters if you feel it helps readability.
  • The contents of the [...] can not span lines.
  • If the named item can not be found, the text will be passed to the output unchanged.

Comments

If you want to include text in the header that you do not want to appear in the output served by devsite, there are several options.

The first option is to make the comment not be part of the docstring for the item being documented. Normally this means separate the two with a blank line:

// Note: this comment is formatted for docgen so that yadda yadda yadda. This
// specific comment will not appear in the generated docs.

// Docstring for the thing.
double InverseReactiveCurrent();

Since devsite supports HTML tags, you can also include HTML comment tags if you want the comment to appear inline in the docstring. The disadvantage of this approach is that the text will be served on web page to end-user's browser, just not rendered:

// Returns the goniometric data associated with the emcabulator.
//
// <!-- Note: be sure to keep this section in order! -->
//
// ...more stuff here...
std::vector<int> GetGoniometricData();

Organizing the documentation

Omitting documentation

Sometimes you don't want a function or structure emitted in the documentation. In these case, you can add the annotation “$nodoc” anywhere in the docstring for the thing you would like to be skipped:

// Private internal function.
// $nodoc
void EnableQuasistaticRegeneration();

Aside: why not use \nodoc or @nodoc instead of $nodoc, both of which are more often used in similar tools? Clang tries to interpret backslash- and @-annotated words but since it doesn‘t know this command it doesn’t do anything but still strips the word from the output. Therefore, we need a different annotation style.

Providing your own declaration

The docgen tool and clang-doc (the underlying tool) don't support all C/C++ constructs so some generated declarations may be incorrect. In other cases, you may want to format the declaration in some specific way to make it more clear.

In these cases you can add the annotation “$nodecl” anywhere in the docstring for the corresponding entity to skip automatic generation of the declaration.

In such cases, you should provide your own version of the declaration. The autogenerated declarations appear above the rest of the docstring; following this format in your custom declarations will keep the documentation easier to follow.

// $nodecl
// ```
// struct DiffusionIntegrator {
//   union {
//     int a;
//     struct {
//       double b;
//       char c;
//     };
//   } u;
// };
// ```
//
// The DiffusionIntegrator collects the interelectrode diffusion in such a
// way that the ...
struct DiffusionIntegrator {
  ...
};

Index overview

You can supply content that goes at the top of the generated “index.md” file. It is recommended this just be the README.md file at the toplevel of your library. This should give an introduction to the library and it will be followed by the generated header file and function indices. The title of this file will also define the title of the generated index.md file.

To specify the overview file, use the overview variable in the cppdocgen GN template. This file path is relative to the BUILD.gn directory.

cpp_docgen("my_docs") {
  headers = [ ... ]
  overview = "README.md"
  ...
}

Per-header documentation

You can supply markdown text to be included at the top of the reference for a header file. To count as the documentation for the header (rather than a copyright block or the documentation for something else), the comment must satisfy all of these requirements:

  • It must be deliniated with “///” comments at the beginning of the line.
  • It must be followed with a blank line.
  • It must appear before any non-preprocessor lines (only “#” and “//” lines are allowed before it).

It is recommended that this block go immediately before or after the include guard.

Setting the title

A title will be generated for each reference page based on the header and library name. This may not always be appropriate.

If the header file comment starts with a markdown heading 1 (“#”), that line will be used as the title of the page instead. For example:

// Copyright 2022 blah blah

#ifndef MY_LIBRARY_MY_HEADER_H_
#define MY_LIBRARY_MY_HEADER_H_

/// # Deprecated functions in libdoom
///
/// The header `<lib/libdoom/deprecated.h>` contains all of the functions
/// that are currently deprecated but allowed to be used.

For user-friendliness:

  • Include the path and name of the header file as the user will type it in their code (likely relative to the library include directory, not the fuchsia repository root). If this is not included in the title, put it near the top of the header documentation text.

  • Include the name of the library.

Grouping functions and defines into one heading

Sometimes you will want some functions or defines to appear under the same heading. This can make similar functions much easier to follow.

Two functions are implicitly grouped when they have the same name and no blank or comment lines separating their declarations. Any comment above the first function becomes the comment for all of them.

// Returns an iterator to the beginning of the container.
iterator begin();
const_iterator begin() const;

These same rules apply to constructors (which always have matching names). The difference is that constructors will always go under the same “construcors” heading, but there will be different sections within that if there are constructor variants with separate comments.

class MyClass {
  // These two will ge grouped together and this will be the docstring for them.
  MyClass();
  MyClass(int a);
  // This one will go in its own section with its own documentation.
  MyClass(std::string a);

Functions (even with non-matching names) and #defines can also be grouped explicitly. To do this, list the items with no blank or comment lines separating them, provide a comment above the first item, and start that comment with a markdown heading 1 (“# ...”). The heading will become the title for all items in the group:

/// # ZX_RIGHT_... defines
///
/// These constants define the rights for objects.
#define ZX_RIGHT_NONE 0
#define ZX_RIGHT_DISINTEGRATE 1
#define ZX_RIGHT_STAPLE 2

/// # begin()/cbegin()
///
/// These functions return a (possibly const) iterator to the beginning of the
/// container.
iterator begin();
const_iterator cbegin();

It is good practice to include as much of the name as practical in the title. This is what the user will be scanning for and it should match with the other titles which use the raw function/define names. It's best to end the title with “macros” or “defines” to match the generated titles of other sections.

In cases where there is a group of related defines that need individual documentation, the recommended formatting is to create a group (so they will all be under one heading with one section showing all the declarations in-order) and then include per-flag documentation in headings under that. The cppdocgen tool will indent the headings automatically to be within the group.

// Encabulator flag macros
//
// These macros define bits that can be used in the `flags` parameter of the
// [enable_encabulator()] function.
//
// # ENCABULATOR_ENABLE_TURBO
//
// Enables the turbo mode of the encabulator. Etc...
//
//
// # ENCABULATOR_ENABLE_MARZELVANES
//
// Documentation for this flag...
#define ENCABULATOR_ENABLE_TURBO 1
#define ENCABULATOR_ENABLE_MARZELVANES 2