DOXYSPHINX(1)

πŸ“¦
version 3.3.12 Β· 2 versions
, in ubuntu stonking

πŸ’– doxysphinx πŸ’–

okay bestie, welcome to the doxysphinx manual page β€” this is the docs for Doxysphinx 3.3.12 and it's gonna be a whole journey 🌈


✨ NAME ✨

doxysphinx β€” Doxysphinx 3.3.12 πŸ’…


πŸ¦‹ GETTING STARTED πŸ¦‹

So in this guide we're gonna walk you through setting up doxysphinx for your doxygen and sphinx project. step by step, no stress, we got you 🫢

Note: this guide is written assuming you want to integrate doxysphinx into your own project. If you just wanna test-drive it and see how things work, we recommend you clone the repo, fire up vscode, and enter the devcontainer. easiest slay ever ✨

🌸 Step 0: Prerequisites 🌸

Please be sure to fulfill the following prerequisites, bestie β€” no skipping πŸ™ˆ

Tip: you can also look at the source code of this project for reference β€” especially the [devcontainer](<span>{{ code }}</span>/.devcontainer) has everything set up already. iconic of it honestly.

πŸŽ€ Project requirements πŸŽ€

You need a project upfront that already has:

  • doxygen installed and configured.
  • sphinx installed and configured.

🧚 Needed tooling 🧚

You should already have python, doxygen and sphinx installed. If yes β€” great! If not, please install them:


πŸ’… Step 1: Installing Doxysphinx πŸ’…

Doxysphinx is distributed as a pypi package β€” https://todo_add_link_here.

Install it with:

pip install doxysphinx
Note: if you have trouble installing/running the package, please look into our FAQ (section I.1) β€” #faq-i-1 β€” where we describe some alternatives. we gotchu πŸ’œ

⭐ Step 2: Prepare Doxygen Config ⭐

Next up you have to prepare your doxygen configuration file (doxyfile) so it has settings that are compatible with doxysphinx. this part matters, fr fr.

The following settings are mandatory and will be checked by a validator if you use your doxyfile as input for doxysphinx (if you use the doxygen html output directory instead, validation will be skipped πŸ‘€).


πŸ‘‘ Mandatory settings πŸ‘‘

these settings are absolutely needed (Doxysphinx will throw detailed errors in case of incorrect ones):

OUTPUT_DIRECTORY       = <anywhere_below_you_sphinx_documentation_source_root!!!> # see note below

GENERATE_TREEVIEW      = NO   # Deactivate doxygens own treeview (as it doesn't look right)
DISABLE_INDEX          = NO   # Menu data is crucial for our TOC generation so it mustn't be disabled

GENERATE_HTML          = YES  # Keep sure that you generate HTML which needed for doxysphinx

CREATE_SUBDIRS         = NO   # NO is the default value and it should be no because doxysphinx can't handle subdirs right now.
Note: why the heck does the doxygen output_dir need to live inside the sphinx docs root?? Right now, for each doxygen html output file, an rst file is generated with the same name/path but a different extension. We did this because sphinx will then automatically generate the html files for the rsts at the correct relative location β€” and no doxygen-documentation-internal links will break, they just stay the same. However, this has the implication that the doxygen html output has to live inside/somewhere below the sphinx source directory (we recommend using something like docs/doxygen/YOUR_LIBRARY_NAME/). If that isn't the case for you, doxysphinx will complain and exit. πŸ’€ "But I don't want my docs dir to get polluted with generated code!" Yes, we don't like that either, but one of our design goals was performance, and scanning htmls and correcting links is just one additional step that takes time and makes things more complicated. Our recommendation is to just gitignore the generated doxygen docs dir. If you cannot live with it, you could take a look at the alternatives <>.

these settings are optional but strongly recommended (you will be notified in case of some value deviations):

SEARCHENGINE           = NO   # deactivate search engine (as sphinx has it's own search)
GENERATE_TAGFILE       = <OUTPUT_DIRECTORY>/<HTML_OUTPUT>/tagfile.xml  # generate a tag file
                              # this could be stored anywhere, however we recommend to put it into the
                              # documentation output folder which is the value of the OUTPUT_DIRECTORY variable
                              # + the value of the HTML_OUTPUT variable (your have to expand it for yourself
                              # because doxygen has no mechanism to reference config settings that were defined
                              # beforehand.
                              # The tagfile is also needed for the doxylink extension

DOT_IMAGE_FORMAT       = svg  # generates nicer svg images
DOT_TRANSPARENT        = YES  # generate transparent images
INTERACTIVE_SVG        = YES  # to be able to scroll and zoom into big images

# if you want to use aliases instead of markdown fences for commenting (see syntax guide) you have to add
# something like this (which doesn't hurt either):
ALIASES                = "rst=\verbatim embed:rst:leading-asterisk" \
                         endrst=\endverbatim  # This allows you to use rst blocks inside doxygen comments with @rst and @endrst
Tip: Doxygen awesome β€” https://jothepro.github.io/doxygen-awesome-css β€” is a stylesheet that makes doxygen documentation look beautiful. We strongly recommend using it because then the doxygen docs would fit far better with any sphinx theme. Just download/clone the doxygen awesome stylesheet and then add it to your doxygen config:
HTML_EXTRA_STYLESHEET = YOUR_DOXYGEN_AWESOME_PATH/doxygen-awesome.css

πŸ“ Step 3: Run Doxysphinx πŸ“

Now it's time to actually run doxysphinx, bestie. the moment we've all been waiting for ✨

You can either do it manually or integrate it in your makefile, cmake, whatever...


πŸ’œ Manually πŸ’œ

Note: keep sure that you first run doxygen. like, actually run it first, okay? πŸ™ˆ

The doxysphinx cli/executable has the following commands/options.


πŸ”₯ Get help πŸ”₯

Show command and usage information. This will also show the most up to date documentation, as this guide will only handle the basics:

doxysphinx --help
doxysphinx <command> --help

🌟 Build 🌟

Build the sphinx rst documents out of the doxygen htmls.

doxysphinx build <SPHINX_SOURCE> <SPHINX_OUTPUT> <INPUT(S)> <--doxygen_exe> <--doxygen_cwd>

Arguments:

  • SPHINX_SOURCE β€” the root of your sphinx source/input directory tree. Often this is the same directory your conf.py is in.
  • SPHINX_OUTPUT β€” the root of you sphinx output directory tree β€” where sphinx puts the generated html files to. This should be the directory where sphinx put's it's main index.html to.
  • INPUT(S) β€” one or many inputs, where each input could be either...
    • a doxygen configuration file (doxyfile). This is recommended for "beginners" because it will also check the config for doxysphinx compatibility.
    • an output path where the generated doxygen documentation resides. This is more like an "expert"-mode which is especially useful when integrating doxysphinx with buildsystems like cmake etc. which are dynamically generating doxygen configs.
  • --doxygen_exe β€” the name/path of the doxygen executable. If nothing is entered, the default value is "doxygen". (OPTIONAL)
  • --doxygen_cwd β€” the directory where doxygen is executed. The default value is the current working directory. (OPTIONAL)

Replace the following arguments:

Warning: please note that sphinx has slightly different output directories depending on the arguments: - the html output will be put to OUTPUT_DIR, so doxysphinx's SPHINX_OUTPUT should be OUTPUT_DIR. - the html output will be put to OUTPUT_DIR/html, so doxysphinx's SPHINX_OUTPUT should be OUTPUT_DIR/html.

🧼 Clean 🧼

If you want to remove the files doxysphinx generated, please use the clean command:

doxysphinx clean <SPHINX_SOURCE> <SPHINX_OUTPUT> <INPUT(S)>

πŸ› οΈ Makefile integration πŸ› οΈ

Add/extend the following targets in your makefile:

clean:
  @doxysphinx clean <SPHINX_SOURCE> <SPHINX_OUTPUT> <INPUT(S)>

doxysphinx:
  @doxysphinx build <SPHINX_SOURCE> <SPHINX_OUTPUT> <INPUT(S)>

Now you just need to call the doxysphinx target right after your doxygen is running. That's it. That's the whole vibe. 🫢


🌸 Step 4: Use rst snippets in your C/C++ Sourcecode 🌸

Finally bestie, the fun part β€” we get to actually write rst inside doxygen comments. πŸ’…

Open some C/C++ file and drop a comment like this on one of your functions/methods/whatever:

/// @brief Creates a new instance of the Car.
///
/// @param engine - the engine to use for this Car.
/// @param color - the color of this Car.
///
/// @rst
/// .. hint::
///    Rst text can also be included after the params.
///
/// @endrst
Car(Engine& engine, Color& color) {};

See those @rst and @endrst tags? πŸ‘€ Those are the moment. Anything you write inside them can be literally any rst code you want. Go wild.

Also pls go peek at the Syntax Guide for the full rundown on how to comment for doxysphinx. It's giving reference material, it's giving necessary. ✨

