Posts Tagged ‘Doxygen’


Saturday, May 2nd, 2009 Nigel Jones

Today’s post was inspired by a new version notice from Dimitri van Heesch concerning his great documentation generator tool doxygen. If you aren’t aware of doxygen, then I strongly recommend reading about it and then using it.

So what is Doxygen exactly? Well it has a lot of capabilities, but in a nutshell it can parse your code (C, C++, Java and a host of others not usually used in the embedded space) and from it generate a very nice hyper-linked documentation set. It does this in part by looking for what I’ll call control directives embedded in comments. Now what I particularly like about Doxygen is that it allows you to trade off between adding control directives while still making your comments readable. For example, at one extreme you can do nothing special to your code and still end up with a reasonable documentation set. On the other extreme, you can embed so many control directives into your comments that the only sane way to read the comments is via Doxygen; however the documentation will be truly impressive! In my case, I find control directives to be very distracting, and so I opt to use a minimal set that doesn’t offend my sensibilities but still gives me very useful results.

So why do I do this? Well while this documentation set is very nice in its own right, I actually find it very useful in improving my code. As remarkable a claim as this is, it’s easily substantiated. Here are a few examples:

Call Trees

One of the very nice add-ons to Doxygen is graphviz. Using graphviz, Doxygen will generate call trees for all of your functions. I often find this very illuminating – both at a macro level and also a micro level. At the macro level, if I see a call tree that looks like your average two years old’s art work, then it’s a clear indication of muddled thinking – and impending doom. At the micro level it allows you to spot some errors. For example consider this code fragment, that is intended to update a parameter in an EEPROM data structure, together with its backup copy:

void params_NosChargesSet(uint16_t nos_charges)
 Factory_Params1.n_charges = nos_charges;
 Factory_Params2.n_charges = nos_charges;

I found the bug in this code not by testing it, but by simply browsing the Doxygen documentation and noticing that the call tree for this function was incorrect. What I liked about this is that this kind of bug is very difficult to detect through testing, and will not be noticed by static analysis. It was however clear as day by looking at its call tree.

Missing documentation

Sometimes when I’m anxious to solve ‘the real problem’, I find that I’m not as diligent as I should be about describing the use of manifest constants, variables etc. As a result I’ll sometimes end up with code that looks like this:

#define SHORT_TERM_BUF_SIZE (8U) /**< meaningful comment */
#define LONG_TERM_BUF_SIZE (32U)

You’ll notice that LONG_TERM_BUF_SIZE has no comment associated with it. However, it’s “obvious” what its use is because of the comment associated with SHORT_TERM_BUF_SIZE that immediately precedes it. Well when you generate the Doxygen documentation, and you click on the hyperlink associated with LONG_TERM_BUF_SIZE, guess what – no description. While some may think that this is a weakness in Doxygen, I actually think it’s a major strength. Here’s why:

  • My coding standard requires me to provide a comment for all manifest constants. Thus it is reminding me of the error of my ways.
  • Someone new coming to the code will typically be overwhelmed by what they are faced with. Having an ‘implicit comment’ is just one more hurdle for them to overcome. Thus Doxygen is accurately reflecting what someone will see when they read your code.

Is Doxygen perfect? No it’s not. It often hangs when I run it. However to be fair, that’s usually because I haven’t played by the rules. Despite this I find it a useful tool in my arsenal. I recommend you take a look at it.