Doxygen собирает документацию API прямо из комментариев в исходниках и генерирует HTML, LaTeX, XML или man-страницы. Он поддерживает C, C++, C#, Objective-C, Fortran, Java, Python и другие языки, поэтому остаётся стандартом для проектов на C и C++. Ниже — настройка Doxyfile, разметка комментариев, группы, диаграммы, проверка предупреждений в CI и публикация результата.
Установка и первый запуск
В Debian и Ubuntu пакет называется doxygen, для диаграмм нужен graphviz. Для настройки через графический интерфейс есть doxywizard, но в статье используется файл конфигурации — его проще хранить в git.
sudo apt install doxygen graphviz
doxygen --version
mkdir -p docs
doxygen -g Doxyfile
Команда создаёт Doxyfile со всеми параметрами и подробными комментариями. Команда doxygen Doxyfile читает конфигурацию из текущего каталога. Если файл называется иначе, укажите путь явно: doxygen docs/Doxyfile.
Минимальный Doxyfile
Из сотен параметров для старта нужны два десятка. Ниже — рабочий пример для проекта на C++ с исходниками в src и заголовками в include.
PROJECT_NAME = "MyProject"
PROJECT_BRIEF = "Библиотека обработки данных"
OUTPUT_DIRECTORY = build/docs
INPUT = README.md include src
RECURSIVE = YES
FILE_PATTERNS = *.h *.hpp *.c *.cpp *.md
EXCLUDE = src/third_party
EXTRACT_ALL = NO
EXTRACT_STATIC = YES
GENERATE_HTML = YES
GENERATE_LATEX = NO
GENERATE_XML = YES
HTML_OUTPUT = html
USE_MDFILE_AS_MAINPAGE = README.md
INPUT_ENCODING = UTF-8
OUTPUT_LANGUAGE = Russian
WARN_IF_UNDOCUMENTED = YES
WARN_AS_ERROR = NO
Параметр EXTRACT_ALL = NO важен: Doxygen документирует только то, что помечено комментариями, и предупреждает о пропусках. Если поставить YES, предупреждения исчезнут вместе с мотивацией писать документацию.
Пути в Doxyfile отсчитываются от каталога, из которого запущена команда. Запускайте doxygen из корня проекта, иначе INPUT и примеры придётся описывать относительно другого места, а ссылки в HTML поедут.
GENERATE_XML пригодится позже: XML легко читается скриптами и используется связкой Breathe и Sphinx для сайта документации. Для небольших проектов достаточно HTML, но XML стоит включить заранее, если документацию планируют объединять с руководством пользователя.
Как писать комментарии
Doxygen понимает несколько стилей: /** … */, /// и //!. Внутри используются команды с обратным слешем или @. Краткое описание отделяется от подробного пустой строкой либо командой \brief.
/**
* \brief Читает конфигурацию из файла.
*
* Поддерживаются форматы JSON и YAML. При ошибке разбора
* возвращается код 2, а текст ошибки попадает в err.
*
* \param path абсолютный путь к файлу
* \param err буфер для сообщения об ошибке
* \return 0 при успехе, 2 при ошибке разбора
* \warning Функция не потокобезопасна.
* \see ConfigWriter
*/
int config_read(const char *path, char *err);
Полезные команды: \note, \warning, \deprecated, \todo, \bug, \see, \since. Для примеров кода используйте \code … \endcode или \include с фрагментом из реального файла — второй вариант не расходится с кодом. Путь к примерам задаётся через EXAMPLE_PATH.
/** \example example_read.c
* Пример использования config_read().
*/
Группы и главная страница
Крупный проект удобно делить на модули. Группа объявляется в отдельном заголовке или .dox-файле, а функции и классы привязываются к ней командой \ingroup.
/** \defgroup config Конфигурация
* \brief Чтение и запись настроек.
* @{
*/
/** \ingroup config */
int config_write(const char *path);
/** @} */
Главную страницу проще всего сделать из README.md, указав USE_MDFILE_AS_MAINPAGE. Внутри работают заголовки Markdown, таблицы и ссылки на классы. Для ручной страницы используйте \mainpage в отдельном файле. Файлы .dox с одним лишь \mainpage удобно держать в docs и не смешивать с кодом.
Диаграммы и связи
Graphviz рисует графы вызовов и наследования. Включайте их выборочно: на большом проекте генерация может занять минуты и дать сотни мегабайт.
HAVE_DOT = YES
DOT_PATH = /usr/bin
CALL_GRAPH = YES
CALLER_GRAPH = NO
CLASS_DIAGRAMS = YES
DOT_IMAGE_FORMAT = svg
INTERACTIVE_SVG = YES
DOT_NUM_THREADS = 2
Для современных проектов с CMake полезно включить CLANG_ASSISTED_PARSING = YES и указать CLANG_DATABASE_PATH на каталог с compile_commands.json. Это повышает точность разбора шаблонов и макросов, но требует libclang и замедляет сборку.
Проверка в CI
Документация должна собираться так же автоматически, как и код. В GitLab CI достаточно отдельной задачи, которая падает при предупреждениях.
docs:
image: debian:stable
script:
- apt-get update && apt-get install -y doxygen graphviz
- doxygen Doxyfile
- test -f build/docs/html/index.html
artifacts:
paths:
- build/docs/html
Чтобы предупреждения действительно ломали сборку, задайте WARN_AS_ERROR = FAIL_ON_WARNINGS. Значение YES просто печатает их, FAIL_ON_WARNINGS возвращает ненулевой код. Перед включением прогоните сборку локально и разберите самый частый класс замечаний.
doxygen Doxyfile 2>&1 | tee doxygen.log
grep -c 'warning:' doxygen.log
doxygen -u Doxyfile
Команда doxygen -u обновляет старый Doxyfile, добавляя новые параметры и сохраняя ваши значения. Её стоит выполнять после обновления Doxygen, иначе новые возможности останутся выключенными.
Публикация и оформление
Готовый HTML — это статические файлы, их можно отдать любым веб-сервером или опубликовать через GitHub Pages. Для своего оформления используйте doxygen -w html header.html footer.html stylesheet.css и укажите HTML_HEADER, HTML_FOOTER и HTML_STYLESHEET. Не правьте файлы внутри сгенерированного каталога: следующая сборка их перезапишет.
Чек-лист качества документации:
- У каждой публичной функции описаны параметры и возвращаемое значение.
- Нет комментариев, которые пересказывают имя функции («возвращает путь»).
- Примеры собираются вместе с проектом, а не живут отдельно.
- WARN_IF_UNDOCUMENTED включён, а сборка в CI проверяет предупреждения.
- Версия Doxygen зафиксирована в CI-образе, чтобы вывод не менялся без причины.
- Сгенерированный каталог добавлен в .gitignore, а исходники документации хранятся отдельно.
Итог
Doxygen не требует отдельного формата документации: комментарии остаются рядом с кодом и проверяются на ревью. Начните с минимального Doxyfile, опишите публичный API, включите предупреждения и автоматическую сборку. Такой процесс дешевле поддерживать, чем отдельный сайт с ручными описаниями, которые устаревают через месяц.