Использование Doxygen для документирования кода
Содержание |
Использование Doxygen
Использовать Doxygen просто – для этого надо просто запустить программу указав ей путь к файлу с настройками. Файл с настройками представляет собой простой текстовой файл, который можно редактировать как в текстовом редакторе, так и с помощью специальных программ, например Doxygate.
В настройках описывается внешний вид документации, какие сущности и отношения между ними следует включать в нее, имя проекта, путь к анализируемым файлам и так далее.
Я предпочитаю редактировать этот файл вручную, тем более, что его достаточно настроить один раз под свои потребности и затем в новых проектах изменять одну строку – имя проекта. В конце заметки будет представлен используемый мной конфигурационный файл.
Что нужно для работы с Doxygen
- Doxygen (Документация)
- make
- Perl
- GraphViz
- MSCGEN
Структура папок в проекте
- /doxygen
- /docs – результат работы программы
- index.html - документация
- /doxyfile
- /filter – скрипт для преобразования sv -> cpp
- /html – html-шаблон страницы (сейчас не используется)
- /img – изображения для вставки на страницы документации
- download_img.sh - скрипт для скачивания картинок
- /scripts
- dofilter.bat – скрипт запуска фильтра для Windows (запускается doxygen`ом)
- dofilter.sh – скрипт запуска фильтра для Unix(запускается doxygen`ом)
- dotest.pl
- Doxyfile.delta – Параметры касающиеся конкретного проекта
- Doxyfile.output – входной файл с параметры для Doxygen (слияние .template и .delta)
- Doxyfile_sv.template – параметры по умолчанию для Doxygen
- Makefile скрипт для запуска
- /docs – результат работы программы
- /sv
- info.txt - файл с декларациями групп/категорий в документации
Назначение файлов
makefile
Скрипт для генерации html-отчета
make
Doxyfile.delta
Файл настроек параметров проекта
#FILTER_PATTERNS = *.sv=./dofilter.sh *.svh=./dofilter.sh FILTER_PATTERNS = *.sv=dofilter.bat *.svh=dofilter.bat STRIP_FROM_PATH = ../ PROJECT_NAME = UniPro (Pinta) PROJECT_NUMBER = 1.0.0 HTML_OUTPUT = docs #HTML_FOOTER = <PATH_DOXYSCR>/html/idv_dox_footer.html INCLUDE_PATH = <PATH_PRJ>/../sv <PATH_PRJ>/../sv/pa_sap <PATH_PRJ>/../sv/pa_sap/sequences <PATH_PRJ>/../sv/pa_lm_sap <PATH_PRJ>/../sv/pa_lm_sap/sequences <PATH_PRJ>/../sv/phy_sap <PATH_PRJ>/../sv/phy_sap/sequences <PATH_PRJ>/../sv/scoreboard <PATH_PRJ>/../sv/scoreboard/l15_model <PATH_PRJ>/../tb <PATH_PRJ>/../test/test_lib <PATH_PRJ>/../test/vseq_lib INPUT = <PATH_PRJ>/../sv <PATH_PRJ>/../sv/pa_sap <PATH_PRJ>/../sv/pa_sap/sequences <PATH_PRJ>/../sv/pa_lm_sap <PATH_PRJ>/../sv/pa_lm_sap/sequences <PATH_PRJ>/../sv/phy_sap <PATH_PRJ>/../sv/phy_sap/sequences <PATH_PRJ>/../sv/scoreboard <PATH_PRJ>/../sv/scoreboard/l15_model <PATH_PRJ>/../tb <PATH_PRJ>/../test/test_lib <PATH_PRJ>/../test/vseq_lib IMAGE_PATH = img
- для добавления новых папок проекта их нужно включить в переменные INCLUDE_PATH и INPUT
- STRIP_FROM_PATH - путь, который исключается при выводе пути к файлу в документации
Файл Doxyfile.output
- LAYOUT_FILE = ./doxyfile/idv_doxylayout.xml
- FILE_PATTERNS = *.svh *.sv *.cpp *.c *.h *.vhd *.v *.txt *.md
- FILTER_PATTERNS = *.sv=./filter/idv_doxyfilter_sv.pl *.svh=./filter/idv_doxyfilter_sv.pl
Пример отчета
Формат комментариев
Doxygen поддерживает несколько стилей комментариев:
/** * Комментарии, воспринимаемые программой Doxygen */
/// Комментарий, воспринимаемые программой Doxygen /// продолжение комментария
int count ; ///< Счетчик повторов int count ; /**< Счетчик повторов */
Примеры тегов
Служебные
@brief
Краткое описание комментируемой сущности.
Пример:
/// @brief Функция для поиска пользователя в базе данных
@details
Подробное описание элемента (функции, класса и пр.), то что будет показано, если перейти по ссылке "More..." ("Подробней") в документации.
Пример:
/** * @details Данная функция делает выборку из базы данных по имени пользователя * и возвращает структуру с информацией о нем. Ожидается, что соединение с базой * данных установлено и пользователь существует */
Комбинации @brief и @details
/*! \brief Brief description. * Brief description continued. * * \details detailed description starts here. */
/*! \brief Brief description. * Brief description continued. * * detailed description starts here. */
/// Brief description. /** detailed description. */
@param
\param [(dir)] <parameter-name> { parameter description }
Параметры передаваемые в функции/классе и пр.
Пример:
/** * A pure virtual member. * @param c1 the first argument. * @param c2 the second argument. */ virtual void testMeToo(char c1,char c2) = 0;
/*! * Copies bytes from a source memory area to a destination memory area, * where both areas may not overlap. * @param[out] dest The memory area to copy to. * @param[in] src The memory area to copy from. * @param[in] n The number of bytes to copy */ void memcpy(void *dest, const void *src, size_t n);
@return
Возвращаемое функцией значение.
Пример:
@return Информация о пользователе
@note, @warning, @todo
@note \todo { paragraph describing what is to be done } \warning { warning message }
@file, @class, @fn, @def, @enum
\fn (function declaration) \file [<name>] \class <name> [<header-file>] [<header-name>] \dir [<path fragment>] \def <name> \enum <name>
class Test { public: enum TEnum { Val1, Val2 }; /*! Another enum, with inline docs */ enum AnotherEnum { V1, /*!< value 1 */ V2 /*!< value 2 */ }; };
Для форматирования
Разметка
- списки
- Item 1 More text for this item. - Item 2 + nested list item. + another nested item. - Item 3 |
|
- Выделения
- _single underscores_ → single underscores
- __double underscores__ → single underscores
- вставка кода
16:15, 3 ноября 2014 (MSK)16:15, 3 ноября 2014 (MSK)16:15, 3 ноября 2014 (MSK){.c} int func(int a, int b) { return a*b; } 16:15, 3 ноября 2014 (MSK)16:15, 3 ноября 2014 (MSK)16:15, 3 ноября 2014 (MSK)
- таблица
| Right | Center | Left | | ----: | :----: | :---- | | 10 | 10 | 10 | | 1000 | 1000 | 1000 |
Вставка изображений
- Первый вариант
\image <format> <file> ["caption"] [<sizeindication>=<size>]
Inserts an image into the documentation.
/*! Here is a snapshot of my new application: * \image html application.jpg * \image latex application.eps "My application" width=10cm */
- Второй вариант
 ![Figure - UVM top env architecture] (UVM_TOP_Architecture.png "UVM top env architecture")
