Данная статья входит в получившийся цикл статей о системе документирования Doxygen:
- Документируем код эффективно при помощи Doxygen
- Оформление документации в Doxygen
- Построение диаграмм и графов в Doxygen
Она завершает цикл статей о системе документации Doxygen. На этот раз статья посвящена построению различных диаграмм и графов в Doxygen. В ней мы рассмотрим основные их виды, различные способы их настройки и оформления, а также приведём ряд примеров и советов по их использованию.
Введение
Doxygen позволяет автоматически строить на основе исходного кода достаточно большое количество разнообразных диаграмм и графов, призванных проиллюстрировать те или иные элементы исходного кода, при этом любой график может служить также и способом навигации по коду и документации, поскольку Doxygen автоматически проставляет поверх самого графика ссылки на соответствующие разделы документации. В живую на результат его работы можно посмотреть, например, здесь и здесь (в последнем примере они для компактности свернуты).
Основными типами диаграмм и графов, которые можно построить с его помощью, являются:
- Диаграмма наследования классов
- Диаграмма кооперации классов
- Диаграмма иерархии классов
- Граф вызовов
- Граф вызывающих функций
- Граф зависимостей (прямых и обратных)
Далее мы подробно рассмотрим каждый из этих типов, но прежде сделаем ряд общих замечаний и поговорим об основных настройках, которые нам пригодятся при их построении. Вообще, многое из того, что будет описано, вы можете найти в соответствующем разделе документации.
Основы построения диаграмм и графов
По умолчанию возможности Doxygen для построения различного рода диаграмм и графов очень ограничены (доступна только диаграмма наследования классов), пример такой диаграммы приведён ниже:
Для того, чтобы строить более продвинутые диаграммы и графы потребуется Graphviz, специальное открытое программное обеспечение, предназначенное для построения различного рода графов. Скачать его можно здесь.
После его установки необходимо выполнить некоторые изменения в файле настроек Doxygen. Для этого используются следующие команды:
Команда | Назначение |
HAVE_DOT | Показывает, что для генерации диаграмм и графов необходимо использовать Graphviz (по умолчанию отключена) |
DOT_PATH | Указывает путь к исполняемому файлу «dot.exe» (по умолчанию предполагается, что путь к нему имеется в переменной path; как правило, так оно и есть). |
Команда | Назначение |
DOT_GRAPH_MAX_NODES | Устанавливает максимальное количество узлов, которые будут отображаться в графе. Если число узлов станет больше установленного значения, то граф будет урезан, в результате чего родительский узел, чьи дочерние узлы были скрыты, станет выделен красным (если же число узлов было задано меньше, чем число детей корневого узла, то он вовсе не будет показан) |
MAX_DOT_GRAPH_DEPTH | Устанавливает максимальную глубину графа (глубина равна число граней от наиболее удаленного узла графа до корневого узла). Опять же, если глубина графа будет превышать это значение, то он будет обрезан, в результате чего родительский узел, чьи дочерние узлы были скрыты, станет выделен красным |
DOT_IMAGE_FORMAT | Указывает формат, в котором будут создаваться диаграммы и графы (поддерживаются «png», «jpg», «svg», «gif») |
DOT_FONTNAME | Устанавливает гарнитуру используемую для отображения текста на графах и диаграммах |
DOT_FONTSIZE | Указывает кегль (высота букв, измеряемая в пунктах) для текста на графах и диаграммах |
DOT_FONTPATH | Указывает путь к папке со шрифтовыми файлами |
HTML_DYNAMIC_SECTIONS | В случае установки этой опции, Doxygen будет сворачивать определенные элементы HTML документации (например, графы), которые пользователь по желанию может впоследствии раскрыть |
Диаграмма наследования классов
Диаграмма наследования классов (class graph) предназначена для графического отображения отношений наследования между классами (как «вверх», так и «вниз»).
Для того, чтобы сгенерировать такую диаграмму для всех документированных классов (при этом если в файле настроек установлена, например, опция EXTRACT_ALL, то к документированным классам относятся все классы) необходимо установить следующую опцию в файле настроек:
CLASS_GRAPH = YES
Ниже приведён пример построения такой диаграммы для тестового примера (он взят из легенды, создаваемой Doxygen), иллюстрирующего различные виды отношений между классами:
Исходный код примера и используемые настройки
Измененные настройки:
Исходный код примера:
CLASS_GRAPH = YES
MAX_DOT_GRAPH_DEPTH = 2
TEMPLATE_RELATIONS = YES
Исходный код примера:
/*! Invisible class because of truncation */
class Invisible { };
/*! Truncated class, inheritance relation is hidden */
class Truncated : public Invisible { };
/*! Class that is inherited using public inheritance */
class PublicBase : public Truncated { };
/*! A template class */
template<class T> class Templ { };
/*! Class that is inherited using protected inheritance */
class ProtectedBase { };
/*! Class that is inherited using private inheritance */
class PrivateBase { };
/*! Class that is used by the Inherited class */
class Used { };
/*! Super class that inherits a number of other classes */
class Inherited : public PublicBase,
protected ProtectedBase,
private PrivateBase,
public Undocumented,
public Templ<int>
{
public:
Used *m_usedClass;
};
Теперь рассмотрим, что означают те или иные условные обозначения.
Корневой узел | |
Обычный узел, соответствующий документированному классу | |
Узел, соответствующий недокументированному классу | |
Родительский узел, чьи дочерние узлы были скрыты (например, в силу ограничения на число узлов в графе или его глубину) |
Указывает на открытое наследование | |
Указывает на защищенное наследование | |
Указывает на закрытое наследование | |
Указывает, что класс является специализацией некоторого шаблонного класса, при этом подпись рядом со стрелкой указывает на то, какой шаблонный параметр был указан при специализации |
Опция | Значение | По умолчанию |
HIDE_UNDOC_RELATIONS | Показывает, необходимо ли скрывать связь с некоторым классом, если он недокументирован или не является классом | YES |
TEMPLATE_RELATIONS | Устанавливает, необходимо ли отображать связь, показывающую, что один класс является специализацией другого | NO |
Диаграмма кооперации классов
Диаграмма кооперации классов (collaboration graph) предназначена для графического отображения отношений наследования между классами (только «вверх», то есть показаны будут только родительские классы), а также взаимодействие между ними, под которым в данном случае понимается то, что один класс содержит среди атрибутов объект другого класса.
Для того, чтобы включить диаграмму наследования классов, необходимо установить команду COLLABORATION_GRAPH:
COLLABORATION_GRAPH = YES
Ниже представлена диаграмма кооперации классов для того же примера, который был рассмотрен ранее:
Следует отметить, что в данном случае отличие от диаграммы наследования классов состоит только в том, что здесь отображена связь между классами Inherited и Used, которая выражается в том, что первый класс имеет атрибут, являющийся экземпляром второго класса. Обозначение для такой связи следующее:
Указывает, что один класс содержит атрибут, являющийся экземпляром другого класса, при этом подпись рядом со стрелкой указавает на имя соответствующего атрибута |
Диаграмма иерархии классов
Диаграмма иерархии классов (graphical hierarchy) предназначена только для отображения отношений наследования между множеством разных классов. Фактически, она представляет собой графическое представление текстового описания иерархии классов, которое генерируется по умолчанию:
Граф вызовов
Прежде, чем перейти к описанию данного типа графов, договоримся, что всё сказанное далее справедливо и для функций и для методов классов, но для краткости мы будем употреблять слово «функции». Итак, граф вызовов (call graph), иллюстрирует то, какие функции вызываются внутри тела документируемой функции, а также во всех вложенных функциях (глубину можно настраивать, задавая максимальную глубину графа в файле настроек).
Для того, чтобы построить граф вызовов функции могут быть использованы два подхода: установка опции, которая вызовет построение графов вызовов для всех функций, и использование специальной команды, которая добавляется в описании функции (последнее может оказаться предпочтительнее, если вам надо проиллюстрировать конкретную функцию или ваш проект очень большой).
Для первого подхода необходимо установить следующую опцию:
CALL_GRAPH = YES
Для второго подхода используется следующая команда:
\callgraph
Пример графа вызова изображен ниже. Формулы на изображении ниже даны для примера (функция combination вычисляет число сочетаний, а для вычисления факториала использует формулу Стирлинга):
Граф вызывающих функций
Граф вызывающих функций (caller graph), иллюстрирует цепочку вызовов различных функций в результате которого вызывается документируемая функция, (глубина такой цепочки может быть настроена путём настройки максимальной глубины графа в файле настроек).
Опять же есть два способа построения таких графов. Первый способ – это установка соответствующей опции в файле настроек:
CALLER_GRAPH = YES
Второй способ – это использование специальной команды:
\callergraph
Простой пример графа вызывающих функций приведён ниже:
Кратко поясним его: для вычисления факториала по формуле Стирлинга используется функция возведения в степень (pow), для вычисления экспоненты также используется данная функция, а вычисление экспоненты может быть использовано для вычисления значений гиперболических функций.
Граф зависимостей
Граф зависимостей идейно близок к графу вызовов, только он иллюстрирует не вызовы, а зависимости между различными файлами исходного кода.
Прямой граф зависимостей
Прямой граф зависимостей (include graph) иллюстрирует цепочку зависимостей вплоть до документируемого файла, т.е. то, какие файлы были подключены к документируемому файлу, затем какие файлы, в свою очередь, были подключены к тем файлам и т.д.
Для построения такого рода графов необходимо установить следующую опцию в файле настроек:
INCLUDE_GRAPH = YES
Пример приведён ниже:
Обратный граф зависимостей
Обратный граф зависимостей (included by graph) иллюстрирует цепочку зависимостей от документируемого файла, т.е. то какие файлы включают в себя документируемый файл, затем в какие файлы включены данные файлы и т.д.
Для построения такого рода графов необходимо установить следующую опцию в файле настроек:
INCLUDED_BY_GRAPH = YES
Пример приведён ниже:
Граф директорий
Граф директорий (directory graph) предназначен для графического представления рассматриваемой директории. Для построения такого графа используется следующая опция:
DIRECTORY_GRAPH = YES
Обратите внимание на то, что один из элементов графа имеет красную обводку, это означает, что в данную директорию вложены другие директории.
UML и Doxygen
Doxygen позволяет создавать диаграммы «в стиле, схожем с Unified Modeling Language». Разработчики очень аккуратно выражаются в этом плане, поскольку эта возможность не подразумевает то, что на основе кода будет построена аккауратная и грамотная UML-схема, для этой задачи следует использовать другие инструменты, да и они зачастую дают сбои, поскольку в UML в первую очередь выражается идея, пусть и порой достаточно близкая к конкретной реализации.
Итак, для того чтобы строить диаграммы в UML стиле, необходимо установить следующую опцию:
UML_LOOK = YES
Вновь обратимся к используемому ранее примеру, только дополним его открытыми, закрытыми и защищенными атрибутами и методами:
К сожалению, Doxygen зачастую не в состоянии отразить многие более сложные концепции, хотя бы просто потому, что нельзя указать, какие конкретно классы необходимо включить в диаграмму. Поэтому в тех случаях, когда необходимо проиллюстрировать, например, примененный шаблон проектирования или какое-то иное решение, иногда проще и эффективнее построить схему в ином редакторе и просто импортировать её. Благо, что для одного из очень распространенных специализированных редакторов PlantUML у Doxygen есть встроенная поддержка (для его использования необходимо указать путь к в опции ).
В первую очередь необходимо убедится в том, что Java установлена на вашем компьютере и корректно настроена и затем указать корректный путь к jar файлу при помощи соответствующей опции:
PLANTUML_JAR_PATH = путь_к_jar_файлу
После этого для вставки диаграммы PlantUML необходимо использовать соответствующие команды \startuml и \enduml:
\startuml [{file}] ["caption"] [<sizeindication>=<size>]
...
\enduml
Все параметры в данном случае необязательны. Параметр file указывает имя для сгенерированного файла, если его не указать, то оно будет выбрано автоматически; параметр caption устанавливает подпись к схеме; последний параметр используется для указания размера схемы.
Теперь перейдём непосредственно к примеру (далее изображена диаграмма для шаблона проектирования «компоновщик»):
/*! \file
Компоновщик (англ. Composite pattern) — структурный шаблон проектирования, объединяющий объекты в древовидную структуру для представления иерархии от частного к целому. Компоновщик позволяет клиентам обращаться к отдельным объектам и к группам объектов одинаково. Ниже представлена иллюстрация данного шаблона при помощи UML:
\startuml
interface Component {
+doThis()
}
class Composite {
-elements
+addElement()
+doThis()
}
class Leaf {
+doThis()
}
Component <|-- Leaf
Component<|-- Composite
Composite o-- Component
\enduml
*/
Результат представлен ниже:
Заключение
Наконец, следует отметить, что схемы можно строить в любом предпочитаемым вами редакторе или при помощи других генераторов, а затем результат импортировать в Doxygen. Вообще, всё зависит от ваших требований и тех задач, которые стоят перед вами; в некоторых случаях тех возможностей, которые предоставляет вам Doxygen, хватит с головой, и тогда я, надеюсь, эта статья окажется для вас приятной находкой; а иногда их может оказаться недостаточно и тогда потребуется применение других инструментов и других решений.
Спасибо за внимание!