Now run doxygen, then doxysphinx, then sphinx β€” and look at the generated documentation. You should see something like this: a screenshot of the final generated html πŸ’– (imagine the demo image here, it's stunning, no cap).


πŸŽ‰ Done πŸŽ‰

πŸŽ‰ Congratulations bestie, you've completed the quickstart. You ate that fr fr. πŸ‘‘


🌈 Further Recommendation 🌈

  • If you wanna link from sphinx documentation directly to doxygen documented symbols -> go see our setting up doxylink guide. (Strongly recommended, like actually, don't skip this one. 🫢)
  • Wanna get to know the doxysphinx comment syntax? -> see our syntax guide. πŸ¦‹
  • Maybe you're curious about the inner workings? -> head over to the reference section. πŸ”
  • Or just wanna look at some examples? -> linking to doxygen. 🌸
  • Or do you want to contribute and bring doxysphinx to the next level?? -> Read the contributors guide and the Developer Quickstart. Main character energy, we love to see it. πŸ‘‘
  • Or just start documenting πŸ˜€.

✨ SYNTAX GUIDE ✨

Here's where you find out exactly how to write your comments in doxygen so doxysphinx actually picks them up. No guessing, no hoping, just facts. πŸ’…


πŸŽ€ Rst Block Syntax πŸŽ€

For creating blocks of restructured text content in C++ documentation comments that will be rendered by Sphinx. Iconic behaviour honestly.


  • If you want the shortest possible syntax: use Markdown Fences with directive autodetection. Short, sweet, slays. ✨
  • If you're coming from breathe and already have your code commented with breathe markers, or if you want maximum compatibility: use Doxygen aliases. 🫢
However β€” if you experience any problems with doxygen parsing etc., you might wanna try one of the other options described in Supported rst block delimiters in doxygen comments. There's options, bestie. You're covered. πŸ’–

πŸ” Markers πŸ”

For doxysphinx to be able to identify a rst block, we only need two things: some kind of "verbatim block" in the html output, and a special marker at the beginning of the content.

The marker can be one of these:

  • {rst} -> our own (doxysphinx) marker πŸ’…
  • embed:rst
  • embed:rst:leading-asterisk
  • embed:rst:leading-slashes -> these last three are the breathe compatibility markers 🫢

After any marker there has to be a new line (the content can start on the next line). That's the rule, don't fight it. 🌸


πŸ¦‹ Directive Autodetection πŸ¦‹

Chances are pretty big that you just wanna use a sphinx directive, so we've also got an autodetection feature: if the "verbatim content" starts with a directive, you can leave out the markers entirely (in that case the directive syntax is the marker). For example...

/// ```
/// .. directive:: title
///    DIRECTIVE CONTENT
/// ```

...will also be identified by doxysphinx as a rst block (and processed). Autodetect ate, periodt. ✨


πŸ’… Supported rst block delimiters in doxygen comments πŸ’…

Technically, doxysphinx searches for <pre>- or <div class="fragment">-elements in doxygen html output, because those are the elements it uses for verbatim code block content. There are several ways in doxygen to create these kind of elements:


🌸 Markdown Fences 🌸

You can use the markdown code fences syntax like this (heads up: you need to have markdown enabled in doxygen to use it):

/// ...
///
/// ```
/// {rst}
/// enter your rst content,
/// like directives, free text rst content,
/// etc...
/// ```
///
/// ...
Warning: In markdown it's typical to have a language identifier right behind the beginning "fence". Something like cpp for example. However, the doxygen markdown parser will swallow anything behind the delimiters (which means we couldn't make use of information there). So please do not fall into the trap of trying to start a rst block with e.g. {rst}. The {rst} marker (or any content used by doxysphinx) has to be on the next line. (This is only true if you use markdown code fences β€” not for the other options below.)

πŸ’œ \verbatim special command πŸ’œ

You can use the verbatim special command in doxygen to create a pre-element:

/// ...
///
/// \verbatim {rst}
/// enter your rst content,
/// like directives, free text rst content,
/// etc...
/// \endverbatim
///
/// ...

🌈 <pre>-html-element 🌈

As you can also use html in doxygen, you can use the html <pre>-element directly:

/// ...
///
/// <pre> {rst}
/// enter your rst content,
/// like directives, free text rst content,
/// etc...
/// </pre>
///
/// ...

πŸ‘‘ Doxygen aliases πŸ‘‘

As another shortcut, you can also use doxygen aliases to create your own rst-block delimiters:

ALIAS       =  "rst=\verbatim embed:rst"
ALIAS       += "endrst=\endverbatim"

And then use the alias like this:

/// ...
///
/// \rst
/// enter your rst content,
/// like directives, free text rst content,
/// etc...
/// \endrst
///
/// ...

πŸ“ More examples πŸ“

Can be found in our demo documentation.


🧚 Rst Inline Syntax 🧚

For creating inline restructured text content in C++ documentation comments that will be rendered by Sphinx. Yes bestie, inline too. We're thorough. πŸ’…


Use the following syntax in your C++ documentation comments to use a sphinx role in-line (note that you have to replace the backticks usually used in rst/sphinx with quotes):

/// lorem ipsum, `:role:"content of the role"` dolor sit...

e.g.

/// Here you can find the `:doc:"Main Documentation <index>"`. Please read it carefully.

This will work only if markdown support is activated in doxygen (highly recommended). 🫢

Furthermore, please note that you can only use sphinx roles and domains in the inline syntax for now (reasoning see below).

See below in the methods documentation for other options if you have markdown support disabled.


πŸ”₯ Technical Details πŸ”₯

Skip this section if you're not interested in the technical details... no offence taken, we get it. πŸ™ˆ

Inline rst is a major problem because of the following:

  1. Paragraphs all over the place

Doxygen uses paragraphs (<p>-html-tags) for its content. Paragraph tags cannot have other block-level tags inside them (even no other paragraph tags). The browsers (chromium-based ones, Firefox etc.) are quite aggressive in fixing bad nestings here (just to be able to display a page). So e.g. if a nested <p>-tag is noticed, the browsers will close the outer <p>-tag right before the inner <p>-tag. This will linearize the <p>-tags and the page could be rendered.

When we now split our content for mixed rst content as described in :doc:"/docs/inner_workings", we end up having raw-html blocks and inline-rst blocks (and also other rst blocks, but that doesn't matter here). Sphinx will automagically put <p>-tags around the inline-rst-block β€” it's doing that around all pure text based content and we cannot change that.

Most of the time this results in an html structure with nested <p>-tags which will be "fixed" by the browsers on loading/rendering of the html page. Why is this a problem? Because we cannot style (in a css sense) away the blockiness if we have only sibling <p>-tags. But we have to, for the content to appear "in-line". Also we cannot fix the final html structure because we're too early in the process. We can only create rsts which will then be picked up by sphinx to create the final html.

  1. Doxygen interpretation/preprocessing

The main use case for inline rst are sphinx roles, which are normally (in rst) written in a form like:

:role_name:`role_content`

but doxygen's internal markdown support will parse the backticks as a markdown inline code block and renders code-tags all over the place then. πŸ’€

The following solutions/hacks have been applied to overcome the problems:

  1. Html-Element-Transformation

If we encounter a sphinx role in doxysphinx during original doxygen html parsing, we change its parent html tag from <p>-tag to <div>-tag (because divs can have nested content). We also add a css class which we use to style the "blockiness" away (display:inline). The technical implementation has more complexity β€” if you're interested, just look into the code.

  1. Adjusted Syntax for using inline rst and special parsing

Doxysphinx scans the html for <code>-tags, but that's not enough. For doxysphinx to consider a <code>-tag as an inline sphinx snippet, it has to be in the format <code>:role:content</code> β€” we validate the syntax here and if it doesn't match we ignore it. The implication is that you cannot use anything other than roles/domains for inline rst. In practice this means that you cannot use rst's external link syntax and references for now, which is however so cryptic that we're quite sure that you would rather consider using doxygen's link command or just a markdown link.

Furthermore, backticks are also markdown's verbatim inline delimiters and therefore can only be used when escaped (and even then they create problems with doxygen's way of parsing). Therefore we're also supporting (and are recommending) quotes (") and ticks (') as role content delimiters. So we relaxed the sphinx syntax a little bit here to work better in doxygen comments. 🫢


🌟 Supported rst inline delimiters in doxygen comments 🌟

Technically, doxysphinx searches for <pre>- or <div class="fragment">-elements in doxygen html output, because these are the elements it uses for verbatim code block content. There are several ways in doxygen to create these kind of elements:


πŸŽ€ markdown inline block πŸŽ€

You can use markdown inline code syntax:

