Skip to content

Latest commit

 

History

History
680 lines (495 loc) · 23.1 KB

File metadata and controls

680 lines (495 loc) · 23.1 KB

🔝 Retour au Sommaire

46.4.2 — Génération de documentation

Chapitre 46 : Organisation et Standards · Section 46.4 : Documentation — Doxygen et commentaires
Niveau : Expert · Prérequis : Section 46.4.1 (syntaxe Doxygen), chapitre 26 (CMake), chapitre 38 (CI/CD)


Installation de Doxygen sur Ubuntu

Doxygen est disponible dans les dépôts officiels d'Ubuntu. L'installation inclut Doxygen lui-même et Graphviz, utilisé pour générer les diagrammes de classes et les graphes de dépendances :

sudo apt update  
sudo apt install doxygen graphviz  

Vérification de l'installation :

doxygen --version  
dot -V     # Graphviz  

Pour obtenir une version plus récente que celle des dépôts (utile pour le support des fonctionnalités C++ les plus récentes), Doxygen peut être compilé depuis les sources ou installé via snap :

sudo snap install doxygen

Le Doxyfile : configuration centrale

Le Doxyfile est le fichier de configuration de Doxygen. Il contient plusieurs centaines d'options, mais une vingtaine suffisent pour un projet typique. Le reste conserve ses valeurs par défaut.

Génération d'un Doxyfile initial

Doxygen génère un fichier de configuration commenté avec toutes les options :

cd docs/  
doxygen -g Doxyfile  

Le fichier produit fait environ 2500 lignes avec les commentaires. En production, on ne conserve que les options modifiées par rapport aux valeurs par défaut, ce qui réduit le fichier à quelques dizaines de lignes lisibles.

Configuration recommandée

Voici un Doxyfile complet pour un projet professionnel, avec chaque option commentée :

# -----------------------------------------------------------------
# Projet
# -----------------------------------------------------------------
PROJECT_NAME           = "MonProjet"  
PROJECT_NUMBER         = 1.2.0  
PROJECT_BRIEF          = "Framework de traitement de données en temps réel"  
PROJECT_LOGO           = docs/logo.png  

# -----------------------------------------------------------------
# Entrées
# -----------------------------------------------------------------
# Répertoires à scanner pour le code source et la documentation.
INPUT                  = include/ \
                         src/ \
                         docs/

# Scan récursif des sous-répertoires.
RECURSIVE              = YES

# Patterns de fichiers à traiter.
FILE_PATTERNS          = *.h *.hpp *.cpp *.md

# Fichiers et répertoires à exclure.
EXCLUDE                = build/ \
                         third_party/

# -----------------------------------------------------------------
# Extraction
# -----------------------------------------------------------------
# Extraire la documentation de tous les membres, même non documentés.
# Utile en développement pour voir les trous dans la documentation.
# À désactiver pour la documentation publique (ne montrer que ce
# qui est explicitement documenté).
EXTRACT_ALL            = NO

# Extraire les membres privés (désactivé pour l'API publique).
EXTRACT_PRIVATE        = NO

# Extraire les membres statiques.
EXTRACT_STATIC         = YES

# -----------------------------------------------------------------
# Comportement des commentaires
# -----------------------------------------------------------------
# La première phrase d'un commentaire sert automatiquement de brief.
JAVADOC_AUTOBRIEF      = YES

# Trier les membres par ordre alphabétique dans la documentation.
SORT_MEMBER_DOCS       = YES

# -----------------------------------------------------------------
# Sortie
# -----------------------------------------------------------------
# Répertoire de sortie pour la documentation générée.
OUTPUT_DIRECTORY       = build/docs

# Générer la sortie HTML (documentation navigable).
GENERATE_HTML          = YES  
HTML_OUTPUT            = html  

# Ne pas générer de LaTeX par défaut (activer pour le PDF).
GENERATE_LATEX         = NO

# Générer la sortie XML (consommée par Breathe/Sphinx si utilisé).
GENERATE_XML           = NO

