Doxygen is an industry-standard tool for generating standalone HTML documentation from in-code comments.
Although Doxygen is useful for its purpose, the default styling of its output is somewhat old-fashioned.
In this post, I'll briefly discuss two different ways of improving the styling of Doxygen docs: first, by modifying the generated HTML; and second, by generating your own HTML from Doxygen's XML output.
Doxygen's HTML output consists of a mix of HTML, CSS, and JS files. Something along these lines:
You can modify these output files in various ways to implement custom styling. For reference, the modifications I wrote for an early version of VCS's docs are available on GitHub (although they've since been deprecated in favor of generating custom HTML from Doxygen's XML).
You can achieve a fair bit just by adding custom CSS – either via the HTML_EXTRA_STYLESHEET option in Doxygen's config file or by modifying the generated files. For example, you can use pseudo-elements to insert Font Awesome icons:
@import url("https://use.fontawesome.com/releases/v5.12.0/css/all.css"); #main-menu li:first-child::before { font-family: "Font Awesome 5 Free"; content: "\f054"; font-weight: 900; }
Besides introducing custom CSS, you can modify the generated HTML files. The following sample Python code simplifies Doxygen's enumerator declarations from enum { enum::a, enum::b } to enum { a, b }:
from bs4 import BeautifulSoup # Read and parse Doxygen's generated HTML. htmlFile = open("./html/xxxx.html", "r+") dom = BeautifulSoup(htmlFile.read(), "html.parser") # Find all enumerator declarations. enumDeclNodes = dom.select("table.memberdecls tr[class^=memitem] > td.memItemRight > a") enumDeclNodes = list(filter(lambda x: x.string != None, enumDeclNodes)) # Modify the declarations' HTML. for node in enumDeclNodes: node.string = re.sub(r'.*?::', '', node.string) # Replace the original HTML file's data with the modified HTML. htmlFile.seek(0) htmlFile.write(str(dom)) htmlFile.truncate() htmlFile.close()
Modifying Doxygen's HTML output is fine for relatively limited stylistic tweaks, but it can get quite cumbersome if you're looking to make larger changes, e.g. to introduce mobile-friendlier layouts. For that, you should perhaps prefer to generate your own custom docs from Doxygen's XML output, as discussed in the next section.
Instead of just tweaking Doxygen's output, you can have Doxygen produce the documentation in an intermediate XML format, then parse the XML yourself and generate whatever final output you want.
To have Doxygen generate XML, set the GENERATE_XML option in Doxygen's config file to "YES". You'll then get output along these lines:
The index.xml file is in effect a table of contents, outlining all of the structures, classes, files, etc. that belong to the documentation. For example, the following snippet from the index file declares the contents of VCS's memory.h source file:
The refid values can be used to find the actual documentation from among the various output XML files. For instance, with the value "memory_8h_xxxx", we'd find the kmem_allocate() function in memory_8h.xml:
The following sample Python code snippet uses the ElementTree XML API to select all plain functions in memory_8h.xml, then inserts their data into a custom HTML string:
For more samples, you can explore VCS's Doxygen XML-to-HTML converter. It's currently not documented for developers unfortunately, but hopefully you'll find your way around it with a bit of effort. For example, the meat of the HTML generator is in RootDocument.py.
We've looked briefly at a few ways to improve Doxygen's default styling.
Modifying the auto-generated HTML/CSS can be a relatively easy way to customize the styling of your Doxygen docs. But larger-scale transformations may require a lot of effort to work around the limitations of Doxygen's way of doing things.
If you're rather looking to make larger-scale customizations, you should potentially bite the bullet and generate your own fully custom output based on Doxygen's XML.