-
Clone custom repository
git clone git@github.com:ElectroQuanta/Doxygen.git
- Source code documentation is critical for software maintenance, specially on large developments teams.
- It aims to describe how the code works instead of what it does
- Utility
- Knowledge transfer: not all code is equally obvious. There might be some complex algorithms or custom workarounds that are not clear enough for other developers.
- Troubleshooting: if there are any problems with the product after it's released, having proper documentation can speed up the resolution time. Finding out product details and architecture specifics is a time-consuming task, which results in the additional costs.
- Integration: product documentation describes dependencies between system modules and third-party tools. Thus, it may be needed for integration purposes.
- Code style enforcement: the source code documentation tools requires specific comment syntax, which forces the developer to follow a strict code style. Having a code style standard is specially useful on large project teams.
An automatic source code documentation tool:
-
Extract annotations from source code files (input)
/** * @brief Clones an activity * @param activity: source activity to perform the copying * @param clone: destination activity to perform the copying * @return operation success: false, if either of the input parameters is * invalid; true otherwise * * The cloning operation is used for editing operation, while the end user has * the opportunity to abort; without cloning, data corruption could occur */ bool activity_clone(const Act_T activity, Act_T clone);
-
Parse them and generate tags (structures like Abstract Syntax Trees)
There are several automatic source code documentation tools, typically language-specific, namely:
Doxygen: C, C++, C\#, Java, Objective-C, PHP, PythonGhostDoc: C\#, Visual Basic, C++, JavaScriptJavadoc: Java onlyDocuriumorYARD: Rubyjsdoc: JavascriptSphinx: Python, C/C++, Ruby, etc.
- Released in 1997 (24 years ago)
- De facto standard tool for:
- Generating documentation from annotated C++ sources
- It supports also: C, Objective-C, C#, PHP, Java, Python, IDL (Corba, Microsoft, and UNO/OpenOffice flavors), Fortran, VHDL and to some extent D
- Static analysis tool for SW source trees
- Generating documentation from annotated C++ sources
- Supports the user in 2 ways:
- Flexibility in documentation generation: It can generate an on-line documentation browser (in HTML) and/or an off-line reference manual (in LaTeX) from a set of documented source files. There is also support for generating output in RTF (MS-Word), PostScript, hyperlinked PDF, compressed HTML, and Unix man pages. The documentation is extracted directly from the sources, which makes it much easier to keep the documentation consistent with the source code.
- Assistance in reverse engineering SW: You can configure doxygen to extract the code structure from undocumented source files. This is very useful to quickly find your way in large source distributions. Doxygen can also visualize the relations between the various elements by means of include dependency graphs, inheritance diagrams, and collaboration diagrams, which are all generated automatically.
- FreeRTOS: IMPORTANT
- FLAC
- GraphViz
- LLVM
- C++ REST SDK
-
Annotate source code
/** * @brief App controller: handles all application's logic * @param app - an initialized application instance * @return an integer signaling the execution state * * Its the execution loop controlling the FSM machine behind the application's * logic. It starts in S_Login state. When end user quits the application, * the databases are saved, for future restoration at subsequent program * executions. */ int App_exec(App_T app);
-
Run doxygen
-
Inspect output
Data flow:
Info flow:
-
Options
[1/2]- From source code: github
-
Requires g++, python, cmake, flex, byson
git clone https://github.com/doxygen/doxygen.git cd doxygen mkdir build cd build cmake -G "Unix Makefiles" .. make make install # install binaries
-
- Source distribution with latest release:
-
Obtain source code
# create temporary folder and cd into it mkdir ~/tmp && cd ~/tmp # get compressed archive wget https://www.doxygen.nl/files/doxygen-1.9.2.src.tar.gz # uncompress gunzip doxygen-1.9.2.src.tar.gz # tar -xzvf doxygen-1.9.2.src.tar.gz # or using tar # cd into the extracted folder cd doxygen-1.9.2
-
Build doxygen: requires g++, python, cmake, flex, byson - it takes about 3 mins
mkdir build && cd build #cmake -Dbuild_wizard=YES .. # build Doxywizard (optional) cmake -G "Unix Makefiles" .. # build configuration make # build application sudo make install # install binaries
-
If it cmake aborts, inspect the output and install the appropriate package:
sudo apt install flex # lexer generator sudo apt install bison # parser generator
-
-
obtain the path for doxygen executable
which doxygen
-
- Install additional utilities
-
Graphviz: Graph visualization tool - required to build diagrams
sudo apt install graphviz
-
- From source code: github
-
GUI - Doxywizard
-
Enable cmake compilation flag and recompile
mkdir build && cd build #cmake -Dbuild_wizard=YES .. # build Doxywizard (optional) cmake -G "Unix Makefiles" .. # build configuration make # build application sudo make install # install binaries
-
Check docs
-
-
CLI - Doxyfile
-
Navigate to src code within git repository
cd code/src -
Open
makefilein your editor of choicevim makefile
-
Look for documentation:
DOXYGENandDOXYFILEpaths- Update these paths
-
Create directories to store documentation
cd code mkdir -p doc/doxygen -
Open Doxyfile and update the following variables:
- We're invoking the Doxyfile from the makefile - UPDATE the path accordingly
OUTPUT_DIRECTORY:../doc/doxygenINPUT:.USE_MFILE_AS_MAINPAGE../../readme.md
- We're invoking the Doxyfile from the makefile - UPDATE the path accordingly
-
-
Build doc
cd code/src make doc -
Inspect the
doc/doxygenfoldercd doc/doxygen-
Check that 2 folders were built:
htmlandlatex -
Navigate to
htmlfolder and openindex.htmlin the backgroundcd doc/doxygen/html xdg-open index.html &
-
- Check
readmefile is present - Explore
Data Structures - Explore
Files
Now it's important to understand how to annotate source code files.
-
Best practices to write good documentation
- Simple and concise. Follow the DRY (Don't Repeat Yourself)
principle. Use comments to explain something that requires detailed information.
- Up to date at all times: the code should be documented when it's being written or modified.
- Document any changes to the code. Documenting new features or add-ons is pretty obvious. However, you should also document deprecated features, capturing any change in the product.
- Simple language and proper formatting: Code documents are typically written in English so that any developer could read the comments, regardless of their native language. The best practices for documentation writing require using the Imperative mood, Present tenses, preferably active voice, and second person.
-
Documenting the code
Doxygen uses special comment blocks, i.e., comment blocks with some additional markings to identify source code annotations for the documentation.
-
Description types
For each entity in the code there are two (or in some cases three) types of descriptions, which together form the documentation for that entity, namely:
- Brief description: short one-liner, briefly documenting the following block. It is optional.
- Detailed description: provides more detailed documentation about the following block. It is optional.
- Body description: for methods and functions there is also a third type of description, consists of the concatenation of all comment blocks found within the body of the method or function.
-
Documentation style
-
Javadocstyle: consists of a C-style comment block starting with two*, as follows:/** * Javadoc style ... text ... */
-
Qt styleadd an exclamation mark (!) after the opening of a C-style comment block, as follows:/*! * Qt style ... text ... */
-
slash style: use a block of at least two C++ comment lines, where each line starts with an additional slash or an exclamation mark, as follows:/// /// slash style ... text ... ///
-
-
Documentation levels
-
file: used to describe modules or classes.
/** * @file App.h * @author Jose Pires * @date 12 Jan 2019 * * @brief App module containing the application logic * * It contains only two public functions: * 1. Init - to initialize the app's memory * 2. Exec - contains all application logic */
-
inline: used to describe
#defines, parameters, class members, and structure and enumeration fields.#define DATABASE_USERS "user.db" /**< Database file for users */
-
block: used to describe classes, functions, structures, and enumerations.
/** * allocate dynamic memory and initialze App * @return initialized App_T */ App_T App_init();
-
-
Documentation scope
-
Public: public interfaces are documented in the interface file (
.h)/** * allocate dynamic memory and initialze App * @return initialized App_T */ App_T App_init();
-
Private: private interfaces are documented in the implementation file (
.c)/** * @brief Saves the database * @param db: a constructed database * @param list: a constructed list to save * @param serialize: pointer to generic function capable of serializing * the specific data of the database * @param print: pointer to generic function to debug info * @return true, if successfull; false otherwise * * Used to save users, activities and packs to the database. * *serialize* functions must be implemented by clients. * *print* functions must be implemented by clients. * @see User.h * @see Activity.h * @see Pack.h */ static bool App_save_database(Database_T db, List_T list, void * (*serialize)(Fifo_T fifo), void(*print)(void *data)) { void *data; if(List_isDirty(list)) { /* Reopen database and rewind list */ Database_close(db); Database_open(db, "wb"); List_rewind(list); /* While an user exists */ while ( (data = List_pop(list)) != NULL ) { /* Serialize object to file and remove from the list */ App_serialize(db, serialize, data); List_remove(&list, data); List_rewind(list); if(print) { print(data); print_msg_wait("Wait\n", -1); } } return true; } return false; }
-
-
Tags explained
- @brief: briefly describing the function’s purpose.
- @param : describing all parameters and its prerequisites, in this case, app.
- @return: identifying the return value of the function.
- Detailed description: providing further details about the function’s operation.
- @see <reftag>: reference files
- @file : document filename
- @author : document autor
- @date <datestr>: document date
-
- Create a new module for anything you like
- try to
#includeany of the previous modules, e.g.,fifo,list,Menu - Create a header file with the public interface and annotate it
- Create the respective implementation file with the private interface and annotate it
- try to
- Modify the readme file to explain why you added the module
- Run doxygen
- Inspect the generated documentation
- Explore snippets from your environment to add annotations
PlantUML is a tool for quickly drawing diagrams from text based descriptions. It is specially adequate for sequence diagrams, as draw.io is not very fluid.
-
Download PlantUML from the website:
plantuml.jar -
Place the
plantuml.jarfile into a known directory and add it to the path:cp ~/Downloads/plantuml.jar ~/
-
Write a diagram text file in an extension
.pu(example input/test.pu) - check the user manual for this -
Navigate to the
inputfolder using cd -
Generate the diagram from the terminal using:
java -jar plantuml.jar test.pu -o ../output/
-
Check the generate png file:
output/test.png
-
Write a diagram text file in an extension
.pu(example input/test.pu) - check the user manual for this -
Navigate to the
inputfolder using cd -
Generate the diagram from the terminal using:
java -jar plantuml.jar test.pu -o ../output/
-
Check the generate png file:
output/test.png
-
Declaring participants
If the keyword participant is used to declare a participant, more control on that participant is possible.
The order of declaration will be the (default) order of display.
Using these other keywords to declare participants will change the shape of the participant representation:
- actor
- boundary
- control
- entity
- database
- collections
- queue
' title PlantUML (comment) @startuml participant Participant as Foo actor Actor as Foo1 boundary Boundary as Foo2 control Control as Foo3 entity Entity as Foo4 database Database as Foo5 collections Collections as Foo6 queue Queue as Foo7 Foo -> Foo1 : To actor Foo -> Foo2 : To boundary Foo -> Foo3 : To control Foo -> Foo4 : To entity Foo -> Foo5 : To database Foo -> Foo6 : To collections Foo -> Foo7: To queue @enduml
-
Change arrow style
You can change arrow style by several ways:
- add a final x to denote a lost message
- use \ or / instead of < or > to have only the bottom or top part of the arrow
- repeat the arrow head (for example, >> or //) head to have a thin drawing
- use – instead of - to have a dotted arrow
- add a final "o" at arrow head
- use bidirectional arrow <->
@startuml ' comments as needed ' lost message Bob ->x Alice ' sync message Bob -> Alice ' async message Bob ->> Alice Bob -\ Alice Bob \\- Alice Bob //-- Alice Bob ->o Alice Bob o\\-- Alice ' bidirectional message Bob <-> Alice Bob <->o Alice @enduml
-
Grouping messages
(src)
It is possible to group messages together using the following keywords:
- alt/else
- opt
- loop
- par
- break
- critical
- group, followed by a text to be displayed
It is possible to add a text that will be displayed into the header (for group, see next paragraph 'Secondary group label').
The end keyword is used to close the group.
Note that it is possible to nest groups.
' title PlantUML (comment) @startuml Alice -> Bob: Authentication Request alt successful case Bob -> Alice: Authentication Accepted else some kind of failure Bob -> Alice: Authentication Failure group My own label Alice -> Log : Log attack start loop 1000 times Alice -> Bob: DNS Attack end Alice -> Log : Log attack end end else Another type of failure Bob -> Alice: Please repeat end @enduml
-
Notes on messages
It is possible to put notes on message using the note left or note right keywords just after the message.
You can have a multi-line note using the end note keywords.
@startuml Alice->Bob : hello note left: this is a first note Bob->Alice : ok note right: this is another note Bob->Bob : I am thinking note left a note can also be defined on several lines end note @enduml
-
Divider or separator
If you want, you can split a diagram using == separator to divide your diagram into logical steps.
@startuml == Initialization == Alice -> Bob: Authentication Request Bob --> Alice: Authentication Response == Repetition == Alice -> Bob: Another authentication Request Alice <-- Bob: another authentication Response @enduml
-
Lifeline activation and destruction
The
activateanddeactivateare used to denote participant activation.Once a participant is activated, its lifeline appears.
The activate and deactivate apply on the previous message.
The
destroydenote the end of the lifeline of a participant.@startuml participant User User -> A: DoWork activate A A -> B: << createRequest >> activate B B -> C: DoWork activate C C --> B: WorkDone destroy C B --> A: RequestCreated deactivate B A -> User: Done deactivate A @enduml
-
Participant creation
You can use the
createkeyword just before the first reception of a message to emphasize the fact that this message is actually creating this new object.@startuml Bob -> Alice : hello create Other Alice -> Other : new create control String Alice -> String note right : You can also put notes! Alice --> Bob : ok @enduml
-
Incoming and outgoing messages
You can use incoming or outgoing arrows if you want to focus on a part of the diagram.
Use square brackets to denote the left "[" or the right "]" side of the diagram.
@startuml [-> A: DoWork activate A A -> A: Internal call activate A A ->] : << createRequest >> A<--] : RequestCreated deactivate A [<- A: Done deactivate A @enduml
-
Anchors and duration
With
teozit is possible to add anchors to the diagram and use the anchors to specify duration time.@startuml !pragma teoz true {start} Alice -> Bob : start doing things during duration Bob -> Max : something Max -> Bob : something else {end} Bob -> Alice : finish {start} <-> {end} : some time @enduml
You can use the -Pcommand-line option to specify the pragma:
java -jar plantuml.jar -Pteoz=true
-
Participants encompass
It is possible to draw a box around some participants, using box and end box commands.
You can add an optional title or a optional background color, after the box keyword.
@startuml box "Internal Service" #LightBlue participant Bob participant Alice end box participant Other Bob -> Alice : hello Alice -> Other : hello @enduml
-
Remove foot boxes
You can use the
hide footboxkeywords to remove the foot boxes of the diagram.@startuml hide footbox title Foot Box removed Alice -> Bob: Authentication Request Bob --> Alice: Authentication Response @enduml
-
Style
strictumlTo be conform to strict UML (for arrow style: emits triangle rather than sharp arrowheads), you can use:
@startuml skinparam style strictuml Bob -> Alice : hello Alice -> Bob : ok @enduml
-
Color a group message
It is possible to color a group message:
@startuml Alice -> Bob: Authentication Request alt#Gold #LightBlue Successful case Bob -> Alice: Authentication Accepted else #Pink Failure Bob -> Alice: Authentication Rejected end @enduml
-
Colors
You can use specify fill and line colors either:
- with its standard name or CSS name
- using HEX value (6 digits): #RRGGBB
- using HEX value (8 digits) with alpha compositing or RGBA color model: #RRGGBBaa
- using short HEX value (3 digits): #RGB
@startuml actor Bob #Red/Yellow actor Alice #FF0000/FFFF00 Alice -> Bob : hello @enduml
-
All together :Important:
This example tries to combine all the most important tips stated previously.
@startuml ' ---------- SETUP ---------------- ' strict uml style and hide footboxes skinparam style strictuml hide footbox ' for anchors and duration this may be required (uncomment) ' !pragma teoz true ' ---------- Declaring participants participant Participant as Foo actor Actor as Foo1 boundary Boundary as Foo2 control Control as Foo3 entity Entity as Foo4 database Database as Foo5 collections Collections as Foo6 queue Queue as Foo7 Foo -> Foo1 : To actor Foo -> Foo2 : To boundary Foo -> Foo3 : To control Foo -> Foo4 : To entity Foo -> Foo5 : To database Foo -> Foo6 : To collections Foo -> Foo7: To queue ' -------- Grouping messages ------------------ ' divider or separator ' Encompass actors ' add colors to cases ' add notes == Initialization == box "Internal Service" #LightBlue participant Bob participant Alice end box Alice -> Bob: Authentication Request alt#Gold #LightBlue Successful case Bob -> Alice: Authentication Accepted note left: this is a first note else #Pink Failure Bob -> Alice: Authentication Rejected note right: this is a 2nd note end == Repetition == Alice -> Bob: Another authentication Request Alice <-- Bob: another authentication Response Alice -> Bob: Authentication Request alt successful case Bob -> Alice: Authentication Accepted else some kind of failure Bob -> Alice: Authentication Failure group My own label Alice -> Log : Log attack start loop 1000 times Alice -> Bob: DNS Attack end Alice -> Log : Log attack end end else Another type of failure Bob -> Alice: Please repeat ' ---------- Anchors and duration {start} Alice -> Bob : start doing things during duration Bob -> Max : something Max -> Bob : something else {end} Bob -> Alice : finish {start} <-> {end} : some time ' --------- Incoming and outgoing messages [-> A: DoWork activate A A -> A: Internal call activate A A ->] : << createRequest >> A<--] : RequestCreated deactivate A [<- A: Done deactivate A ' ------- Participant creation --------- Bob -> Alice : hello create Other Alice -> Other : new create control String Alice -> String note right : You can also put notes! Alice --> Bob : ok '-------- Lifeline activation/deactivation participant User User -> A: DoWork activate A A -> B: << createRequest >> activate B B -> C: DoWork activate C C --> B: WorkDone destroy C B --> A: RequestCreated deactivate B A -> User: Done deactivate A @enduml
-
Relations between classes
Class01 <|– Class02 ' extension Class03 *– Class04 ' composition Class05 o– Class06 ' aggregation
-
Visibility
-field1 / private #field2 / protected ~method1() / package private +method2() / public
-
Static and abstract
You can define static or abstract methods or fields using the {static} or {abstract} modifier.These modifiers can be used at the start or at the end of the line. You can also use {classifier} instead of {static}.
-
Notes
You can also define notes using note left of, note right of, note top of, note bottom of keywords.
note top of Flight : default class\ndiagram.You can also define a note on the last defined class using note left, note right, note top, note bottom. A note can be also define alone with the note keywords, then linked to other objects using the .. symbol.Object .. N2 -
Example
-
Define actors and usecases
Actors and use cases can be defined with the reserved keywords
actorandusecase.actor zekinha Susana usecase eat usecase sleep usecase watchSupernatural usecase studyForTestAlso it can be defined on the fly using
:Actor-name:and(usecase-name).Additionally, it can also be used the alias
as, to define shorter names for usecases and actors:Main Admin: as Admin (Use the application) as (Use) User -> (Start) User --> (Use) Admin ---> (Use) -
Direction
The default direction is
top to bottom directionbut it can be changed toleft to right direction. -
Example
<diags/plantuml/usecases/usecase-test>
-
Basic Syntax
[*] = initial state and final state –> = arrows S1 –> S2 : S1 : (can be used for outputs in Moore cycle)
-
Composite State
- Use the
statekeywords and braces{}
- Use the
-
Notes
Notes can be defined using:
note left ofnote right ofnote top ofnote bottom of
- check example on
code/src/makefile



