# -----------------------------------------------------------------
# Apparence HTML
# -----------------------------------------------------------------
# Activer la recherche côté client (JavaScript).
SEARCHENGINE           = YES

# Activer la navigation arborescente dans le panneau latéral.
GENERATE_TREEVIEW      = YES

# Désactiver le timestamp dans le footer (reproductibilité des builds).
HTML_TIMESTAMP         = NO

# Feuille de style personnalisée (optionnel).
# HTML_EXTRA_STYLESHEET  = docs/custom.css

# -----------------------------------------------------------------
# Diagrammes (Graphviz)
# -----------------------------------------------------------------
# Activer les diagrammes générés par dot (Graphviz).
HAVE_DOT               = YES

# Diagrammes de classes avec héritage.
CLASS_DIAGRAMS         = YES  
CLASS_GRAPH            = YES  

# Graphes de collaboration (quelles classes utilisent quelles autres).
COLLABORATION_GRAPH    = YES

# Graphes d'inclusion de headers.
INCLUDE_GRAPH          = YES  
INCLUDED_BY_GRAPH      = YES  

# Graphes d'appels de fonctions (coûteux sur de gros projets).
CALL_GRAPH             = NO  
CALLER_GRAPH           = NO  

# Format de sortie des graphes.
DOT_IMAGE_FORMAT       = svg  
INTERACTIVE_SVG        = YES  

# Limiter la profondeur des graphes pour éviter l'explosion.
MAX_DOT_GRAPH_DEPTH    = 3

# -----------------------------------------------------------------
# Warnings
# -----------------------------------------------------------------
# Afficher les warnings pour les paramètres non documentés.
WARN_IF_UNDOCUMENTED   = YES

# Afficher les warnings pour les commandes Doxygen mal formées.
WARN_IF_DOC_ERROR      = YES

# Traiter les warnings comme des erreurs (utile en CI).
# WARN_AS_ERROR          = FAIL_ON_WARNINGS

# Fichier de log pour les warnings.
WARN_LOGFILE           = build/docs/doxygen_warnings.log

# -----------------------------------------------------------------
# Préprocesseur
# -----------------------------------------------------------------
# Activer le préprocesseur (nécessaire pour les macros).
ENABLE_PREPROCESSING   = YES  
MACRO_EXPANSION        = YES  

# Macros à prédéfinir pour la documentation.
# Utile pour documenter du code derrière des macros de plateforme.
PREDEFINED             = __linux__ \
                         MONPROJET_EXPORT=

Les options les plus impactantes

Parmi les centaines d'options, quelques-unes méritent une attention particulière car elles changent fondamentalement le résultat produit.

EXTRACT_ALL : quand cette option est à YES, Doxygen documente tous les symboles publics, même ceux sans commentaire Doxygen. C'est utile en phase de développement pour visualiser l'ensemble de l'API et identifier les trous de documentation. Pour la documentation publique d'une bibliothèque, NO est préférable : seuls les symboles explicitement documentés apparaissent, ce qui évite de publier une référence incomplète.

JAVADOC_AUTOBRIEF : à YES, la première phrase de chaque commentaire (jusqu'au premier point) est automatiquement utilisée comme brief. Cela rend l'écriture de commentaires plus naturelle en évitant le @brief explicite sur chaque élément.

WARN_AS_ERROR : la valeur FAIL_ON_WARNINGS fait échouer Doxygen dès qu'un warning est détecté (paramètre non documenté, lien cassé, commande invalide). C'est l'option clé pour l'intégration CI — elle transforme la documentation en un test qui échoue quand la qualité se dégrade.

HAVE_DOT : active la génération de diagrammes via Graphviz. Sans cette option, Doxygen ne produit que des diagrammes textuels basiques. Avec Graphviz, les diagrammes de classes, les graphes d'inclusion et les graphes de collaboration deviennent des SVG interactifs navigables.


Exécution manuelle

La génération de documentation s'exécute en une commande :

doxygen docs/Doxyfile

Doxygen affiche sa progression et les éventuels warnings sur la sortie standard. La documentation HTML est générée dans le répertoire spécifié par OUTPUT_DIRECTORY/HTML_OUTPUT — dans notre configuration, build/docs/html/.

Pour visualiser le résultat localement :

# Ouvrir dans le navigateur par défaut
xdg-open build/docs/html/index.html

# Ou servir via un serveur HTTP local
python3 -m http.server 8000 -d build/docs/html

Intégration CMake

L'intégration de Doxygen dans CMake permet de générer la documentation via le build system standard du projet, avec une cible dédiée docs.

Configuration minimale

# docs/CMakeLists.txt

find_package(Doxygen REQUIRED)

if(DOXYGEN_FOUND)
    set(DOXYGEN_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile)

    add_custom_target(docs
        COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_IN}
        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
        COMMENT "Génération de la documentation Doxygen..."
        VERBATIM
    )
