📚 CMake Doxygen #
In this post we run through setting up a CMake Doxygen Site build. The Doxygen docs will automatically be created on each push to GitHub using a GitHub Action, with the site hosted on GitHub Pages. We use a C++ game dev project, though the examples here are useful more generally.
If that sounds what you came here for, then let’s get going!
🧱 What we’re Building #
I added Doxygen documentation to an Arkanoid clone game, which I built in C++. The example code comes from that project. The GitHub Action generates a documentation site, hosted for free on GitHub Pages on each push.
![CMake Doxygen Site: Screen capture shows documentation for a C++ class. The title reads Arkanoid, followed by the version number: 0.0.1. The menu has Main Page, Classes and Files links. Below the page subheading reads Brick Struct Reference and heads a section with a detailed description of the A P I.](https://rodneylab-nebula-a-1zqt.shuttle.app/v1/lab/post/cmake-doxygen-site/cmake-doxygen-site-class-docs.fb765c179fcd.png?w=592&h=333&fit=min&auto=format)
You have probably seen this kind of Doxygen documentation for C++ libraries you use. The styling is a little brutalist, but builds are robust and could serve for internal projects as well as more ambitious libraries.
⚙️ CMake Doxygen Config #
I created a docs
directory within the project root directory to contain
Doxygen config and docs CMakeLists.txt
file. So, to start, I needed
to add this to the main CMakeLists.txt
file:
1 cmake_minimum_required(VERSION 3.16)2 project(3 Arkanoid4 VERSION 0.0.15 DESCRIPTION "Arkanoid clone built in C++ with raylib and flecs."6 LANGUAGES CXX)78 # ...TRUNCATED910 option(CREATE_DOCUMENTATION "Create documentation" ON)11 if(CREATE_DOCUMENTATION)12 add_subdirectory(docs)13 endif()
We will get the project version from CMake later (for output in generated docs), so define it once
here, in line 4
as our source of truth.
Next we can add the main Doxygen CMake file in a new docs
folder (file
path: docs/CMakeLists.txt
):
1 # check if Doxygen is installed2 find_package(Doxygen)3 if(DOXYGEN_FOUND)4 set(DOXYGEN_IN ${CMAKE_CURRENT_SOURCE_DIR}/../docs/Doxyfile.in)5 set(DOXYGEN_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)67 configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT} @ONLY)8 message("Doxygen build started")910 # note the option ALL which enables building the docs together with the application11 add_custom_target(12 doc_doxygen ALL13 COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT}14 WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}15 COMMENT "Generating API documentation with Doxygen"16 VERBATIM)17 else(DOXYGEN_FOUND)18 message(19 "Doxygen needs to be installed to generate the doxygen documentation")20 endif(DOXYGEN_FOUND)
We set the Doxygen config file path here, in line 4
to docs/Doxyfile.in
. We can create a template for that file in the Terminal:
doxygen -g docs/Doxyfile.in
You should now have a docs/Doxyfile.in
file, which you can customize
for CMake. You can download the latest version of Doxygen from the official site , or install it with system package manager (if you don’t already have it installed).
Next scan through the generated file, and update it using CMake variables:
# ...TRUNCATEDPROJECT_NAME = "Your project name"# ...PROJECT_NUMBER = @PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@# ...OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@/doc_doxygen/# ...INPUT = @CMAKE_CURRENT_SOURCE_DIR@/../src @CMAKE_CURRENT_SOURCE_DIR@/../docs# TRUNCATED...
These placeholders will get updated by CMake when it builds the docs.
That’s all the config done. Next, you will want to add some Doxygen markup to your C++ source files.
🖥️ Adding Doxygen Markup to C++ Source #
If you are new to Doxygen, or a little rusty, for a basic Doxygen cheat sheet see, try the RIP Tutorial page . Also keep the official Doxygen docs open , in case you need more detail on some feature.
For inspiration, here is some Doxygen markup I added to the src/components.h
file of my project:
src/components.h
— click to expand code.
#ifndef SRC_COMPONENTS_H#define SRC_COMPONENTS_H/*! \file src/components.h* \brief Declarations for ECS component classes and structs*/// TRUNCATED.../*** \brief One-sided collider suitable for walls and platforms*/struct AxisAlignedOneWayCollider{AxisAlignedOneWayCollider(): collision_side(CollisionSide::BOTTOM), displacement(0.F){}/*** \brief Constructor initialising collider with displacement and collision side values** \param[in] displacement_value displacement of active collision side from left of window, for left and right colliders, displacement from top of window for top and bottom colliders.* \param[in] collision_side_value either top, right, bottom or left depending on active collision side. For example,* LEFT indicates collider will only register collisions from an object moving right, hitting the left side*/AxisAlignedOneWayCollider(const float displacement_value,const CollisionSide collision_side_value): collision_side(collision_side_value), displacement(displacement_value){}// e.g LEFT indicates collider will only register collisions from an object moving right, hitting the left sideCollisionSide collision_side;// for left or right collider, displacement of colliding side in pixels from left of window, for top or bottom collider, displacement of colliding side from top of screenfloat displacement;};// TRUNCATED...#endif
You should be able to build your project with CMake now, and have docs generated in your build
folder. I ran build from a .build
directory, and have an HTML file
(.build/docs/doc_doxygen/html/index.html
), which I can open in a
browser to see the created docs.
![CMake Doxygen Site: Screen capture shows a documentation site skeleton home page. The title reads Arkanoid, followed by the version number: 0.0.1. The menu has Main Page, Classes and Files links. Below the page subheading reads Arkanoid Documentation.](https://rodneylab-nebula-a-1zqt.shuttle.app/v1/lab/post/cmake-doxygen-site/cmake-doxygen-site-docs-home.ed0a9d1f07e9.png?w=592&h=329&fit=min&auto=format)
🎬 Adding the GitHub Action #
GitHub looks for Actions in a .github/workflows directory. Each action has a YAML file. I based this on franneck94’s GitHub Documentation Action from the CppProjectTemplate repo.
1 name: Documentation2 on:3 push:4 tags:5 - "*"6 branches: [main]7 permissions:8 contents: read9 jobs:10 build:11 name: Build and publish documentation12 permissions:13 contents: write14 pages: write15 runs-on: ubuntu-latest16 steps:17 - name: Harden Runner18 uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.119 with:20 egress-policy: audit21 disable-telemetry: true22 - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.723 - name: Install Linux Dependencies24 if: runner.os == 'Linux'25 run: sudo apt-get update && sudo apt-get install libxrandr-dev libxcursor-dev libudev-dev libopenal-dev libflac-dev libvorbis-dev libgl1-mesa-dev libegl1-mesa-dev freeglut3-dev libxinerama-dev libxi-dev26 - name: Setup Cpp27 uses: aminya/setup-cpp@bfbfe9ca0b2c69a076f6513393d61fc478fb54f8 # v0.41.028 with:29 clangtidy: true30 - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.031 - name: Install Docs32 run: |33 sudo apt-get install doxygen34 pip install -r requirements.txt --require-hashes35 - name: configure36 run: |37 cmake -H. -Bbuild -G "Unix Makefiles" -DCMAKE_BUILD_TYPE="Debug"38 - name: building39 run: |40 cmake --build build --config Debug --target doc_doxygen -j441 - name: Deploy to GitHub Pages42 uses: Cecilapp/GitHub-Pages-deploy@526a34f794dfdf7edd6a4ac94321b1e7945910c0 # v343 env:44 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}45 with:46 build_dir: ./build/docs/doc_doxygen/html
The Action needs write permissions, to output the generated HTML documentation needed for the site. You will need to tweak the Linux Dependencies based on your project.
I use hashes for GitHub Actions, for added security, and similarly for the necessary Python
dependencies, adding the Python ones to a requirements.txt
file in
the project root directory:
colorlog==6.8.2 \--hash=sha256:4dcbb62368e2800cb3c5abd348da7e53f6c362dda502ec27c560b2e58a66bd33gcovr==7.2 \--hash=sha256:e3e95cb56ca88dbbe741cb5d69aa2be494eb2fc2a09ee4f651644a670ee5aeb3 \--hash=sha256:fd5cc432c9df863983c530dbd5077937c730b6589117916c188577681469b395jinja2==3.1.4 \--hash=sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369 \--hash=sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197dlxml==5.3.0 \--hash=sha256:01220dca0d066d1349bd6a1726856a78f7929f3878f7e2ee83c296c69495309e \# TRUNCATED...--hash=sha256:fb66442c2546446944437df74379e9cf9e9db353e61301d1a0e26482f43f0dd8Pygments==2.18.0 \--hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \--hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a
See pip docs on secure installations for more on generating pip hashes and Hash-checking mode .
GitHub Pages Repo Config #
The Action will output the generated site to a gh-pages
branch after
each push is merged. You can set GitHub to publish the content from that branch to the repo’s
associated GitHub Pages page. The repo will need to be public if you do not have paid GitHub account.
Navigate to the repo in the GitHub web console and select Settings from the top menu
bar, then Pages from the left (side) menu. Keep Source set to Deploy from a branch
, then under Branch, select gh-pages
from the dropdown and hit Save.
![CMake Doxygen Site: Screen capture shows a documentation site skeleton home page. The title reads Arkanoid, followed by the version number: 0.0.1. The menu has Main Page, Classes and Files links. Below the page subheading reads Arkanoid Documentation.](https://rodneylab-nebula-a-1zqt.shuttle.app/v1/lab/post/cmake-doxygen-site/cmake-doxygen-site-github-pages-config.3b5487ffe3bd.png?w=592&h=329&fit=min&auto=format)
Now try pushing some changes and merging them. The page may well take a few minutes to build after commit. If all goes well, and you return to this config tab, you should see a status message confirming the page built and its URL.
🗳 Poll #
🙌🏽 CMake Doxygen Site: Wrapping Up #
In this CMake Doxygen Site post, we saw how you might add automatic documentation generation in a C++ game. More specifically, we saw:
- how to set up Doxygen builds to run with CMake;
- adding a Doxygen site generation GitHub Action; and
- automatically building a docs sites with GitHub Pages on each branch merge.
I hope you found this useful. As promised, you can get the full project code on the Rodney Lab GitHub repo . Do let me know if you found this content useful and would like to see more similar content. Also reach out if there is anything I could improve to provide a better experience for you.
🙏🏽 CMake Doxygen Site: Feedback #
If you have found this post useful, see links below for further related content on this site. Let me know if there are any ways I can improve on it. I hope you will use the code or starter in your own projects. Be sure to share your work on X, giving me a mention, so I can see what you did. Finally, be sure to let me know ideas for other short videos you would like to see. Read on to find ways to get in touch, further below. If you have found this post useful, even though you can only afford even a tiny contribution, please consider supporting me through Buy me a Coffee.
Finally, feel free to share the post on your social media accounts for all your followers who will find it useful. As well as leaving a comment below, you can get in touch via @askRodney on X (previously Twitter) and also, join the #rodney Element Matrix room. Also, see further ways to get in touch with Rodney Lab. I post regularly on Game Dev as well as Rust and C++ (among other topics). Also, subscribe to the newsletter to keep up-to-date with our latest projects.