Je me suis amusé à écrire une mini librairie C++ pour l'algèbre linéaire (matrices et vecteurs, …) et j'ai eu envie de générer une documentation à partir du code source.
Je me suis renseigné un peu et j'ai découvert Doxygen, un outil écrit en C++ qui permet de générer de la documentation à partir des codes sources de différents langages (C++, Java, etc.).
Cela fonctionne bien, mais la sortie HTML n'est vraiment pas terrible. J'ai donc décidé, avec l'avis du forum Discord de l'association des Jeunes Bioinformaticiens de France (JeBif) de me pencher sur Sphinx, un générateur de documentation Python, qui produit des sites plus élégants.
Sphinx ne permet pas d'extraire la documentation des codes sources C++, mais génère du HTML à partir de fichiers au format ReStructuredText ou Markdown. Je continue ainsi d'utiliser Doxygen pour l'extraction des commentaires et des signatures des fonctions. Avec l'extension Breathe de Sphinx, on peut en effet extraire la documentation générée au format XML par Doxygen pour en faire un jolie petite documentation dans le style ReadTheDoc.
Prêt ? Alors c'est parti !
Comment configurer Doxygen ?
Commençons tout d'abord par installer Doxygen :
1 |
sudo apt-get install doxygen |
Nous allons nous baser pour notre exemple sur un projet fictif : une classe C++ représentant un chat.
1 2 |
[crayon-675c51d089ff3721045970 ]mkdir -p monprojet/include cd monprojet/include |
Créons maintenant un header C++, avec quelques blocs de commentaires :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
// monprojet/include/cat.hpp /** * @brief This is a cat */ class Cat { public : Cat() { say("I'm a cat"); } /** * @brief the cat is saying meow */ void meow() { say("meow"); } /** * @brief the cat is saying something * @param message the message to say */ void say(const std::string& message) { std::cout << message << std::endl ; } }; |
On peut maintenant générer le fichier de configuration de doxygen à la racine du projet :
1 |
[crayon-675c51d089ffb033903611 ]doxygen -g Doxyfile |
On peut changer quelques paramètres dans ce fichier, dont notamment INPUT, le dossier où se trouve les sources, et surtout GENERATE_XML pour obtenir les fichiers xml nécessaire à Sphinx.
1 2 3 4 5 6 7 8 9 |
[crayon-675c51d08a000420534562 ]INPUT = "./include" EXTRACT_ALL = YES RECURSIVE = YES OUTPUT_DIRECTORY = "./doc/" GENERATE_XML = YES |
On peut aussi désactiver les sorties HTML et LaTeX de doxygen, activées par défaut et qui ne nous sont pas utiles.
1 2 3 |
[crayon-675c51d08a005560904121 ]GENERATE_HTML = NO GENERATE_LATEX = NO |
Voilà, c'est fini pour la configuration du Doxyfile, maintenant, c'est au tour de Sphinx !
Comment configurer Sphinx ?
Pareillement, il faut installer Sphinx, par exemple avec le gestionnaire de paquet de votre distribution Linux (on pourrait aussi utiliser Pip):
1 |
[crayon-675c51d08a00a026841892 ]sudo apt-get install python-sphinx |
Dans le dossier du projet, on peut maintenant créer un dossier doc qui contient la configuration Sphinx et la documentation générée :
1 2 |
[crayon-675c51d08a00e221398146 ]mkdir doc cd doc |
Dès lors on peut utiliser sphinx-quickstart pour générer la structure de la documentation Sphinx :
1 |
[crayon-675c51d08a013100816482 ]sphinx-quickstart |
Il faut maintenant configurer Sphinx afin qu'il puisse importer le xml de doxygen.
En premier lieu, il faut installer Breathe, une extension qui permet justement d'importer la doc depuis les fichiers xml :
1 |
[crayon-675c51d08a018538467420 ]pip install breathe |
Dans le fichier conf.py , on doit ajouter ces quelques lignes :
1 2 3 4 |
[crayon-675c51d08a01d513121914 ]# in doc/source/conf.py extensions = ['breathe'] breathe_projects = {'monprojet': '../xml'} breathe_default_project = 'monprojet' |
Puis, dans index.rst, on demande à Sphinx de faire le rendu de la documentation :
1 2 3 |
[crayon-675c51d08a022608382308 ]// in doc/source/index.rst .. doxygenclass:: Cat :members : |
Si vous appréciez le thème de ReadTheDocs, vous pouvez l'installer :
1 |
[crayon-675c51d08a027942910740 ]pip install sphinx_rtd_theme |
et l'utiliser :
1 2 |
[crayon-675c51d08a02b154728008 ]# in doc/source/conf.py html_theme = 'sphinx_rtd_theme' |
Maintenant que tout est mis en place, il est temps de générer la documentation.
Générer la doc
Dans la racine du projet, on commence par lancer doxygen :
1 |
[crayon-675c51d08a031636068614 ]doxygen Doxyfile |
Puis on lance sphinx :
1 2 |
[crayon-675c51d08a037046393578 ]cd doc make html |
La documentation est ensuite disponible dans le dossierdoc/build/html.
Voici ce que j'obtiens :
Intégration et Déploiement continus avec GitLab CI/CD
Lancer ces deux petites commandes, c'est sympa mais, si c'est à faire à chaque nouvelle version du code source, cela peut vite devenir lourd …
C'est là qu'interviennent les pipelines CI/CD (Continuous Integration / Continuous Deployment) de GitLab : vous faites un push de vos modifications de codes sources et cela met à jour votre documentation en conséquence. Génial, non ?
Voici un exemple de .gitlab-ci.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
[crayon-675c51d08a03d231785016 ]image : python :3.10-alpine docs : script : - apk update & ;& ; apk add doxygen make - doxygen Doxyfile - pip install sphinx - pip install sphinx_rtd_theme - pip install breathe - cd docs & ;& ; make html artifacts : paths : - ./docs/build/html only : - main pages : stage : deploy script : - cp -r ./docs/build/html/* ./public/ artifacts : paths : - public |
Ainsi, la règle docs génère la documentation en utilisant la méthode présentée précédemment, et la règle pages déploie la documentation générée sur GitLab Pages (ici sur frama.io).
Bonus : Générer la documentation avec une règle Cmake
Dans le billet de blog Microsoft, la méthode présentée est intégrée au processus de build de Cmake pour le projet C++ concerné.
Voici donc une solution, si vous souhaitez que la gestion de la documentation se fasse avec le CMakeLists.txt.
Il faut commencer par créer un fichier CMakeLists.txt.
CMake est un système assez complet, et il faudrait une article dédié pour le présenter plus en détail (avis aux amateurs 😉 ), mais je vais reprendre ici un exemple simpliste de configuration, adapté à notre chère librairie féline…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
[crayon-675c51d08a042042472324 ]cmake_minimum_required(VERSION 3.14) project(autodoc) set(CMAKE_CXX_STANDARD 17) file(GLOB_RECURSE HEADERS "include/*.hpp") file(GLOB_RECURSE SOURCES "include/*.cpp") set(EXECUTABLE_NAME "autodoc") add_executable(${EXECUTABLE_NAME} ${HEADERS} ${SOURCES}) install(TARGETS ${EXECUTABLE_NAME} DESTINATION bin) # # DOCUMENTATION # # Auto documentation ## Doxygen find_program(DOXYGEN NAMES doxygen DOC "Path to doxygen executable" ) ## Sphinx find_program(SPHINX NAMES sphinx-build DOC "Path to sphinx-build executable" ) if(DOXYGEN AND SPHINX) add_custom_target( doc COMMAND ${DOXYGEN} ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile COMMAND cd docs & ;& ; make html WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "Generating API documentation with Doxygen" VERBATIM ) endif() |
La partie qui nous intéresse se situe après le "# DOCUMENTATION". On y retrouve les deux config pour les deux outils que l'on utilise. CMake commence par vérifier que les deux outils sont installés avec find_program puis on ajoute une règle "doc" au ficher Makefile généré plus tard par CMake avec "add_custom_target".
Pour compiler tout ce beau monde, dans un dossier "build":
1 2 3 4 5 |
[crayon-675c51d08a047793302910 ]mkdir build cd build cmake .. make # Compiler le binaire C++ si ça vous chante... make doc # Compiler la doc avec Doxygen + Sphinx |
Et voilà : vous trouverez la sortie html de Sphinx dans même dossier qu'auparavant, que vous pourrez visionner en local, ou téléverser sur le web.
Remerciements
Merci beaucoups aux relecteurs : Jonathan, Sebastien et Yoann.
Références
- Mon blog post d'origine : How to make automatic documentation using Doxygen, breathe and Sphinx
- Un dépôt test mettant cette technique en pratique : https://framagit.org/sortion/test-autodoc,
- Le GitLab Pages associé : https://unclesamulus.frama.io/test-autodoc/
- Clear, Functional C++ Documentation with Sphinx + Breathe + Doxygen + CMake : https://devblogs.microsoft.com/cppblog/clear-functional-c-documentation-with-sphinx-breathe-doxygen-cmake/
Laisser un commentaire