endif()

La documentation est ensuite générée via :

cmake --build build --target docs

Configuration avancée avec doxygen_add_docs()

CMake fournit un module FindDoxygen avec une fonction dédiée, doxygen_add_docs(), qui simplifie l'intégration et permet de surcharger les options du Doxyfile directement depuis CMake :

# docs/CMakeLists.txt

find_package(Doxygen REQUIRED
    OPTIONAL_COMPONENTS dot)  # Graphviz optionnel

if(DOXYGEN_FOUND)
    # Surcharge d'options Doxygen depuis CMake.
    # Chaque variable DOXYGEN_XXX correspond à l'option XXX du Doxyfile.
    set(DOXYGEN_PROJECT_NAME "${PROJECT_NAME}")
    set(DOXYGEN_PROJECT_NUMBER "${PROJECT_VERSION}")
    set(DOXYGEN_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/doxygen")
    set(DOXYGEN_GENERATE_HTML YES)
    set(DOXYGEN_GENERATE_LATEX NO)
    set(DOXYGEN_GENERATE_TREEVIEW YES)
    set(DOXYGEN_JAVADOC_AUTOBRIEF YES)
    set(DOXYGEN_EXTRACT_ALL NO)
    set(DOXYGEN_WARN_IF_UNDOCUMENTED YES)
    set(DOXYGEN_RECURSIVE YES)

    # Graphviz
    if(DOXYGEN_DOT_FOUND)
        set(DOXYGEN_HAVE_DOT YES)
        set(DOXYGEN_DOT_IMAGE_FORMAT svg)
        set(DOXYGEN_INTERACTIVE_SVG YES)
        set(DOXYGEN_CLASS_GRAPH YES)
        set(DOXYGEN_COLLABORATION_GRAPH YES)
        set(DOXYGEN_INCLUDE_GRAPH YES)
    endif()

    # Exclusions
    set(DOXYGEN_EXCLUDE_PATTERNS
        "*/build/*"
        "*/third_party/*"
    )

    # Création de la cible.
    # Les arguments sont les répertoires et fichiers à scanner.
    doxygen_add_docs(docs
        ${CMAKE_SOURCE_DIR}/include
        ${CMAKE_SOURCE_DIR}/src
        ${CMAKE_SOURCE_DIR}/docs
        COMMENT "Génération de la documentation Doxygen..."
    )
endif()

L'avantage de cette approche : les valeurs dynamiques du projet (nom, version, chemins) sont injectées automatiquement depuis CMake, sans dupliquer l'information dans le Doxyfile. Un Doxyfile séparé reste nécessaire uniquement si vous avez besoin d'options que doxygen_add_docs() ne couvre pas — dans ce cas, le fichier est passé en option et les variables CMake le complètent.

Injection de la version du projet

Pour que la documentation affiche toujours la version courante sans modification manuelle :

# Si vous utilisez un Doxyfile, générez-le avec configure_file
configure_file(
    ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in
    ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
    @ONLY
)

Le fichier Doxyfile.in utilise des substitutions CMake :

# docs/Doxyfile.in
PROJECT_NAME    = "@PROJECT_NAME@"  
PROJECT_NUMBER  = "@PROJECT_VERSION@"  
INPUT           = @CMAKE_SOURCE_DIR@/include \  
                  @CMAKE_SOURCE_DIR@/src \
                  @CMAKE_SOURCE_DIR@/docs
OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@/doxygen

Chaque @VARIABLE@ est remplacé par la valeur correspondante de CMake au moment de la configuration. Le Doxyfile généré dans le répertoire de build contient les chemins absolus corrects.


Intégration CI/CD

La documentation doit être générée et vérifiée automatiquement à chaque commit. Deux jobs CI distincts couvrent deux objectifs différents : la vérification de qualité et le déploiement.

Job de vérification : warnings comme erreurs

Ce job s'exécute sur chaque merge request. Il vérifie que la documentation est complète et syntaxiquement correcte :

# .gitlab-ci.yml (extrait)
docs-check:
  stage: test
  image: ubuntu:24.04
  before_script:
    - apt-get update && apt-get install -y doxygen graphviz cmake ninja-build g++
  script:
    - cmake -B build -G Ninja -DBUILD_DOCS=ON
    - cmake --build build --target docs
    # Vérifier qu'aucun warning n'a été émis
    - |
      if [ -s build/docs/doxygen_warnings.log ]; then
        echo "⚠️  Warnings Doxygen détectés :"
        cat build/docs/doxygen_warnings.log
        exit 1
      fi
  artifacts:
    when: on_failure
    paths:
      - build/docs/doxygen_warnings.log
    expire_in: 7 days

L'alternative, plus directe, est d'utiliser WARN_AS_ERROR = FAIL_ON_WARNINGS dans le Doxyfile. Doxygen retournera alors un code d'erreur non nul dès qu'un warning est émis, faisant échouer le job CI sans script de vérification supplémentaire.

Équivalent GitHub Actions

# .github/workflows/docs.yml
name: Documentation

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  docs-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install dependencies
        run: sudo apt-get update && sudo apt-get install -y doxygen graphviz

      - name: Configure
        run: cmake -B build -DBUILD_DOCS=ON

      - name: Generate documentation
        run: cmake --build build --target docs

      - name: Check for warnings
        run: |
          if [ -s build/docs/doxygen_warnings.log ]; then
            echo "::error::Doxygen warnings detected"
            cat build/docs/doxygen_warnings.log
            exit 1
          fi

      # Déploiement sur GitHub Pages (uniquement sur main)
      - name: Deploy to GitHub Pages
        if: github.ref == 'refs/heads/main' && github.event_name == 'push'
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./build/docs/doxygen/html

Ce workflow combine vérification (sur chaque PR) et déploiement (sur main uniquement). La documentation est toujours accessible à jour sur GitHub Pages après chaque merge.

Déploiement sur GitLab Pages

GitLab Pages utilise une convention : tout ce qui est dans le répertoire public/ de l'artefact du job pages est servi en tant que site statique.

# .gitlab-ci.yml (extrait)
pages:
  stage: deploy
  image: ubuntu:24.04
  before_script:
    - apt-get update && apt-get install -y doxygen graphviz cmake ninja-build g++
  script:
    - cmake -B build -G Ninja -DBUILD_DOCS=ON
    - cmake --build build --target docs
    - mv build/docs/doxygen/html public
  artifacts:
    paths:
      - public
  only:
    - main

Après exécution, la documentation est accessible à l'URL https://<group>.gitlab.io/<project>/.


Personnalisation du thème HTML

Le thème par défaut de Doxygen est fonctionnel mais daté. Plusieurs options permettent de moderniser l'apparence.

Feuille de style personnalisée

La méthode la plus simple consiste à ajouter une feuille CSS qui surcharge le thème par défaut :

# Doxyfile
HTML_EXTRA_STYLESHEET = docs/custom.css
/* docs/custom.css */

/* Typographie modernisée */
body, td, th {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI",
                 Roboto, Helvetica, Arial, sans-serif;
    font-size: 15px;
    line-height: 1.6;
}

/* Blocs de code */
pre.fragment, div.fragment {
    font-family: "JetBrains Mono", "Fira Code", "Consolas", monospace;
    font-size: 13px;
    border-radius: 6px;
    border: 1px solid #e0e0e0;
    background-color: #f8f9fa;
    padding: 12px 16px;
}

/* Navigation latérale */
#side-nav {
    background-color: #f5f5f5;
}

