How to Document Code¶
The documentation for xAODAnaHelpers uses a slightly non-trivial workflow:
Doxygen parses the header and source files to generate an XML tree of the code
breathe is a sphinx wrapper that enables us to parse the XML tree from doxygen
sphinx is what produces the various output formats such as html, latex, e-pub from source code comments
ReadTheDocs.org uses
doxygen
,breathe
, andsphinx
to automatically produce our documentation everytimemain
changes.
Our documentation is automatically generated for us so we will always guarantee that our documentation is up-to-date for all users.
The aim of this document is to help you get started with producing your own documentation locally to help resolve errors, typos, and make sure you’re formatting it the way that you want before pushing it to our github repo.
Setting it up Locally¶
Locally, we are going to need doxygen to do the initial parsing. Note that out of the box without doxygen, we can parse python scripts, such as xAH_run.py API Reference, which are included as part of xAODAnaHelpers. However, if we wish to have all of our C++ code’s documentation included, we will need doxygen to do parse it.
Doxygen¶
Get doxygen however you want. For Macs, we can use:
brew install doxygen
to install it. At this point, one should be able to generate the XML tree by navigating to the docs
folder and running doxygen
with no arguments:
cd docs
doxygen
since we provide a Doxyfile
in the docs
directory with the correct configurations.
Python Virtual Environment¶
Next, I suggest setting up a python virtual environment. Luckily, this solution is the hardest part. Most (rational) people use virtualenvwrapper to manage my python dependencies and workspace. It is assumed you already have pip.
To get the entire functionality of venvwrapper
, we just need to grab the package and update our environment when we want to use it:
pip install virtualenvwrapper
echo "source /usr/local/bin/virtualenvwrapper.sh" >> ~/.bash_profile
Note
Don’t forget to source your profile if you’re going to use the same shell:
source ~/.bash_profile
From now on, we will have commands like mkvirtualenv
, workon
, and rmvirtualenv
in our shell. As a first-time user, you haven’t made a virtual environment yet, so the first thing we do is make one:
mkvirtualenv xAH
This will also automatically call workon xAH
. This is something we will always run in the future to enter the virtual environment.
Note
If you ever forget the name of the virtual environment you made, just run workon
without any arguments. There is also tab completion.
Python Packages¶
Note
If you choose to use a virtual environment, enter it workon xAH
This is super easy. We provide a requirements.txt
file:
cd docs
pip install -r requirements.txt
which will install all the required packages for you. As of the time of this document, this contains the following packages:
alabaster==0.7.12
Babel==2.9.1
beautifulsoup4==4.8.1
breathe==4.35.0
bs4==0.0.1
certifi==2024.7.4
chardet==3.0.4
docutils==0.15.2
exhale==0.2.4
idna==3.7
imagesize==1.1.0
Jinja2==3.1.4
lxml==4.9.1
MarkupSafe==2.1.3
packaging==19.2
Pygments==2.15.0
pyparsing==2.4.5
pytz==2019.3
PyYAML==6.0
requests==2.32.2
six==1.13.0
snowballstemmer==2.0.0
soupsieve==1.9.5
Sphinx==4.5.0
sphinx-argparse==0.2.5
sphinx-rtd-theme==0.4.3
sphinxcontrib-applehelp==1.0.1
sphinxcontrib-devhelp==1.0.1
sphinxcontrib-htmlhelp==2.0.0
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.2
sphinxcontrib-serializinghtml==1.1.5
urllib3==1.26.19
Generate Docs Locally¶
Now that we have doxygen
and all of the required python packages installed, all you need to do now is process everything:
cd docs
make clean
doxygen
make html
open _build/html/index.html
and we’re good to go. Sphinx provides a Makefile
in docs/
to make the html generation much easier to work with.
You may not always run all of these pieces each time you generate documentation. For example, if you need to make a change to the header/source files of any kind, you will need to re-run doxygen
. In the rare case that the html generation isn’t working right, you might want to run make clean
so you start over again. If you’re only changing the reStructuredText (rst) files in docs/
you might only ever need to run make html
. All in all, it doesn’t take more than 10-15 seconds to generate the necessary documentation.
Documenting Code¶
In most cases, we will want to follow the reStructuredText directives and formatting for doing the code documentation. We just want to use doxygen
+ breathe
to expose those comments to sphinx
to parse and display correctly. In what follows, we provide a set of guidelines (really, examples) to make it easier to document our code specifically.
Note
All comments for a given class, function, variable should be prior to the given item you’re adding documentation for.
If you have a question about how to do something, google it in the context of reStructuredText or ask on the mailing list. Also have a look through most of our source code and compare it to the docs to figure out how we do something.
One-Line Comments¶
One-line comments are very useful in cases where we do not have much to say about something, perhaps because it is a rather trivial item:
/** @brief generically the main name assigned to all histograms */
std::string m_name;
which will render as
-
std::string HistogramManager::m_name
generically the main name assigned to all histograms
Block Comments¶
Block comments are very useful in all other cases. When in doubt, you can always make a block comment with just a single line, even for a variable. The flexibility allows us to include a lot more detail and formatting such as tables and latex:
/**
@brief Destructor, allows the user to delete histograms that are not being recorded.
*/
virtual ~HistogramManager();
which will render as
-
virtual HistogramManager::~HistogramManager()
Destructor, allows the user to delete histograms that are not being recorded.
Doxygen rst
directive¶
To tell doxygen
and breathe
that a given block of text should be considered as reStructuredText, we simply need to wrap it:
@rst
This is now inside a doxygen directive that tells doxygen not to parse it, so that breathe can parse it for Sphinx.
@endrst
which will render as expected if we were writing it inside a standard .rst
file. As usual, we have an example:
/**
@brief This is used by any class extending to pre-define a set of histograms to book by default.
@rst
.. note:: The expectation is that the user does not directly use this class but rather inherits from it.
We expect the user to create a new group of histograms, such as for jets::
class JetHists : public HistogramManager
{
public:
JetHists(std::string name, std::string detailStr);
virtual ~JetHists() ;
StatusCode initialize();
StatusCode execute( const xAOD::JetContainer* jets, float eventWeight, int pvLoc = -1);
StatusCode execute( const xAOD::Jet* jet, float eventWeight, int pvLoc = -1 );
using HistogramManager::book; // make other overloaded version of book() to show up in subclass
using HistogramManager::execute; // overload
};
The above example is taken from our implementation in :cpp:class:`JetHists`.
@endrst
*/
class HistogramManager {};
which will render as
-
class HistogramManager
This is used by any class extending to pre-define a set of histograms to book by default.
We expect the user to create a new group of histograms, such as for jets:
class JetHists : public HistogramManager { public: JetHists(std::string name, std::string detailStr); virtual ~JetHists() ; bool m_debug; StatusCode initialize(); StatusCode execute( const xAOD::JetContainer jets, float eventWeight, int pvLoc = -1); StatusCode execute( const xAOD::Jet jet, float eventWeight, int pvLoc = -1 ); using HistogramManager::book; // make other overloaded version of book() to show up in subclass using HistogramManager::execute; // overload };
The above example is taken from our implementation in
JetHists
.Note
The expectation is that the user does not directly use this class but rather inherits from it.
Subclassed by MetHists
For everything else…¶
These cover the general basics of how to document code for xAODAnaHelpers. Everything else is specific to how doxygen and Sphinx and breathe work. Most of these are well-supported with a large community, so googling is always very helpful here. Otherwise, feel free to ask on the mailing list.