«Бог не меняет того, что (происходит) с людьми, пока они сами не изменят своих помыслов.» Коран, Сура 12:13

Использование Doxygen для документирования кода

Материал из Wiki
Перейти к: навигация, поиск

Содержание

Использование Doxygen

Использовать Doxygen просто – для этого надо просто запустить программу указав ей путь к файлу с настройками. Файл с настройками представляет собой простой текстовой файл, который можно редактировать как в текстовом редакторе, так и с помощью специальных программ, например Doxygate.

В настройках описывается внешний вид документации, какие сущности и отношения между ними следует включать в нее, имя проекта, путь к анализируемым файлам и так далее.

Я предпочитаю редактировать этот файл вручную, тем более, что его достаточно настроить один раз под свои потребности и затем в новых проектах изменять одну строку – имя проекта. В конце заметки будет представлен используемый мной конфигурационный файл.

Что нужно для работы с Doxygen

Структура папок в проекте

  • /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 скрипт для запуска
  • /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 Функция для поиска пользователя в базе данных

@detailed

Подробное описание элемента (функции, класса и пр.), то что будет показано, если перейти по ссылке "More..." ("Подробней") в документации.

Пример:

/**
 * @detailed Данная функция делает выборку из базы данных по имени пользователя
 * и возвращает структуру с информацией о нем. Ожидается, что соединение с базой 
 * данных установлено и пользователь существует
 */

Комбинации @brief и @detailed

/*! \brief Brief description.
 *         Brief description continued.
 *
 *  \detailed 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

@note
\todo { paragraph describing what is to be done }
\warning { warning message }
\version { version number }
\ref <name> ["(text)"]

Creates a reference to a named section, subsection, page or anchor.

\section and \subsection
\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)
\subpage <name> ["(text)"]
\mainpage A simple manual 
\page intro Introduction
\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
\dot
/*! \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).
 */

Для форматирования

Организация структуры

Комментирование в стиле Doxygen

Doxygen поддерживает несколько стилей комментариев. Я придерживаюсь следующего:

/** Комментарии */

Обратите внимание, что последовательность символов /** сообщает программе, что начинается комментарий предназначенный для нее. Начиная с этого места и до завершающих символов */ следуют комментарии.


Есть несколько директив, которые помогают Doxygen составить грамотную документацию. Вот основные:

@brief Краткое описание комментируемой сущности.

Пример:
@brief Функция для поиска пользователя в базе данных
@detailed Подробное описание сущности, то что будет показано, когда вы нажмете в документации рядом с коротким описанием ссылку "Подробней". На мой взгляд использоваться должно как можно реже, в силу того, что короткое описание должно точно отражать идею использования сущности, а использование ее не должно сопровождаться неожиданными предусловиями.

Пример:
@detailed Данная функция делает выборку из базы данных
по имени пользователя и возвращает структуру с информацией
о нем. Ожидается, что соединение с базой данных установлено
и пользователь существует
@param Параметры передаваемые функции.

Пример:
@param name Имя пользователя
@return Возвращаемое функцией значение.

Пример:
@return Информация о пользователе
@throw Исключения выбрасываемые функцией.

Пример:
@throw DatabaseError Если произошла ошибка при подключении
к базе данных

Пример комментариев для класса:

/** @brief Класс для работы с базой данных @detailed Осуществляет подключение к базе при создании  и закрывает соединение при уничтожении */
class Database
{
public:
/** @brief Конструктор @param connectionString Строка подключения к базе 
    данных @throw ConnectionError Если подключение не удалось */
	explicit Database(const std::string& connectionString);
/** @brief Поиск пользователя в базе данных @detailed Данная функция делает выборку из базы данных 
 по имени пользователя и возвращает структуру с информацией  о нем. Ожидается, что соединение с базой
 данных установлено  и пользователь существует @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.