/* Liens */
a {
    color: #0366d6;
    text-decoration: none;
}

a:hover {
    text-decoration: underline;
}

Doxygen Awesome : thème moderne clé en main

Le projet open source Doxygen Awesome (doxygen-awesome-css) fournit un thème moderne complet, avec mode sombre, navigation améliorée et design responsive. Son intégration est simple :

# Ajout comme sous-module Git
git submodule add https://github.com/jothepro/doxygen-awesome-css.git \
    docs/doxygen-awesome-css
# Doxyfile
HTML_EXTRA_STYLESHEET = docs/doxygen-awesome-css/doxygen-awesome.css \
                        docs/doxygen-awesome-css/doxygen-awesome-sidebar-only.css

# Options recommandées par le thème
GENERATE_TREEVIEW      = YES  
DISABLE_INDEX          = NO  
FULL_SIDEBAR           = NO  
HTML_COLORSTYLE        = LIGHT  

Le résultat est une documentation visuellement comparable aux sites de documentation modernes (à la Read the Docs ou Docusaurus), sans quitter l'écosystème Doxygen.

En-tête et pied de page personnalisés

Doxygen permet de surcharger le HTML d'en-tête et de pied de page pour ajouter un logo, des liens de navigation, ou un analytics tracker :

# Générer les templates par défaut
doxygen -w html header.html footer.html stylesheet.css Doxyfile

