| # 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 |
| ``` |