Saturday, January 22, 2011

Doxygen: Step-by-step

I've started to use Doxygen to document a small little experimental library of mine.  Here are the steps I would use to document in retrospect.

First step was to create a header file for the library.  Call it myLibrary.h.  In addition to including any files that should be publicly available, I put in a nice piece of documentation to specify what the library does.

/*! \mainpage
My library does something.  It's awesome.


Here are two examples:
- \subpage AwesomeDemo1
- \subpage AwesomeDemo2
*/

This just sets up our main page.  It states what the library does.  I have two example pages.  One of them is called AwesomeDemo1 and the other is AwesomeDemo2.  The dash denotes that this is a list of items.

Ok, that's a good first step.  Now, let's look at AwesomeFunctionality.h.  All of the following are fragments from AwesomeFunctionality.h with some comments mixed in to explain what's going on:

/*! \file AwesomeFunctionality.h
\brief This is awesome
Awesomeness is achieved by doing awesome things.  These awesome things arise from the awesome code made available in this header file.
*/

This declares what the file does.  What should we find in this file?!  It sort of emphasizes the simple fact that no file should be a catch-all for garbage that belongs elsewhere.  Give your file a purpose!  In Doxygen, when you generate a file list, the text after "brief" becomes a short description of the file (call it an overview so someone knows if they want to know more).  The text afterwards is for once the reader decides to get more information.

/*! \page AwesomeDemo1 First Awesome Demo


Here's something awesome:
\code
Awesome *x = new Awesome();
\endcode
*/

Recall our AwesomeDemo1?  Here we name it "First Awesome Demo", which will be linked to from the main page (and also serves as the name for this page).  Following is the text on the page, and a piece of sample code.

I tend to learn from example, and Doxygen will link the sample code to the documented classes.  Be clear and concise about what the demo does with little added fluff and your reader will be happy.

/*! \defgroup AwesomeGroup The awesomeness begins here
This group contains a set of things that are awesome and you should look at!
*/

This defines a module that the user will see as "The awesomeness begins here".  You might want to name it something reasonable, such as "Compositing Capabilities".  Imagine if you're a reader that wants to do "awesome things".  Then if functions and classes related to "awesome thing" can be found in a single place, it makes the reader's life easier.

Finally, let's get to the interesting part:

//! Does something awesome
/*! \ingroup AwesomeGroup
  This is an awesome thing!


  Look at the function \ref AwesomeFunction for more details!
*/
class Awesome
{
//! Awesome data member
int m_awesome;
};

Finally, some code.  This is just a header file, so it's just a skeleton.  The first comment is the brief.  "Does something awesome" should give the reader a clear idea of what the object does.  The longer documentation, using C-style comments (don't forget the !), first specifies that this has something to do with the AwesomeGroup.  Then we give a longer description of what the object does.  Notice we use "\ref", it will make a link to the function called AwesomeFunction.  Normally, for classes, links are automatically created.

For each member within the class, we document them as our next example.  If there isn't much, we just leave in the brief comment.

//! Initializes the awesomeness
/*! \ingroup AwesomeGroup
\param[in] something something or other
\pre The awesomeness has not been initialized 
\post The awesomeness is initialized
\exception If the awesomeness was already initialized
\return An awesome integer
*/
int AwesomeFunction(int something)


Now...  for methods within a class, normally I wouldn't use "\ingroup".  The rest is to be used judiciously.  Your goal is to give enough information so that the object may be used without drowning the user with too much information.

The parameters can be named as either [in], [out], or [in,out].  Specify if data will change or not.  Const should be used for [in] though.

The pre-condition, post-condition, and exception parts should be used judiciously.  Or so I believe.  It is nice to have them though.

Return - well, it's always a good idea to say what that is.

I used the GUI front-end.  Upon compiling the documentation, I did not include any private headers or source (.cpp) files.  Essentially, only the public documentation should be easy to get.  Private documentation should be accessible within the headers but more challenging to get at.

As a reader, you must have realized that most of my efforts have been for the reader.  And the logic is quite simple - the documentation is for another person - a future reader.  Documentation simply makes your project more accessible to others.  Something that is essential for open-source projects.  To be used, it has to be easy, and require minimal effort on the part of the user (regardless of functionality).

No comments:

Post a Comment