Cela produit trois fichiers dans le répertoire courant. Vous pouvez ensuite les modifier et les référencer dans le Doxyfile :

HTML_HEADER  = docs/header.html  
HTML_FOOTER  = docs/footer.html  

Génération PDF via LaTeX

Pour produire une documentation PDF (souvent requise dans les contextes réglementaires : automobile, aéronautique, défense), Doxygen peut générer du LaTeX compilable en PDF :

# Doxyfile
GENERATE_LATEX = YES  
LATEX_OUTPUT   = latex  
USE_PDFLATEX   = YES  
PDF_HYPERLINKS = YES  

La compilation LaTeX nécessite une installation TeX :

sudo apt install texlive-latex-base texlive-latex-extra \
                 texlive-fonts-recommended latexmk

Après la génération Doxygen, le PDF est produit par :

cd build/docs/latex  
make       # Appelle pdflatex automatiquement  

Le fichier refman.pdf est le document de référence complet. Pour les gros projets, la compilation LaTeX peut prendre plusieurs minutes — c'est typiquement un job CI nocturne plutôt qu'un build à chaque commit.


Pipeline Sphinx + Breathe (alternative avancée)

Pour les projets qui ont besoin d'une documentation narrative riche (tutoriels, guides, architecture) mêlée à la référence d'API, la combinaison Sphinx + Breathe offre le meilleur des deux mondes : Doxygen extrait la documentation du code C++, Breathe la rend accessible à Sphinx, et Sphinx produit un site navigable avec un thème moderne.

Principe du pipeline

Code C++  ──Doxygen──►  XML  ──Breathe──►  Sphinx  ──►  HTML/PDF
                                               ▲
                                    Fichiers .rst/.md
                                    (documentation narrative)

Installation

pip install sphinx breathe sphinx-rtd-theme

Configuration Sphinx (docs/conf.py)

# docs/conf.py

project = 'MonProjet'  
version = '1.2.0'  

extensions = [
    'breathe',
    'sphinx.ext.autodoc',
]