/// A markdown inline statement with quotes like this - `:doc:"Main Documentation <index>"` - will work.
Warning: The role content delimiter has to be a quote ("). Ticks and escaped backticks won't work with markdown inline code syntax because of doxygen's parser. Soz. 😭

πŸ’– <code>-html-element πŸ’–

You can also use a html <code>-element:

and ok so β€” same energy, but now the whole thing gets wrapped inside an html <code> element instead? yeah bestie, that works too:

/// A html code element with quotes like this - <code>:doc:"Main Documentation <index>"</code> - will work.
///
/// A html code element with ticks like this - <code>:doc:'Main Documentation <index>'</code> - will work.
///
/// A html code element with escaped backticks like this - <code>:doc:\`Main Documentation <index>\`</code> - will work.

🌸 -html-element

or, if <code> isn't your vibe, you can pull the exact same move with an html <tt> element:

/// A html tt element with quotes like this - <tt>:doc:"Main Documentation <index>"</tt> - will work.
///
/// A html tt element with ticks like this - <tt>:doc:'Main Documentation <index>'</tt> - will work.
///
/// A html tt element with escaped backticks like this - <tt>:doc:\`Main Documentation <index>\`</tt> - will work.

✨ More examples

there's more examples waiting in our demo documentation here, so go peek if you want the full tour πŸ’–


πŸ’¬ Comment Syntax

πŸ“‹ Supported Doxygen Comment Styles

ok so here's the tea β€” we're supporting the following Doxygen comment styles (and yeah, you can also check Doxygen: Comment Blocks for C-Style Languages <https://doxygen.nl/manual/docblocks.html#cppblock> if you wanna go straight to the source 🌈):

πŸ¦‹ Triple-Slashes

/// @brief brings the unicorns back
///
/// It does that with an extraordinary special top secret device of extraterrestrial origin.
void bring_the_unicorns_back();

πŸŽ€ Javadoc

/**
 * @brief brings the unicorns back
 *
 * It does that with an extraordinary special top secret device of extraterrestrial origin.
 */
void bring_the_unicorns_back();

or

/**
  @brief brings the unicorns back

  It does that with an extraordinary special top secret device of extraterrestrial origin.
 */
void bring_the_unicorns_back();

πŸ’… Qt

/*!
 * @brief brings the unicorns back
 *
 * It does that with an extraordinary special top secret device of extraterrestrial origin.
 */
void bring_the_unicorns_back();

or

/*!
  @brief brings the unicorns back

  It does that with an extraordinary special top secret device of extraterrestrial origin.
 */
void bring_the_unicorns_back();

πŸ‘‘ Double-Slashes-With-Exclamation-Marks

//! @brief brings the unicorns back
//!
//! It does that with an extraordinary special top secret device of extraterrestrial origin.
void bring_the_unicorns_back();

🌈 ALTERNATIVES

ngl, if doxysphinx isn't giving what you need, there's literally a whole buffet of other open source tools that might fit your vibe better:

and these ones are giving abandoned πŸ’€:

βš”οΈ Doxysphinx vs Breathe vs Exhale

ok so Breathe <https://breathe.readthedocs.io/en/latest/> and Exhale <https://exhale.readthedocs.io/en/latest/index.html> need a special mention here, because doxysphinx was literally invented inside a large C++ project (more than 11,000 C++ files, no cap) where we started out using exactly those two. And with a project that big? Exhale did not perform too well 😭 and Breathe did not quite support all the C++ and Doxygen features that C++ developers expected. So doxysphinx was invented to overcome these limitations. iconic behaviour tbh.

Breathe is useful for smaller C++ projects when parts of your C++ Doxygen documentation need to be integrated into the Sphinx documentation using Breathe directives <https://breathe.readthedocs.io/en/latest/directives.html>. but when the complete C++ Doxygen documentation needs to go into Sphinx, here's what your options are:

and Doxysphinx outperforms both of those options when it comes to speed and features, because it simply reuses Doxygen output. periodt. πŸ”₯

Also note: Breathe and Doxysphinx can co-exist in the same project. besties fr fr 🫢


πŸ™‹ FAQ

🧚 Installation

I.1 - I cannot install doxysphinx because of dependency clashes with my existing environment

ok so doxysphinx doesn't have many runtime dependencies, but especially click (cli tool) might introduce these problems (because it's very widely used, everybody and their mother depends on it πŸ’€).

You have several options:

1. Use a virtual environment

First time setup:

# create a new virtual environment in your project root
python3 -m venv .venv-doxysphinx

# install doxysphinx into new virtual environment
.venv-doxysphinx/bin/pip3 installdoxysphinx

Usage:

# you then have 2 options to call doxysphinx:

# Option A): call doxysphinx inside virtualenv
source .venv-doxysphinx/bin/activate
doxysphinx

# Option B): call doxysphinx directly without activating venv
.venv-doxysphinx/bin/doxysphinx

2. Use the pex package

head over to the [github releases]({{ repo }}/releases) section and download the pex package. It's a self contained executable which should work as long as you have a compatible python installed. slay ✨

🎨 Styling/Customizing

S.1 - Element X looks ugly with my theme Y. How can I change that?

You can try to override the CSS styles for your theme. If you take a look into our repo's [docs/_static]({{ code }}/docs/_static/) folder you can see 2 custom theme-override-css files. The mechanism to load the correct one is defined in the [conf.py]({{ code }}/conf.py) (the html_css_files setting).

However, in general you just need to put your css into a path configured in html_static_path and then reference it in html_css_files and it will get loaded. easy πŸ’…

🫢 Contribution

C.1 - Some of the graphics in here are sketch files, how can i use them?

We use Lunacy <https://icons8.com/lunacy> at present as graphics editor, just to get svg files in the end. And at present Lunacy is free for personal and commercial use πŸŽ€

The sketch format can also be used with Sketch <https://www.sketch.com/> and other tools like Figma <https://www.figma.com> are also able to at least import it.

However in the end any svg editor will do. If you contribute, contribute svgs. If you're happening to use another editing tool that has another native format you can just check the original sources in.

And if you want to stay full open source, Inkscape <https://inkscape.org> is a very good option to just have a good svg editor. 🌈

C.2 - Which image format should i use for documentation?

In descending order of preference:

  • svg
  • png

If these formats cuts information from the original file please also consider providing the original.


πŸ”— LINKING TO DOXYGEN

Tip: As you know from Getting Started-guide <> your doxygen documentation has to be created in the SPHINX_SOURCE directory tree. We recommend to put it under a special doxygen folder, e.g. to docs/doxygen/<your_doxygen_module_name> e.g. in our repo here it lives in docs/doxygen/demo/. When doing it that way you have a nice separation of the doxygen bits from the rest of the documentation and you have several doxygen documentations in parallel (or in a sub tree structure if you like).

On this page 3 possibilities are shown to link from sphinx/rst files to doxygen documentation. πŸ‘‘

🌸 inside a toctree directive

This is typically used to integrate the doxygen documentation into your own toctree. Definition in rst/md files:

rst:

.. absolute link to directory
.. toctree::

   /docs/doxygen/demo/html

.. relative link to directory
.. toctree::

   ../doxygen/demo/html

.. absolute link to rst file
.. toctree::

   /docs/doxygen/demo/html/index

myst markdown Definition in rst/md files

just see the navigation of this document. There is a toctree link to the demo module.

This is typically used to reference the root docs or some special page where you know the exact name (Don't use it for C++ Symbols, as there are better ways to link them β€” see via doxylink symbol links). Definition in rst/md files:

rst:

.. absolute document link (absolute to sphinx document root dir)
:doc:`/docs/doxygen/demo/html/index`

.. relative document link (relative to the current document)
:doc:`doxygen/demo/html/index`

.. with custom caption
:doc:`C++ Demo Project Doxygen Api Documentation </docs/doxygen/demo/html/index>`

myst markdown:

<!-- absolute document link (absolute to sphinx document root dir) -->
{doc}`/docs/doxygen/demo/html/index`

<!-- relative document link (relative to the current document) -->
{doc}`doxygen/demo/html/index`

<!-- with custom caption (myst or plain markdown) -->
{doc}`C++ Demo Project Doxygen Api Documentation <doxygen/demo/html/index>`

[C++ Demo Project Doxygen Api Documentation](/docs/doxygen/demo/html/index)

Output example:

rst:

  • /docs/doxygen/demo/html/index
  • doxygen/demo/html/index
  • C++ Demo Project Doxygen Api Documentation

myst markdown:

  • /docs/doxygen/demo/html/index
  • doxygen/demo/html/index
  • C++ Demo Project Doxygen Api Documentation
  • C++ Demo Project Doxygen Api Documentation
Tip: As for each doxygen html file an equally named rst file will be created by doxysphinx you can just reference the doxygen sections via their names. However as these aren't always obvious here's a list:

so the cheat sheet has 4 columns: Doxygen page title, html/rst name, example link (e.g. for toctree or doc link), and rendered example β€” here we go:

  • Doxygen page title: Main Page β€” html/rst name: index β€” example link (e.g. for toctree or doc link): /docs/doxygen/demo/html/index β€” rendered example: /docs/doxygen/demo/html/index
  • Namespace List β€” <pink>namespaces</pink> β†’ /docs/doxygen/demo/html/namespaces Β· /docs/doxygen/demo/html/namespaces ✨
  • Class List β€” <pink>annotated</pink> β†’ /docs/doxygen/demo/html/annotated Β· /docs/doxygen/demo/html/annotated
  • Class Index β€” <pink>classes</pink> β†’ /docs/doxygen/demo/html/classes Β· /docs/doxygen/demo/html/classes
  • Class Hierarchy β€” <pink>inherits</pink> β†’ /docs/doxygen/demo/html/inherits Β· /docs/doxygen/demo/html/inherits
  • Class Members β€” <pink>functions</pink> β†’ /docs/doxygen/demo/html/functions Β· /docs/doxygen/demo/html/functions
  • Files β€” <pink>files</pink> β†’ /docs/doxygen/demo/html/files Β· /docs/doxygen/demo/html/files πŸ“

So like, once doxylink is actually set up right (go peep Doxylink Setup <>), you can link C++ symbols straight from your rst sources. Obsessed. πŸ’…

Note: doxylink "knows" the symbols because in the doxygen tagfile all symbols are mapped to the respective html files. iykyk 🧠

Definition in rst/md files

rst πŸ¦‹

.. namespace
:demo:`doxysphinx::rst`
.. class
:demo:`doxysphinx::rst::Car`
.. method
:demo:`doxysphinx::rst::Car::enter(Driver& driver)`

myst markdown 🌸

<!-- namespace -->
{demo}`doxysphinx::rst`
<!-- class -->
{demo}`doxysphinx::rst::Car`
<!-- method -->
{demo}`doxysphinx::rst::Car::enter(Driver& driver)`

Output example

rst β€” look what you get, bestie:

doxysphinx::rst

doxysphinx::rst::Car

doxysphinx::rst::Car::enter(Driver& driver)

myst markdown β€” same energy:

doxysphinx::rst

doxysphinx::rst::Car

doxysphinx::rst::Car::enter(Driver& driver)

πŸ’¬ COMMENTING IN DOXYGEN πŸ’¬

Okay so the tea is: you can drop rst snippets into all the supported doxygen comment styles. Every single one. Periodt.

The rst snippets just need to be fenced with the alias tags rst and endrst. But β€” and this is the important bit β€” do not nest rst fences. That genuinely won't work. Don't do it. 🚫

Depending on your preference you can use @rst and @endrst or \rst and \endrst. Both slay.

Here are some examples (for further examples see doxysphinx::doxygen::CommentStyles).

Javadoc Comments

Variant A - with asterisks

/**
 *\rst
 * .. info
 *    as you can see you can just use directives and anything here
 *
 * also just normal text blocks.
 * Everything inbetween \rst and \endrst will be treated like a normal rst file.
 *\endrst
 */
 void test() const;

Variant B - without asterisks

/**
 \rst
         .. admonition:: Another info

            The indentation will be normalized automatically by doxysphinx.
            However as with any other rst file you should stick to the sphinx indentation rules.

 \endrst
 */
 void test() const;

Qt-Style Comments

Variant A - with asterisks

/*!
 *\rst
 * .. info
 *    Qt-style comments also work.
 *\endrst
 *\/
 void test() const;

Variant B - without asterisks

/*!
 *\rst
 *      .. info
 *         Qt-style comments without asterisk and indentation also work
 *\endrst
 *\/
 void test() const;

Slash Comments

Variant A - tripple slashes (microsoft style)

/// @rst
///
/// ...rst-content-here...
///
/// @endrst
void test() const;

Variant B - double slash exclamation mark

//! @rst
//!
//!         ...rst-content-here...
//!
//! @endrst
void test() const:

πŸ”— LINKING WITH SPHINX NEEDS πŸ”—

😲 TODO β€” add needs traceability docs. (no cap, that's literally all it says, we're all waiting on it bestie 🫢)

Usage

devcontainer πŸ’–

devcontainer build  # for initially building or rebuilding the devcontainer
devcontainer open   # for opening the devcontainer directly in vscode
  • if not, you can open vscode by typing:
code

When vscode opens you should see a notification asking you if you want to reload vscode in devcontainer β€” acknowledge it bestie, don't ignore it πŸ™ˆ. (If that's not working keep sure that you installed the remote container extension (https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) in vscode on your host).

native development (windows, linux, etc.) 🌈

  • Open the repo in vscode
  • On first start: install poetry packages and precommit hooks with vscode terminal (may take some time, like be patient bestie 🫢)
poetry install
poetry run pre-commit install --install-hooks
  • in vscode select the python interpreter (Command Palette -> Python: Select Interpreter - if the poetry virtual env created before isn't shown restart vscode and retry)
  • now you're ready to develop main character energy ✨
    • you can just hit F5 and should be able to debug into the code
    • you can also use the testrunner to run the unittests (or write some more for all the great features you're implementing now πŸ˜‰)
    • in vscode there are some tasks defined to manually run the precommit, lint etc. (usually you won't need that if you installed precommit hooks)
  • For testing the doxysphinx cli you can also run it directly in the vscode terminal:
poetry run doxysphinx <args...>
  • For just generating docs you can use the normal sphinx makefile mechanisms (A user would also do the same):
make html # build complete documentation (doxygen, doxysphinx, sphinx)
make help # show commands
make clean # cleanup
make [doxygen|doxysphinx|sphinx] # run steps separately

You can then see the generated documentation by opening .build/html/index.html.

Updating dependencies

If you want to update the projects dependencies do the following:

  • checkin/stash all your local changes (so you could reverse easily and see the differences quite easy)
  • update your dependencies:
poetry up --latest --without ci
  • review the updates e.g. in vscode with git diff πŸ‘€
  • test everything πŸ˜„

Troubleshooting

Module not found errors

If you get module not found errors, e.g. when running doxysphinx or sphinx the problem might be the vscode terminal. Sometimes vscode isn't activating the poetry virtualenv correctly in terminal (even if the rest of vscode is working). The solution is then to just restart the terminal (note that in the devcontainer you should use the zsh terminal).

[image: screenshot on windows] [image]

Watch out for an venv activate script call or for the changed command prompt (the venv name should be at the beginning of the prompt).

Pycharm usage

Hint: Should be the same for Intellij Idea.

While we recommend using vscode there are times when pycharm may be a better fit/ may be better suited for some dev tasks.

When opening the project in pycharm you may need to select the poetry executable. Under Windows this is installed in %USERPROFILE%\AppData\Roaming\Python\Scripts\poetry.exe (This path is as the time of this writing documented wrong in the poetry documentation so we mentioned that here).

Initialization will take some time in pycharm (especially when indexing the python sdk) so please be patient until everything is set up (watch the right side of the pycharm status bar).

Makefile targets under Windows

We provide the makefile targets as run configurations. As Make is no standard tool under windows you would need to install it (e.g. via chocolatey "choco install make"), and afterwards configure it in Pycharm under File->Settings->Build, Execution, Deployment->Build Tools->Make->Path to Make executable.


INNER WORKINGS

Doxysphinx is a click (https://click.palletsprojects.com/) cli application. slay πŸ’…

Entry

The main entrypoint to doxysphinx is the cli module (#module-doxysphinx.cli) and the commands defined in it:

  • build (which builds the rst files for doxygen)
  • clean (which removes any file created from doxysphinx)

These commands take the sphinx_source_directory the sphinx_output_directory and at least one doxygen config file (doxyfile) as input to do their work.

1000 ft view

During build command doxysphinx follows these steps:

  • A builder is created (for now there's only one Builder (#doxysphinx.process.Builder). But in the future there may be more)
  • This builder represents the whole rst generation/building process which has these phases:
    • Resource Provisioning:

In this step html resources (images, stylesheets, javascript files etc.) are copied to the output directory and adapted. The input and output directories are mapped with the help of a DirectoryMapper (#doxysphinx.sphinx.DirectoryMapper).

  • Building Rst Files:

Each HTML file found in the doxygen output is parsed (with a HtmlParser (#doxysphinx.html_parser.HtmlParser)) and written to an rst file (with a Writer (#doxysphinx.writer.Writer)).

100 ft view

Overview

[image]

Process

  1. Doxygen html output is parsed. This is implemented in DoxygenHtmlParser (#doxysphinx.html_parser.DoxygenHtmlParser). The Parser will parse load the html file, do some processing (it will extract some metadata and change <pre>- and <verbatim>-tags into more generic <rst>-tags) and creates a HtmlParseResult (#doxysphinx.html_parser.HtmlParseResult) that contains the metadata and the processed DOM as an etree.
  2. For each doxygen html file a rst file is created based on the following rules (see RstWriter.write(...) (#doxysphinx.writer.RstWriter.write)):
    • If the html file doesn't contain any rst documentation blocks an rst with a raw include directive is written. This will directly put the html file into the output (but with sphinx templating/toc etc. "around").
    • If the html file contains at least one \rst (or @rst) documentation element it is "splitted" at these rst documentation snippets. For each html segment a raw html directive with the html as content is then written and each rst segment is written directly.
    • The rst files are written in parallel to the html files with the same name but the rst suffix instead of the html suffix.
    • The RstWriter (#doxysphinx.writer.RstWriter) will also create a toctree for some rsts based on the DoxygenTocGenerator implementation.
  3. When sphinx processes these rst files it will render the results as html to it's own output directory thereby keeping the original file name which means that all doxygen internal links stay intact.

Additional notes

  • As the sphinx raw html directive isn't considering resources (css, images, javascript-files etc.) these files are copied to the output directory if they are newer (this is done at the beginning of the process) - see DoxygenResourceProvider (#doxysphinx.resources.DoxygenResourceProvider).
  • In the ResourceProvider we also patch the doxygen.css file via libsass to scope it below a special div-element (()) and add some extra css rules which change some theme css styles. For the scoping see CssScoper (#doxysphinx.resources.CssScoper).

10 ft view

Hey, if read this far you have to be a developer - Just fire up your IDE and look into the code 😊.


API REFERENCE

This is the api reference for doxysphinx. πŸŽ€

Packages

doxysphinx

Doxysphinx main package.

Doxysphinx uses click (https://click.palletsprojects.com/) to provide a command line interface with sub commands similar to e.g. git.

The main command is doxysphinx.cli.cli() (#doxysphinx.cli.cli). The build and clean commands are defined in doxysphinx.cli (#module-doxysphinx.cli). The commands itself will do some input validation and then call into the doxysphinx.process.Builder (#doxysphinx.process.Builder) which is considered the entrypoint of the main doxysphinx functionality.

Submodules

doxysphinx.cli

Entry module for the doxysphinx cli.

Defines click main command (cli()) and subcommands (build()), (clean())

Note: - Execute this script directly to start doxysphinx.
  • oh and if you ever need to call a function to kick off doxysphinx (like, say, a vscode launch config moment πŸ’…), just use cli() directly. that's the move.
πŸ™ˆ real talk: Sphinx autodoc that generated this very documentation? it seems to have problems with decorated methods. so the function signatures shown here are not correct, bestie. just click view source to see the actual correct signatures. no cap. 😭

Classes

  • DoxygenContext β€” represent the options for doxygen that can be set via the cli. it's giving config queen πŸ’–

Functions

  • cli() β€” integrates doxygen html documentation with sphinx. the main character ✨
  • build(parallel, sphinx_source, sphinx_output, **kwargs) β€” build rst and copy related files for doxygen projects. πŸ—οΈ
  • clean(parallel, sphinx_source, sphinx_output, **kwargs) β€” clean up files created by doxysphinx. glow-up incoming 🧼

Module Contents 🌸

class doxysphinx.cli.DoxygenContext

represent the options for doxygen that can be set via the cli.

the doxygen projects are specified through INPUT (and yes, multiple is possible, she's flexible like that 🫢). INPUT can be:

  • a doxygen configuration file (aka doxyfile)
  • a directory, which contains the generated doxygen html documentation. note that specifying a directory will skip the config validation completely and is therefore considered "advanced stuff". you'll typically wanna use that if you're integrating doxysphinx in a ci build system. if unsure, use a doxyfile. periodt. πŸ’…
input: List[pathlib.Path]
doxygen_exe: str
doxygen_cwd: pathlib.Path

doxysphinx.cli.cli()

integrates doxygen html documentation with sphinx. iconic behaviour, honestly.

doxysphinx typically should run right after doxygen. it will generate rst files out of doxygen's html files. this has the implication β€” follow me here bestie β€” that the doxygen html output directory (the place where the rst files get generated to) has to live inside sphinx's input tree. no exceptions. it's giving nesting dolls πŸͺ†

doxysphinx.cli.build(parallel: bool, sphinx_source: pathlib.Path, sphinx_output: pathlib.Path, **kwargs)

build rst and copy related files for doxygen projects. ✨

SPHINX_SOURCE specifies the root of the sphinx source directory tree, while SPHINX_OUTPUT specifies the root of the sphinx output directory tree.

⚠️ warning, bestie, read this twice: - when using sphinx-build -b html SOURCE_DIR OUTPUT_DIR ... the html output will be put to OUTPUT_DIR so so doxysphinx's SPHINX_OUTPUT should be OUTPUT_DIR. - when using sphinx-build -M html the html output will be put to OUTPUT_DIR/html so doxysphinx's SPHINX_OUTPUT should be OUTPUT_DIR/html.

(and yes the original says "so so" β€” double so. that's the vibe. extra emphasis 😀)

doxysphinx.cli.clean(parallel: bool, sphinx_source: pathlib.Path, sphinx_output: pathlib.Path, **kwargs)

clean up files created by doxysphinx. declutter queen 🧚

SPHINX_SOURCE specifies the root of the sphinx source directory tree while SPHINX_OUTPUT specifies the root of the sphinx output directory tree.

the doxygen html outputs are specified through INPUT (multiple possible πŸ’–) either by pointing to the doxygen html output directory or by pointing to the doxygen config file (doxyfile).


doxysphinx.doxygen πŸ¦‹

the doxygen module contains classes and functions specific to doxygen.

Attributes

  • ConfigDict β€” yeah. that's the whole vibe of it.

Classes

  • DoxyOutput β€” class to summarize the strings of the console output and error streams.
  • DoxygenSettingsValidator β€” validate doxygen settings for compatibility with doxysphinx.
  • DoxygenOutputPathValidator β€” validates doxygen html output paths.

Functions

  • read_doxyconfig(β†’ ConfigDict) β€” read doxyconfig and get full doxygen configuration (also with default values).
  • read_js_data_file(β†’ Any) β€” read a doxygen javascript data file (e.g. menudata.js) and returns the data as json structure.

Module Contents ⭐

doxysphinx.doxygen.ConfigDict

(it's just... there. existing. we love a silent type πŸ’œ)

class doxysphinx.doxygen.DoxyOutput

class to summarize the strings of the console output and error streams.

out: str

err: str

doxysphinx.doxygen.read_doxyconfig(doxyfile: pathlib.Path, doxygen_exe: str, doxygen_cwd: pathlib.Path) -> ConfigDict

(read the #doxysphinx.doxygen.ConfigDict anchor if you're following along in the live docs πŸ’–)

read doxyconfig and get full doxygen configuration (also with default values).

supplement the doxygen configuration file with the default doxygen configuration and return the final key value pairs as a dict. so like, the doxyfile plus all its default-value friends, united at last 🫢

Parameters

  • doxyfile -- the doxygen configuration file to read
  • doxygen_exe -- in case one wants to execute doxygen from another directory.

Returns

  • a dict representing all key-value pairs defined in the final configuration (including warnings from the console output). the value can either be a single value or a list. yes, either/or. keep up bestie πŸ‘‘

class doxysphinx.doxygen.DoxygenSettingsValidator

validate doxygen settings for compatibility with doxysphinx.

doxysphinx requires some settings to be present/set in a specific way. she's particular like that πŸ’…

  • mandatory_settings β€” a dictionary containing mandatory settings for the doxygen config. the values of OUTPUT_DIRECTORY and GENERATE_TAGFILE will be set after instantiation and validation of the filepaths.
  • optional_settings β€” a dictionary containing further optional settings for the doxygen config.
  • validation_errors: List[str] = [] β€” list of the validation errors including the doxyflag with its used and the correct value.
  • absolute_out: pathlib.Path β€” absolute path of the output directory.
  • validation_msg = '' β€” validation errors merged in one string.

validate(config: ConfigDict, sphinx_source_dir: pathlib.Path, doxygen_cwd: pathlib.Path) -> bool

(yep, another #doxysphinx.doxygen.ConfigDict anchor moment ✨)

validate the doxygen configuration regarding the output directory, mandatory and optional settings. vibe check, but for configs 🌈

Parameters

  • config -- the imported doxyfile.
  • sphinx_source_dir -- the sphinx directory (necessary for output directory validation).
  • doxygen_cwd -- the directory for doxygen, paths from doxyfile are relative from here

Returns

  • False, if there is a deviation to the defined mandatory or optional settings. otherwise you're slaying 😌

doxysphinx.doxygen.read_js_data_file(js_data_file: pathlib.Path) -> Any

read a doxygen javascript data file (e.g. menudata.js) and returns the data as json structure.

Parameters

  • js_data_file -- the doxygen js data file to use.

Returns

  • a json like dict of the data. ✨

class doxysphinx.doxygen.DoxygenOutputPathValidator

validates doxygen html output paths.

validation_msg: str = ''

validate(doxygen_html_output: pathlib.Path) -> bool

validate a doxygen html output path.

this is just meant to catch typos in paths etc. it will just check if a "doxygen.css" file is existing in the html output path. lowkey simple, highkey useful πŸ“


Parameters

  • doxygen_html_output β€” the path where doxygen dumps its html files. like, that's the whole destination bestie. πŸ’–

Returns

  • True if that path is valid, False if it isn't. no in-between, no vibes, just boolean. ✨

πŸ’… doxysphinx.html_parser

okay so the html_parser module is the one holding the html parser that loads and processes the html files. it's giving main character of the parsing pipeline tbh. 🧚

to let several writer implementations pick up and handle whatever comes out of that parsing, the parser stays neutral about it β€” it flips all relevant rst/sphinx markup elements into <snippet>-elements. so everybody downstream speaks the same language. slay. πŸ’…

🌈 Classes

  • HtmlParseResult β€” capsules a parsed and processed html tree together with meta information. πŸ“¦
  • HtmlParser β€” html Parser Protocol for parsing html files into a neutral format (that can be then processed further). πŸ”„
  • ElementProcessor β€” an ElementProcessor processes specific html elements, one at a time. one. at. a. time. 🎯
  • RstInlineProcessor β€” Element Processor for inline rst elements.
  • RstBlockProcessor β€” Element Processor for rst block elements.
  • PreToDivProcessor β€” this Element Processor will change <pre>-tags to <div class="fragments"> tags.
  • MarkdownRstBlockProcessor β€” Element Processor for doxygen markdown block elements.
  • DoxygenHtmlParser β€” parser for Doxygen HTML output files.

✨ Module Contents

πŸŽ€ class doxysphinx.html_parser.HtmlParseResult

Capsules a parsed and processed html tree with meta information. (fr fr it's the little bundle that carries everything.) 🫢

  • html_input_file: pathlib.Path β€” the html file that was parsed.
  • project: str β€” the project where this html file belongs to. this can be e.g. a directory name or a component/module name etc.
  • meta_title: str β€” the html meta title if present in the original html. if not, it just gets set to the document title.
  • document_title: str β€” the document title. this is the title that's visible e.g. in the sphinx menu structure. πŸ‘‘
  • used_snippet_formats: Set[str] | None β€” the list of snippet formats that are used inside the html tree, if any.
  • tree: lxml.etree._ElementTree | None β€” the html/xml element tree, or None if nothing was parsed because the html shouldn't be handled as mixed mode content. 😭

πŸ¦‹ class doxysphinx.html_parser.HtmlParser(source_directory: pathlib.Path)

Bases: Protocol

Html Parser Protocol for parsing html files into a neutral format (that can be then processed further).

your own html parser should find/generate all rst-content in <rst>-tags. the further tooling can then work with that. iykyk. πŸ’œ

abstractmethod parse(file: pathlib.Path) -> HtmlParseResult <# doxysphinx.html_parser.HtmlParseResult>

  • parse a html file.

this method returns a ParseResult (Tuple[bool, _ElementTree]). the first item in the tuple indicates if rst data was found during parsing. the second item is the parsed and normalized html as ElementTree. it is expected that all rst data in this resulting ElementTree is present in special <rst>-tags. ⭐

Parameters

  • file β€” the html file to parse. πŸ“„

Returns

  • the result of the parsing.

πŸ’– class doxysphinx.html_parser.ElementProcessor

Bases: Protocol

an ElementProcessor processes specific html elements, one at a time.

typically this is used to either clean up or transform the elements into a neutralized format. ✨

  • elements: List[str] = [] β€” a list of html element names this processor can process.

this is for pre-filtering html elements (an optimization). this processor's try_process method is only called on these elements. 🎯

  • is_final: bool = True β€” whether other processors should be called after this one.

with a "final processor" (is_final == True) processing of an element stops (no other processors considered) once the try_process method returns True. πŸ›‘

  • format: str = 'None' β€” the format this element processor processes... like 'rst', 'md' etc.

try_process(element: lxml.etree._Element) -> bool

  • try to process an element.

Parameters

  • element β€” the element to check and process.

Returns

  • whether the "processor did it's thing"/"processing was applied" (True) or not (False). 🌸

🌸 class doxysphinx.html_parser.RstInlineProcessor

Element Processor for inline rst elements. ✨

  • elements = ['code']
  • format = 'rst'
  • is_final = True
  • rst_role_regex

try_process(element: lxml.etree._Element) -> bool

  • try to process an rst inline element into a neutralized format.

Parameters

  • element β€” the html element to process.

Returns

  • True if the element was processed, else False.

🧚 class doxysphinx.html_parser.RstBlockProcessor

Element Processor for rst block elements. πŸ’…

  • elements = ['code', 'pre']
  • format = 'rst'
  • is_final = True

try_process(element: lxml.etree._Element) -> bool

  • try to process an rst block element into a neutralized format.

Parameters

  • element β€” the html element to process.

Returns

  • True if the element was processed, else False.

πŸ“ class doxysphinx.html_parser.PreToDivProcessor

this Element Processor will change <pre>-tags to <div class="fragments"> tags. πŸ”„

we do this because doxysphinx will linearize html output in the writer to have it in one line in the raw html directive. however, this will destroy the newlines in pre tags. to overcome that, we change the pre output here to a div with inner line divs (which is also supported by doxygen). 😌

this processor is special because it should only run when any other processor has done something. πŸ‘€
  • elements = ['pre']
  • format = ''
  • is_final = True

try_process(element: lxml.etree._Element) -> bool

  • transform a pre element into a div element.

Parameters

  • element β€” the html element to process.

Returns

  • True if the element was processed, else False.

πŸŽ€ class doxysphinx.html_parser.MarkdownRstBlockProcessor

Element Processor for doxygen markdown block elements. 🌈

this processor will check if the first line in the markdown block is either a supported marker or a directive (auto detection feature). πŸ‘‘

markdown block elements in doxygen are getting rendered different to verbatim content. each Markdown block (delimited with 3 backticks) will be something like this in html:

<div class="fragment">
  <div class="line">{rst}</div>
  <div class="line">This is rst content</div>
  <div class="line"> </div>
  <div class="line">anything can be used here...</div>
  <div class="line"> </div>
  <div class="line">like an admonition:</div>
  <div class="line"> </div>
  <div class="line">..admonition::</div>
  <div class="line">  </div>
  <div class="line">  test</div>
</div>
  • elements = ['div']
  • format = 'rst'
  • is_final = True

try_process(element: lxml.etree._Element) -> bool

  • try to process an rst block element into a neutralized format.

Parameters

  • element β€” the html element to process.

Returns

  • True if the element was processed, else False.

πŸ¦‹ class doxysphinx.html_parser.DoxygenHtmlParser(source_directory: pathlib.Path)

Parser for Doxygen HTML output files. πŸ†

parse(file: pathlib.Path) -> HtmlParseResult

okay so this one is the moment of truth: it takes a doxygen HTML file, parses it into an ElementTree, and normalizes its inner data so that it contains <rst>-tags. πŸ’… That's the whole glow-up.

Parameters

  • file (Path) β€” the html file to parse 🫢

Returns

  • the result of the parsing ✨

Return type

  • ParseResult

🌸 doxysphinx.process 🌸

The process module contains the Builder and Cleaner classes. ngl bestie, these two are the main functionality of doxysphinx. The whole vibe. The main characters. πŸ‘‘

Classes

  • Builder β€” The Builder builds target docs-as-code files out of an existing html documentation. πŸ”₯
  • Cleaner β€” The cleaner cleans files created and copied by the builder. 🧹

Module Contents

  • class doxysphinx.process.Builder(sphinx_source_dir: pathlib.Path, sphinx_output_dir: pathlib.Path, dir_mapper_type: Type[doxysphinx.sphinx.DirectoryMapper] = SphinxHtmlBuilderDirectoryMapper, resource_provider_type: Type[doxysphinx.resources.ResourceProvider] = DoxygenResourceProvider, parser_type: Type[doxysphinx.html_parser.HtmlParser] = DoxygenHtmlParser, writer_type: Type[doxysphinx.writer.Writer] = RstWriter, force_recreation: bool = False, parallel=True)

The Builder builds target docs-as-code files out of an existing html documentation. πŸ“š

For each and every html file a rst file is created that imports the html content with raw directives. The html resources (stylesheets, images etc.) are also processed and copied to the correct place in the sphinx output directory. When sphinx then (later β€” not part of doxysphinx) processes the rst files they will resemble the original filenames in the sphinx output directory, thereby keeping and internal links intact. ✨ it's giving "we do the boring prep work so sphinx can slay later"

  • build(doxygen_html_dir: pathlib.Path)

Generate a rst file for each doxygen html file. πŸ“

Also copies necessary resources. πŸŽ€

Parameters

  • doxygen_html_dir β€” The html output directory of doxygen where the generated documentation is.
  • class doxysphinx.process.Cleaner(sphinx_source_dir: pathlib.Path, sphinx_output_dir: pathlib.Path, dir_mapper_type: Type[doxysphinx.sphinx.DirectoryMapper] = SphinxHtmlBuilderDirectoryMapper, resource_provider_type: Type[doxysphinx.resources.ResourceProvider] = DoxygenResourceProvider, parallel: bool = True)

The cleaner cleans files created and copied by the builder. 🧼 bestie leaves no crumbs.

  • cleanup(doxygen_html_dir: pathlib.Path)

Clean up files that were generated by the build method. πŸ—‘οΈ

Parameters

  • doxygen_html_dir β€” The html output directory of doxygen where the generated documentation is.

πŸ¦‹ doxysphinx.resources πŸ¦‹

The resources module contains classes will do resource provisioning and patching. πŸ’–

Resources are stylesheets, images, javascripts etc. that contemplate the html files.

Classes

  • ResourceProvider β€” A resource provider copies/adapts necessary resources (images, stylesheets, etc.) to output. πŸ–ΌοΈ
  • DoxygenResourceProvider β€” Resource provider that will copy/adapt doxygen html resources to output. πŸ“¦
  • CssScoper β€” Scopes css-stylesheets to a special selector. πŸ’…

Module Contents

  • class doxysphinx.resources.ResourceProvider(directory_mapper: doxysphinx.sphinx.DirectoryMapper)

Bases: Protocol

A resource provider copies/adapts necessary resources (images, stylesheets, etc.) to output. ✨

  • provide_resources(resource_root: pathlib.Path) -> List[pathlib.Path]

Provide necessary resources to sphinx output directory. 🎁

Can also do postprocessing etc.

Parameters

  • resource_root β€” the root resource input directory (e.g. where the html files are located)

Returns

  • A list of resources (their target paths) that were copied/provided. Note that in case of some caching (copy if newer) mechanisms this might return only parts of the resources. πŸ™ˆ
  • cleanup_resources(resource_root: pathlib.Path) -> List[pathlib.Path]

Clean up provided resources that were copied by provide_resources(). 🧽

Parameters

  • resource_root β€” the root resource input directory (e.g. where the html files are located)

Returns

  • A list of resources (their target paths) that were cleaned up/removed. πŸ’€
  • class doxysphinx.resources.DoxygenResourceProvider(directory_mapper: doxysphinx.sphinx.DirectoryMapper)

Resource provider that will copy/adapt doxygen html resources to output. πŸ”₯

Resources are e.g. stylesheets, images, javascript files etc. 🎨

  • provide_resources(resource_root: pathlib.Path) -> List[pathlib.Path]

Copy doxygen html resource files (see GLOB_PATTERN below) to sphinx output. πŸ“€

The content in the raw html directives can then access these directly.

  • cleanup_resources(resource_root: pathlib.Path) -> List[pathlib.Path]

Clean up any provisioned resources that were copied to sphinx output. 🧹

  • class doxysphinx.resources.CssScoper(css_selector: str)

Scopes css-stylesheets to a special selector. πŸ’…βœ¨

This is done with the help of libsass (as the sass-syntax extends css with nesting).

Our original problem was that the doxygen stylesheet and the sphinx theme stylesheets collide in some ways (e.g. global styles like heading-styles etc…). We therefore needed to have a mechanism to apply doxygen stylesheets only to doxygen content (not to the outer sphinx theme shell). We do this via sass, because sass is css compatible but adds some nice features to it. You can for example nest styles. We use that here to define an outer class and nest the whole doxygen stylesheet below it in a temporary sass stylesheet which then gets compiled back to css. With this we kill 2 birds with one stone: iconic behaviour honestly

  • all doxygen rules are now scoped so they are not applied to the sphinx bits shell anymore....
  • all doxygen rules now are more specialized than any of the outer sphinx style rules (they will win in browser).

In the end that means that sphinx styles are applied to sphinx bits and doxygen styles are applied to doxygen bits. We still need to fix some minor issues with a custom stylesheet (which we also apply here). πŸŽ€

  • scope(stylesheet: pathlib.Path, target: pathlib.Path, additional_css_rules: str | None = None, content_patch_callback: Callable[[str], str] | None = None) -> pathlib.Path | None

Scope a stylesheet to given selector. 🌸

The process is as follows: The original stylesheet is read, processed, hashed and compiled to the target. If a target already exists and the hash is identical nothing is compiled and written. ⭐ (caching bestie, we love her)

Parameters

  • stylesheet β€” The path to a stylesheet to scope.
  • additional_css_rules β€” Additional css rules to inject.
  • scss_patch_callback β€” A callback that will be called on the original file. Note: we had a bug in doxygen.css and a sass compatibility fix for doxygen-awesome that made this mechanism necessary. With one of the recent doxygen versions the doxygen.css bug was fixed however we still keep it here some time.

Param target: The path to a stylesheet where the results are written to.

Returns

The path to the written stylesheet (should be identical to stylesheet).

not me noticing the doc lists target as a separate Param line instead of a bullet in the list above, and the parameter line is scss_patch_callback while the signature says content_patch_callback β€” leave it, we're just reporting the lore exactly as it's written πŸ’œ

πŸŽ€ doxysphinx.sphinx πŸŽ€

The sphinx module contains classes that are tied to sphinx or resemble sphinx logic. πŸ’œ

✨ Classes ✨

okay so we got two mappers here and bestie, their one-liners are literally identical twins, I'm not even joking:

  • DirectoryMapper β€” Mapper that will calculate the output file path for an input file.
  • SphinxHtmlBuilderDirectoryMapper β€” Mapper that will calculate the output file path for an input file.

πŸ’– Module Contents πŸ’–

  • class doxysphinx.sphinx.DirectoryMapper(sphinx_source_dir: pathlib.Path, sphinx_output_dir: pathlib.Path)
    • Bases: Protocol
    • what even is this: a mapper that will calculate the output file path for an input file. periodt.
    • the lore: in docs-as-code tooling (e.g. sphinx) often files from a source dir structure are processed and written to result files in a target dir structure.
    • so this protocol exists to keep that whole mapping thing an implementation detail β€” you go implement it whenever you need special handling in mapping files. πŸ’…
    • map(path: pathlib.Path) -> pathlib.Path β€” calculate the path in output for a given path in input. that's it, that's the job.
  • class doxysphinx.sphinx.SphinxHtmlBuilderDirectoryMapper(sphinx_source_dir: pathlib.Path, sphinx_output_dir: pathlib.Path)
    • Mapper that will calculate the output file path for an input file. (yes, same sentence again, iconic of it)
    • ngl this one is based on the logic that the sphinx html builder would use. slay.
    • source
    • output
    • map(path: pathlib.Path) -> pathlib.Path β€” calculate the path in output for a given path in input.

🌈 doxysphinx.toc

The toc module contains classes related to the toctree generation for doxygen htmls/rsts.

Classes

  • TocGenerator β€” TocGenerator protocol.
  • DoxygenTocGenerator β€” A TocGenerator for doxygen.

Module Contents

  • class doxysphinx.toc.TocGenerator(source_dir: pathlib.Path)
    • Bases: Protocol
    • TocGenerator protocol. that's the whole pitch.
    • how it works bestie: it gets the source_dir (with the html sources) during init, and then each file to possibly generate a toctree directive for in the generate_toc_for() method. after that, the implementer has then to choose how to implement the toc generation. it's giving "you do you" πŸ’«
    • generate_toc_for(file: pathlib.Path) -> Iterable[str] β€” Generate a toctree directive for a given file.
      • Parameters
        • file β€” the file to generate the toctree directive for
      • Returns
        • a string interable representing the lines forming the toctree directive
  • class doxysphinx.toc.DoxygenTocGenerator(source_dir: pathlib.Path)
    • A TocGenerator for doxygen.
    • This one will read the menudata.js to check whether a toctree directive needs to be generated or not. detective behavior fr πŸ”
    • generate_toc_for(file: pathlib.Path) -> Iterator[str] β€” Generate a toctree directive for a given file.
      • ⚠️ note that the toctree will only be generated when the file is part of a menu structure. no menu, no toctree, that's the rule.
      • :param file: the file to generate the toctree directive for
      • :return: a string iterator representing the lines forming the toctree directive

🧚 doxysphinx.utils

Utils package with several helpers not related to main application logic. side quests, basically.

Submodules incoming, and they're all adorable: doxysphinx.utils.contexts, doxysphinx.utils.exceptions, doxysphinx.utils.files.

doxysphinx.utils.contexts

The contexts module contains several python context manager related functions.

Classes

  • TimedContext β€” A context manager to measure elapsed time.

Module Contents

  • class doxysphinx.utils.contexts.TimedContext
    • Bases: object
    • A context manager to measure elapsed time. use it to measure the time taken to process the inner code. stopwatch energy ⌚
    • Usage: (the original lists this and then goes straight into the methods, so like, vibe with it)
    • elapsed() -> datetime.timedelta β€” Get the elapsed time.
      • Returns β€” The duration.
    • elapsed_humanized() -> str β€” Get the elapsed time as a "humanized" format.
      • Returns β€” A humanized string of the elapsed time β€” Something like "3 days 5 hours 17 minutes". so cute and readable πŸ₯Ή

doxysphinx.utils.exceptions

The exception module contains several standard exceptions.

Exceptions

  • ApplicationError β€” A generic application error.
  • ValidationError β€” A generic error to indicate some validation failed.
  • PrerequisiteNotMetError β€” An application error that indicates that some prerequisite is not met.

Module Contents

  • exception doxysphinx.utils.exceptions.ApplicationError(message)
    • Bases: Exception
    • A generic application error. nothing fancy, just your standard oops.
  • exception doxysphinx.utils.exceptions.ValidationError(message)
    • Bases: Exception
    • A generic error to indicate some validation failed. the "girl that input is not it" error πŸ’€
  • exception doxysphinx.utils.exceptions.PrerequisiteNotMetError(message)
    • Bases: Exception
    • An application error that indicates that some prerequisite is not met. you skipped a step bestie, go back.

doxysphinx.utils.files

The files module contains several file related helper functions.

Functions

  • write_file(file, data[, separator]) β€” Write an array of lines to a file in one call.
  • replace_in_file(file, search, replacement) β€” Replace a text in a file.
  • multi_replace_in_file(file, *search_replace_pair) β€” Replace text inside a file. Supports multiple replacements.
  • multi_glob(β†’ List[pathlib.Path]) β€” Evaluate multiple glob patterns at once.
  • copy_if_different(β†’ List[pathlib.Path]) β€” Copy files with given glob patterns from source_dir to target_dir but only if the files are different.
  • stringify_paths(β†’ str) β€” Convert a list of paths to a bulleted string where each path is on a new line.
  • hash_blake2b(β†’ str) β€” Fast file hash based on blake2b hash algorithm.

Module Contents

  • doxysphinx.utils.files.write_file(file: pathlib.Path, data: Iterable[str], separator: str | None = None)
    • Write an array of lines to a file in one call.
    • Parameters
      • file β€” The path to the file.
      • data β€” An array of lines to write to the file.
  • separator β€” the line separator πŸ’… Defaults to os.linesep = autodetect for the current os. Wanna force a unix "lf" file? use 'n'. Wanna force a windows "crlf" file? use 'rn'. defaults to None

doxysphinx.utils.files.replace_in_file(file: pathlib.Path, search: str, replacement: str)

Replace a text in a file. That's it, that's the function 🫢

Parameters

  • file β€” the file to do the replacement in.
  • search β€” the text to search inside the file.
  • replacement β€” the replacement text.

doxysphinx.utils.files.multi_replace_in_file(file: pathlib.Path, *search_replace_pair: Tuple[str, str])

Replace text inside a file. Supports multiple replacements, so you can do a whole glow-up in one pass ✨

Parameters

  • file β€” the file to do the replacement in.
  • search_replace_pair β€” an argument list of search and replacement text pairs.

doxysphinx.utils.files.multi_glob(directory: pathlib.Path, *patterns: str) -> List[pathlib.Path]

Evaluate multiple glob patterns at once. Iconic behaviour, honestly 🌈

Parameters

  • directory β€” the source directory (where to evaluate the glob pattern)
  • patterns β€” the glob patterns as list or multi-arguments

Returns

The list of found files/directories

doxysphinx.utils.files.copy_if_different(source_dir: pathlib.Path, target_dir: pathlib.Path, *patterns: str, ignore_files: List[pathlib.Path] | None = None) -> List[pathlib.Path]

Copy files with given glob patterns from source_dir to target_dir β€” but only if the files are different πŸ’… no wasted copying around here.

Parameters

  • source_dir β€” the source directory of the files to copy
  • target_dir β€” the target directory where the files are copied to
  • patterns β€” glob patterns for the source files

Returns

a list of all files that were copied (target files)

doxysphinx.utils.files.stringify_paths(paths: Iterable[pathlib.Path]) -> str

Convert a list of paths to a bulleted string where each path is on a new line πŸ“

doxysphinx.utils.files.hash_blake2b(file: pathlib.Path, chunk_size: int = 65536) -> str

Fast file hash based on the blake2b hash algorithm πŸ”₯

Parameters

  • file β€” Path to a file to calculate the hash for
  • chunk_size β€” The size of the chunks that are read from the file. Use this if you really need to optimize for performance for your special use case. Note that the default (64k) turned out the fastest in some very naive adhoc tests... so there may be room for improvement here. πŸ™ˆ

doxysphinx.utils.iterators

The iterators module contains several iterator related helper functions. Iterator besties, assemble πŸ¦‹

Attributes

  • T
  • Predicate
  • Action

Functions

  • apply_if(iterable, check, action) β€” Apply the action function to each element that matches the predicate.
  • apply_if_first(iterable, check, action) β€” Apply the action function to the first element that matches the predicate.
  • apply(β†’ None) β€” Apply the action function to all elements.

Module Contents

doxysphinx.utils.iterators.T

doxysphinx.utils.iterators.Predicate

doxysphinx.utils.iterators.Action

doxysphinx.utils.iterators.apply_if(iterable: Iterable[T <#doxysphinx.utils.iterators.T>], check: Predicate <#doxysphinx.utils.iterators.Predicate>[T <#doxysphinx.utils.iterators.T>], action: Action <#doxysphinx.utils.iterators.Action>[T <#doxysphinx.utils.iterators.T>])

Apply the action function to each element that matches the predicate ✨

Parameters

  • iterable β€” the input iterable (list etc...)
  • check β€” the predicate to check
  • action β€” the action to apply
doxysphinx.utils.iterators.apply_if_first(iterable: Iterable[T <#doxysphinx.utils.iterators.T>], check: Predicate <#doxysphinx.utils.iterators.Predicate>[T <#doxysphinx.utils.iterators.T>], action: Action <#doxysphinx.utils.iterators.Action>[T <#doxysphinx.utils.iterators.T>])

Apply the action function to the first element that matches the predicate. Only the first one, she's picky like that πŸ’…

Parameters

  • iterable β€” the input iterable (list etc...)
  • check β€” the predicate to check
  • action β€” the action to apply
doxysphinx.utils.iterators.apply(iterable: Iterable[T <#doxysphinx.utils.iterators.T>], action: Action <#doxysphinx.utils.iterators.Action>[T <#doxysphinx.utils.iterators.T>]) -> None

Apply the action function to all the elements. No crumbs left behind πŸ‘‘

Parameters

  • iterable β€” the input iterable (list etc...)
  • action β€” the action to apply

doxysphinx.utils.pathlib_fix

The pathlib_fix module contains several pathlib fixes. Gluing over the cracks so you don't have to 🩹

Functions

  • path_resolve(β†’ pathlib.Path) β€” Fix/Workaround for bug https://bugs.python.org/issue38671.
  • path_is_relative_to(β†’ bool) β€” Fix/Workaround for strange behavior in python 3.8.

Module Contents

doxysphinx.utils.pathlib_fix.path_resolve(path: pathlib.Path) -> pathlib.Path

Fix/Workaround for bug <https://bugs.python.org/issue38671>.

On Windows resolve will not return correct absolute paths for non-existing files (only for existing ones). This got fixed in python 3.10, however as we need to support older versions.... 😭

doxysphinx.utils.pathlib_fix.path_is_relative_to(path: pathlib.Path, base: pathlib.Path) -> bool

Fix/Workaround for strange behavior in python 3.8.

The issue is that Path.is_relative_to complains about PosixPath not having such an attribute in a foreign project. Rude of it, honestly πŸ’€


doxysphinx.utils.rst

The rst module contains rst specific helpers. RST girlies rise πŸŽ€

Functions

  • rst_safe_encode(β†’ str) β€” Encode text to be rst safe (special chars will get escaped correctly).

Module Contents

doxysphinx.utils.rst.rst_safe_encode(text: str) -> str

Encode text to be rst safe (special chars will get escaped correctly). No accidental formatting jumpscares 🫢

Parameters

  • text β€” the text to encode.

Returns

The rst safe encoded text


doxysphinx.writer

The writer module contains classes that write the docs-as-code output files. This is where the actual writing happens, main character energy only ✍️

Classes

  • Writer β€” Protocol representing a Writer that write docs-as-code files.
  • RstWriter β€” Writes sphinx-rst files to disk.

Module Contents

class doxysphinx.writer.Writer(source_directory: pathlib.Path, toc_generator_type: Type[doxysphinx.toc.TocGenerator <#doxysphinx.toc.TocGenerator>] = DoxygenTocGenerator)

Bases: Protocol

Protocol representing a Writer that write docs-as-code files.

write(parse_result: doxysphinx.html_parser.HtmlParseResult <#doxysphinx.html_parser.HtmlParseResult>, target_file: pathlib.Path, html_hash: str) -> pathlib.Path

Write a parsed html result to a target file. ✨

The format of that file is controlled by the concreate Writer implementation. (yes bestie, "concreate" β€” that's what it says, we don't fix the original's typos πŸ’–)

Parameters

  • parse_result β€” the result of a previous html parser run
  • target_file β€” the target file to write

Returns

The written file (should be always identical to target_file input, but allows chaining...)

okay so next in the API lineup we've got the writer that actually puts bytes on your disk, and then β€” big one β€” the whole how-to-contribute saga. Grab a snack. πŸ“

class doxysphinx.writer.RstWriter(source_directory: pathlib.Path,
toc_generator_type: Type[doxysphinx.toc.TocGenerator] = DoxygenTocGenerator)

Bestie. This class Writes sphinx-rst files to disk. That's the whole job description. It takes a source_directory (a pathlib.Path, naturally), and a toc_generator_type which is a Type[doxysphinx.toc.TocGenerator] and defaults to DoxygenTocGenerator. πŸ’…

write(parse_result: doxysphinx.html_parser.HtmlParseResult, target_file: pathlib.Path, html_hash: str) -> pathlib.Path

Write html content to the target_file. Slay.

Parameters

  • parse_result β€” The result of the html parsing (=content + metadata). Your parsed goodies, both the content and the metadata, wrapped up together. πŸŽ€
  • target_file β€” The target docs-as-code (e.g. rst) file. Like, the actual file that's getting written. πŸ¦‹

Returns

The path the file was written to. Because of course you get the path back, so you know exactly where the magic landed. ✨


🌈 HOW TO CONTRIBUTE 🌈

First of all, thanks for considering contributing to this project!! Your help is highly appreciated!! πŸ˜­πŸ’– No fr, they mean it.

πŸŽ€ TLDR πŸŽ€

So this document got quite long... here is the very short summary/checklist:

  • [ ] don't commit on main - use pull requests only
  • [ ] use this branch naming convention: feature/#39_bring_the_unicorns_back
  • [ ] commits must adhere to the conventional commits spec.
  • [ ] add copyright header to new file or add yourself as author in existing files.
  • [ ] sign your commits with a developer certificate of origin (dco) - (git commit -s -m "MESSAGE") or use vscode which is configured for the repo to do this automatically.
  • [ ] only once: add yourself as a contributor to NOTICE.md (https://github.com/boschglobal/doxysphinx/blob/main/NOTICE.md).

🚫 Pull requests only

Use pull requests to contribute to this repository.

Pushes to the main branch are automatically rejected. πŸ’€ Like, the door is literally bolted shut.

Keep your PRs focussed on a single purpose. For example, do not implement multiple features or fix multiple bugs in a single PR unless they are interconnected. Simply create separate PRs instead. One vibe per PR, periodt. πŸ’…

🌿 Branch naming convention

Branches should be named with this scheme:

group/short_description

The group denotes the purpose of the contribution:

  • feature: A new feature
  • fix: A bug fix
  • ci: GitHub workflow only changes
  • docs: Documentation only changes

The short description should describe the change/feature etc. If you have a bigger change please create an issue here in github and use the number as short description, e.g. feature/#39_bring_the_unicorns_back πŸ¦„

✨ Conventional Commits

We use Conventional Commits (https://www.conventionalcommits.org/en/v1.0.0/) to automatically calculate the semantic version, create the changelog, and publish the release via Python-Semantic-Release (https://python-semantic-release.readthedocs.io/en/latest/) tooling. So the robots do the boring bookkeeping and you just write nice messages. Iconic.

The following is a slightly adapted version (to doxysphinx) of the excellent Angular commit style (https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#commits).

🧾 Commit message format

Each commit message consists of a header, a body and a footer. The header has a special format that includes a type, a scope and a subject:

<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>

The header is mandatory and the scope of the header is optional.

Any line of the commit message should not be longer than 100 characters!. This allows the message to be easier to read on GitHub as well as in various git tools. Do not make me read a wall of text in git log, bestie, I'm begging. 😭

🏷️ Type

Must be one of the following:

  • feat: A new feature
  • fix: A bug fix
  • docs: Documentation only changes
  • style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
  • refactor: A code change that neither fixes a bug nor adds a feature
  • perf: A code change that improves performance
  • test: Adding missing or correcting existing tests
  • chore: Changes to the build process or auxiliary tools and libraries such as documentation generation

πŸ” Scope

The scope could be anything specifying place of the commit change. For example parser, writer, config, examples, cli etc...

You can use * when the change affects more than a single scope or just leave (<scope>) out completely. No cap, both are valid. 🫢

πŸ“ Subject

The subject contains succinct description of the change:

  • use the imperative, present tense: "change" not "changed" nor "changes"
  • don't capitalize first letter
  • no dot (.) at the end

πŸ«€ Body

Just as in the subject, use the imperative, present tense: "change" not "changed" nor "changes". The body should include the motivation for the change and contrast this with previous behavior. Tell us why, babe. πŸ’œ

The footer should contain any information about Breaking Changes and is also the place to reference GitHub issues that this commit closes (https://help.github.com/articles/closing-issues-via-commit-messages/).

Breaking Changes should start with the word BREAKING CHANGE: with a space or two newlines. The rest of the commit message is then used for this.

βͺ Reverting a commit

If the commit reverts a previous commit, it should begin with revert:, followed by the header of the reverted commit. In the body it should say: This reverts commit <hash>., where the hash is the SHA of the commit being reverted.

🌟 Examples

  • a very short new feature commit message:
feat: add button that brings the unicorns back
  • a multiple changes (just add a newline and repeat the pattern) + breaking change commit message:
feat(config): config file support

Now we established our own configuration file mechanism. The previous command line argument based
mechanism forced the users to always create a script, use makefiles etc. With the new mechanism only a
config file needs to be given. Config can be read from yml, toml and json files. As we're often dealing with
python projects there is also special support for pyproject.toml.

fixes #59

BREAKING CHANGE: cli arguments aren't supported anymore.

docs(config): document config mechanism

The new config mechanism is documentation in our sphinx documentation.

Include a copyright notice and license consistent with the style used by this project. If your contribution contains code under the copyright of a third party, document its origin, license, and copyright holders.

Typically for code this would be through a header. You can use this as a template: .copyright.tmpl

✍️ Sign your work

This project also tracks patch provenance and licensing using the Developer Certificate of Origin and Signed-off-by tags initially developed by the Linux kernel project.

Developer Certificate of Origin
Version 1.1

Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
1 Letterman Drive
Suite D4700
San Francisco, CA, 94129

Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.

Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
    have the right to submit it under the open source license
    indicated in the file; or

(b) The contribution is based upon previous work that, to the best
    of my knowledge, is covered under an appropriate open source
    license and I have the right under that license to submit that
    work with modifications, whether created in whole or in part
    by me, under the same open source license (unless I am
    permitted to submit under a different license), as indicated
    in the file; or

(c) The contribution was provided directly to me by some other
    person who certified (a), (b) or (c) and I have not modified
    it.

(d) I understand and agree that this project and the contribution
    are public and that a record of the contribution (including all
    personal information I submit with it, including my sign-off) is
    maintained indefinitely and may be redistributed consistent with
    this project or the open source license(s) involved.

With the sign-off in a commit message you certify that you authored the patch or otherwise have the right to submit it under an open source license. The procedure is simple: To certify above Developer's Certificate of Origin 1.1 for your contribution just append a line

Signed-off-by: Random J Developer <random@developer.example.org>

to every commit message using your real name or your pseudonym and a valid email address. 🫢

If you have set your user.name and user.email git configs you can automatically sign the commit by running the git-commit command with the -s option. There may be multiple sign-offs if more than one developer was involved in authoring the contribution.

🏒 Individual vs. Corporate Contributors

Often employers or academic institution have ownership over code that is written in certain circumstances, so please do due diligence to ensure that you have the right to submit the code. πŸ™ˆ Like, genuinely check, don't just vibe it.

If you are a developer who is authorized to contribute to Ontology Central on behalf of your employer, then please use your corporate email address in the Signed-off-by tag, otherwise use a personal email address.

Each contributor is responsible for identifying themselves in the NOTICE.md (https://github.com/boschglobal/doxysphinx/blob/main/NOTICE.md) file, the project's list of copyright holders and authors. Please add the respective information corresponding to the Signed-off-by tag as part of your first pull request.

If you are a developer who is authorized to contribute to Ontology Central on behalf of your employer, then add your company / organization to the list of copyright holders in the NOTICE.md (https://github.com/boschglobal/doxysphinx/blob/main/NOTICE.md) file. As author of a corporate contribution you can also add your name and corporate email address as in the Signed-off-by tag.

If your contribution is covered by this project's DCO's clause "(c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it", please add the appropriate copyright holder(s) to the NOTICE.md (https://github.com/boschglobal/doxysphinx/blob/main/NOTICE.md) file as part of your contribution. πŸŽ€

okay bestie, this next bit is completely optional β€” like, literally nobody is forcing you β€” but we strongly recommend installing doxylink (https://github.com/sphinx-contrib/doxylink) for linking from sphinx documentation directly to doxygen documented symbols like functions, classes etc. it's giving seamless cross-referencing, periodt. πŸ”₯

Setup ✨

Step one, install the pip package:

pip install sphinxcontrib-doxylink

Step two, activate the doxylink extension in your sphinx conf.py:

extensions = [
  # all the other extension
  "sphinxcontrib.doxylink",
]

slay. that's the whole activation, no cap. 🫢

Registration πŸ“

So here's the tea: doxylink "knows" the c++ symbols by reading tagfiles that are generated by doxygen (this is also the reason why tagfiles need to be enabled in doxygen config β€” see Step 2: Prepare Doxygen Config).

You now need to register your doxygen documentations with in your sphinx conf.py with doxylink with the doxylink variable:

doxygen_root = "docs/doxygen" # this is just a convenience variable
doxylink = {
    "demo": (  # "demo" is the role name that you can later use in sphinx to reference this doxygen documentation (see below)
        f"{doxygen_root}/demo/html/tagfile.xml", # the first parameter of this tuple is the tagfile
        f"{doxygen_root}/demo/html", # the second parameter of this tuple is a relative path pointing from
                                     # sphinx output directory to the doxygen output folder inside the output
                                     # directory tree.
                                     # Doxylink will use the tagfile to get the html file name of the symbol you want
                                     # to link and then prefix it with this path to generate html links (<a>-tags).
    ),
}

Register all your doxygen documentions via this mechanism. In your rst files you can then use e.g. (as documented here: https://sphinxcontrib-doxylink.readthedocs.io/en/stable/)

The class :demo:`doxysphinx::rst::Car` implements the car.

look at that little role name doing its main character thing. iconic. πŸ‘‘

Done πŸŽ‰

πŸŽ‰ Congratulations you've completed the doxylink setup.

Related topics:

  • To get to know the doxysphinx setup -> see our doxysphinx guide <>.

Welcome to the Doxysphinx documentation!


WHAT IS DOXYSPHINX? πŸ¦‹

...an integration tool 🧚

Doxysphinx is a doxygen (https://doxygen.nl) and sphinx (https://sphinx-doc.org) integration tool.

It will make the doxygen documentation appear inside the sphinx documentation: [image: doxysphinx result examples screenshot] [image]

It comes as an easy-to-use cli tool and typically runs right after doxygen created it's html documentation. Doxysphinx creates restructured text (.rst) files out of these (doxygen) html files. Afterwards sphinx will pick up these rst files and create an integrated documentation (sphinx theming is applied, search etc.). [image: doxysphinx integration process] [image]

like, it's literally the matchmaker between your two doc worlds and they're both thriving, fr fr. πŸ’œ

...a traceability enablement tool πŸ”—

Doxysphinx is also a traceability enablement tool because as doxygen documentation gets integrated with sphinx you can e.g. define and reference sphinx-needs (https://sphinxcontrib-needs.readthedocs.io/en/latest/) objects to link requirements, architecture elements, etc. directly in and to your source code.

With that it can be also seen as a little cog in the docs-as-code gear.

a little cog!! in the big docs-as-code gear!! she's small but she is essential, okay? 🫢


FEATURES πŸ’–

  • Reuses doxygens html output...
    • Graphics are working (hierarchies, etc.)
    • Doxygen's structure and views are preserved - namespaces, indexes, code views etc.
  • Integration in sphinx brings...
    • Sphinx Theming/Frame applied
    • Sphinx full text search over the doxygen documentation
  • Use sphinx enabled (directives, extensions, etc.) restructured text snippets in doxygen comments
    • This allows for example to define and reference sphinx need objects like requirements, components etc. down in the source code to get full tracability.

the way that last one gives you full tracability right down in the source code?? obsessed. 🌸


CAVEATS πŸ™ˆ

bestie listen β€” Furo is NOT happening and that's just the vibe check result, don't fight it. 😭 and if you want to embedd one single class or method inline instead of a whole page? that's a Breathe job, not a doxysphinx job. no cap.

πŸ‘‘ Author

  • Author name not set

aaaand that's a wrap on the whole DOXYSPHINX(1) page, bestie! πŸŽ€ this one shipped as version 3.3.12 and it's dated Jul 07, 2026 β€” so when you cite it, cite it right: DOXYSPHINX(1), 3.3.12, Jul 07, 2026. πŸ’– go forth and integrate those docs, you absolute legend. slay. βœ¨πŸ¦‹πŸ’…

πŸ“¦ where this page comes from