- IMAGE_PATH = img
Разделы и подразделы
- \section <section-name> (section title) - Creates a section with name <section-name>.
- \subsection <subsection-name> (subsection title) - Creates a subsection with name <subsection-name>. The title of the subsection should be specified as the second argument of the \subsection command.
- \subsubsection <subsubsection-name> (subsubsection title)
- \paragraph <paragraph-name> (paragraph title)
Страницы и подстраницы
\mainpage A simple manual \page intro Introduction \subpage <name> ["(text)"]
Содержание
\tableofcontents
Creates a table of contents at the top of a page, listing all sections and subsections in the page.
\code [ '{'<word>'}'] \code{.py} class Python: pass \endcode
Диаграммы GraphViz
/** \mainpage * Class relations expressed via an inline dot graph: * \dot * digraph example { * node [shape=record, fontname=Helvetica, fontsize=10]; * b [ label="class B" URL="\ref B"]; * c [ label="class C" URL="\ref C"]; * b -> c [ arrowhead="open", style="dashed" ]; * } * \enddot * Note that the classes in the above graph are clickable * (in the HTML output). */
Диаграммы MSCGEN
/** @msc описание рисунка @endmsc */
/** @msc arcgradient = 8; a [label="Client"],b [label="Server"]; a=>b [label="data1"]; a-xb [label="data2"]; a=>b [label="data3"]; a<=b [label="ack1, nack2"]; a=>b [label="data2", arcskip="1"]; |||; a<=b [label="ack3"]; |||; @endmsc */
ref
\ref <name> ["(text)"]
Creates a reference to a named section, subsection, page or anchor.
Организация структуры
\ingroup (<groupname> [<groupname> <groupname>])
- ingroup добавлет описания class, file или namespace в соответствующую группу(ы).
\defgroup <name> (group title)
- defgroup Indicates that a comment block contains documentation for a group of classes, files or namespaces. This can be used to categorize classes, files or namespaces, and document those categories. You can also use groups as members of other groups, thus building a hierarchy of groups.
The <name> argument should be a single-word identifier.
\addtogroup <name> [(title)]
- создаёт новую группу либо добавляет описание к уже существующей группе
/*! \addtogroup mygrp * Additional documentation for group 'mygrp' * @{ */ /*! * A function */ void func1() { } /*! Another function */ void func2() { } /*! @} */
Примеры
* @defgroup sequences Sequences * @{ * @brief Sequence classes * * @defgroup pa_sap_tx_seq PA_SAP TX Sequences * @defgroup pa_sap_rx_seq PA_SAP RX Sequences * @defgroup pa_lm_sap_tx_seq PA_LM_SAP TX Sequences * ... * @}
/// @file l15_pa_sap_tx_sequences.sv /// @ingroup pa_sap_tx_seq
/** * @class l2_data_base_seq * @ingroup pa_sap_tx_seq * @brief Consist of all base task for generate all sequence variants for test cases * */ class l2_data_base_seq extends uvm_sequence #(pa_sap_tr);
Доступные группы
- agents Agents
- drivers Drivers
- monitors Monitors
- env Environments
- scoreboard Scoreboards
- tests Tests
- sequences Sequences
- pa_sap_tx_seq PA_SAP TX Sequences
- pa_sap_rx_seq PA_SAP RX Sequences
- pa_lm_sap_tx_seq PA_LM_SAP TX Sequences
- pa_lm_sap_rx_seq PA_LM_SAP RX Sequences
- phy_sap_tx_seq PHY_SAP TX Sequences
- phy_sap_rx_seq PHY_SAP RX Sequences
- phy_sap_tx_cntr_seq PHY_SAP TX Control Sequences
- phy_sap_rx_cntr_seq PHY_SAP RX Control Sequences
- vsequence Virtual sequences
- transaction Transaction (Sequence item)
Комментирование в стиле Doxygen
Doxygen поддерживает несколько стилей комментариев. Я придерживаюсь следующего:
/** Комментарии */
Обратите внимание, что последовательность символов /** сообщает программе, что начинается комментарий предназначенный для нее. Начиная с этого места и до завершающих символов */ следуют комментарии.
Есть несколько директив, которые помогают Doxygen составить грамотную документацию. Вот основные:
@brief | Краткое описание комментируемой сущности. Пример: @brief Функция для поиска пользователя в базе данных |
@details | Подробное описание сущности, то что будет показано, когда вы нажмете в документации рядом с коротким описанием ссылку "Подробней". На мой взгляд использоваться должно как можно реже, в силу того, что короткое описание должно точно отражать идею использования сущности, а использование ее не должно сопровождаться неожиданными предусловиями. Пример: @details Данная функция делает выборку из базы данных по имени пользователя и возвращает структуру с информацией о нем. Ожидается, что соединение с базой данных установлено и пользователь существует |
@param | Параметры передаваемые функции. Пример: @param name Имя пользователя |
@return | Возвращаемое функцией значение. Пример: @return Информация о пользователе |
@throw | Исключения выбрасываемые функцией. Пример: @throw DatabaseError Если произошла ошибка при подключении к базе данных |
Пример комментариев для класса:
/** @brief Класс для работы с базой данных @details Осуществляет подключение к базе при создании и закрывает соединение при уничтожении */ class Database { public: /** @brief Конструктор @param connectionString Строка подключения к базе данных @throw ConnectionError Если подключение не удалось */ explicit Database(const std::string& connectionString); /** @brief Поиск пользователя в базе данных @details Данная функция делает выборку из базы данных по имени пользователя и возвращает структуру с информацией о нем. Ожидается, что соединение с базой данных установлено и пользователь существует @param name Имя пользователя @return Информация о пользователе @throw DatabaseError Если произошла ошибка при подключении к базе данных @throw InvalidRequest Если пользоваделя в базе не существует */ CustomerPtr GetCustomer(const std::string& name); };
Этого достаточно для 99% кода, но остается вопрос комментирования на уровне проекта, а не файла. Для этого служат следующие директивы:
@mainpage | Основная страница проекта, то с чего начинается просмотр документации. Пример: @mainpage Приложение для учета пользователей |
@page | Дополнительные страницы проекта. Я рассматриваю их как логически обособленные части проекта. Пример: @page Database Database Утилиты для работы с базой данных |
@ref | Ссылки на страницы проекта, с их помощью можно организовать например ссылки с главной страницы проекта на страницы подпроектов. Пример: @ref Database Утилиты для работы с базой данных |
Для организации четкой структуры я рекомендую в каждом подпроекте создавать файл description.h в котором будет директива @page, описание для чего нужен этот подпроект и принципы работы с ним.
В свою очередь в корне проекта я также создаю файл description.h в котором немного рассказано о проекте в целом и приведены ссылки на его части:
/** @mainpage Приложение для учета пользователей Состоит из следующих частей: - @ref Database Утилиты для работы с базой данных */
Чтобы привести фрагмент кода (например пример работы с классом) используется конструкция @code – @endcode:
/** Пример использования Foo: @code Foo f(); f.Run(); @endcode */
Списки можно создавать с помощью символа - (минус). Пример:
/** Список: - Первый пункт - Второй пункт */
Перечисления я оформляю так:
/** @brief Режимы устройства */ enum Mode { Mode_On, /**< Включено */ Mode_Off /**< Выключено */ };
В большинстве случаев приведенных директив достаточно, с полным списком вы можете ознакомиться в руководстве.
Ложка дегтя
Обратите внимание! Очень ВАЖНО перед объявлением пространства имен повторять его имя в комментарии Doxygen. Похоже на баг (версия 1.6.2), но без этого содержимое пространства не попадет в документацию. Пример:
/** namespace A @brief Пространство имен A */ namespace A { }
Символ @ в конструкции namespace отсутствует!
Файл с настройками Doxygen
Как уже упоминалось, для работы Doxygen нужен файл с настройками. Программа умеет создавать файл с параметрами по умолчанию:
doxygen -g
После этого будет сгенерирован файл с именем Doxyfile содержащий настройки по умолчанию. Вы можете отредактировать его под свои нужды, что сделать довольно просто благодаря содержащимся в нем пояснениям.
Рассмотрю некоторые из пунктов которые я изменяю:
PROJECT_NAME | Имя проекта. |
QUIET | Допустимые значения YES и NO. Я ставлю YES, для того чтобы предупреждения не терялись среди обилия информации о работе программы. |
WARN_NO_PARAMDOC | YES для вывода предупреждений о недокументированных аргументах функции. |
INPUT | Путь к анализируемому коду. Я рекомендую в корне проекта создать директорию docs содержащую Doxyfile с настройками, в таком случае значение этого параметра будет ../ |
FILE_PATTERNS | Шаблон для имени анализируемых файлов. Поскольку документироваться должны только открытые интерфейсы, то очевидно, что следует анализировать только заголовочные файлы: *.h |
RECURSIVE | Рекурсивно анализировать файлы в поддиректориях – YES. |
EXCLUDE_PATTERNS | Исключение из анализа директорий соответствующих маске. Пример: EXCLUDE_PATTERNS = */.svn/* */build/* */tests/* */sources/* |
HAVE_DOT | YES, если установлен Graphviz и требуется визуализация связей. |
Очень разумно будет один раз написать свою конфигурацию для Doxygen и в новых проектах менять лишь один параметр – PROJECT_NAME.