# Configuration Breathe
breathe_projects = {
    "MonProjet": "../build/docs/doxygen/xml"
}
breathe_default_project = "MonProjet"

# Thème
html_theme = 'sphinx_rtd_theme'

Configuration Doxygen pour Sphinx

Le Doxyfile doit activer la sortie XML, consommée par Breathe :

GENERATE_XML  = YES  
XML_OUTPUT    = xml  
GENERATE_HTML = NO    # Sphinx génère le HTML à la place  

Utilisation dans les fichiers reStructuredText

API Reference
=============

Engine
------

.. doxygenclass:: monprojet::core::Engine
   :members:
   :undoc-members:

ConnectionPool
--------------

.. doxygenclass:: monprojet::network::ConnectionPool
   :members:

Sphinx génère une page qui inclut la documentation Doxygen extraite des commentaires C++, intégrée dans le design et la navigation du site Sphinx.

Quand choisir Sphinx + Breathe ?

Cette combinaison est justifiée quand le projet a une documentation narrative conséquente (guides, tutoriels, changelogs, migration guides) qui coexiste avec la référence d'API. Pour un projet dont la documentation se résume à la référence d'API, Doxygen seul avec un thème comme Doxygen Awesome est plus simple et suffisant.


Diagnostiquer les problèmes courants

Symboles non documentés dans la sortie

Si des classes ou fonctions que vous avez documentées n'apparaissent pas dans la documentation générée, les causes les plus fréquentes sont :

  • Le répertoire contenant les fichiers n'est pas listé dans INPUT.
  • Le pattern du fichier n'est pas dans FILE_PATTERNS (par exemple, .hpp manquant).
  • EXTRACT_ALL = NO et le commentaire Doxygen est syntaxiquement invalide (le /** ou /// est absent ou malformé).
  • Le fichier est dans un répertoire listé dans EXCLUDE ou EXCLUDE_PATTERNS.

La commande doxygen -d Preprocessor active le mode debug du préprocesseur, utile pour diagnostiquer les problèmes liés aux macros et aux #ifdef.

Diagrammes manquants

Si les diagrammes de classes ne sont pas générés, vérifiez que HAVE_DOT = YES et que dot (Graphviz) est installé et dans le PATH. Doxygen ne signale pas toujours clairement l'absence de Graphviz — les diagrammes sont silencieusement omis.

Liens croisés cassés

Les commandes @ref et @see qui pointent vers un symbole inexistant génèrent un warning. Avec WARN_AS_ERROR = FAIL_ON_WARNINGS, ces liens cassés font échouer le build. C'est le comportement souhaité : un lien cassé dans la documentation est un bug, au même titre qu'un test en échec.

Warnings trop nombreux au démarrage

Sur un projet existant qui n'a jamais été documenté avec Doxygen, activer WARN_IF_UNDOCUMENTED peut produire des milliers de warnings. La stratégie recommandée est d'y aller progressivement : commencez avec EXTRACT_ALL = NO et WARN_IF_UNDOCUMENTED = NO, documentez l'API publique module par module, puis activez les warnings et WARN_AS_ERROR une fois que le backlog est résorbé.


Résumé

La génération de documentation avec Doxygen s'organise en trois couches. La première est la configuration via le Doxyfile, où les options clés sont EXTRACT_ALL, JAVADOC_AUTOBRIEF, WARN_AS_ERROR, et l'activation de Graphviz pour les diagrammes. La deuxième est l'intégration CMake, soit avec un add_custom_target simple, soit avec doxygen_add_docs() qui synchronise automatiquement les métadonnées du projet. La troisième est le déploiement CI/CD : un job de vérification sur chaque merge request (warnings comme erreurs) et un job de déploiement sur la branche principale (GitHub Pages, GitLab Pages). Le thème par défaut peut être modernisé via une feuille CSS personnalisée ou le thème Doxygen Awesome. Pour les projets à forte composante narrative, Sphinx + Breathe offre un pipeline complet qui combine référence d'API extraite du code et documentation éditoriale.


⏭️ Standards de codage