I always wished of having a easy method to generate a “call graph” ( aka control flow graph ) depicting the calling relationship between the subroutines of a source code( in my case for code in C language). Now that i finally found a method ( and most importantly time to experiment it out ); i am documenting the steps in this blog. I used Doxygen coupled with Graphviz to get this done.
Firstly, a big thanks to the contributors of this page ( https://en.wikipedia.org/wiki/Call_graph ) in Wikipedia where i got to see the multiple options to get this done. And of-course went through tips from this post of stackoverflow : https://stackoverflow.com/questions/517589/tools-to-get-a-pictorial-function-call-graph-of-code.
Of the various options to get this done i decided to do the “Doxygen”(http://www.doxygen.org) way because i had good vibes about this tool! Also given that couple of projects that i worked with earlier had used Doxygen; i had some understanding on how it worked. And most importantly, your code need “NOT” have used “Doxygen style comments” for the call graph feature to work. I am sure many of you’ll heave a sigh of relief; as did i ;-).
Now the natural companion for Doxygen to get this work done is Graphviz ( Graph Visualization Software : http://www.graphviz.org/ ).
The reason these two tools are related is that Graphviz provides “dot” tool which is used by “Doxygen” to generate call graph.
Depending upon your requirement you could generate :
- class diagrams
- class inheritance graphs
- direct and indirect include dependencies of files
- caller and call graph for subroutines
Now with this background, let me jump into how to set this up and get it running :
Please note :
- This is what i did on MacOS 10.12.5. Apart from the installation stuff; i think other steps would work the same way for Linux.
- I rely heavily on brew for getting developer packages into Mac; and i see it does a great job. If you have not yet used it you can get more details here : https://brew.sh/
1. Install Graphviz
==> brew install graphviz
2. Install Doxygen
==> brew install doxygen
3. Go the parent directory of you code-base; and generate a Doxygen configuration file. By default the configuration file gets the name of Doxyfile
==> doxygen -g
Configuration file `Doxyfile’ created.
Now edit the configuration file and enter
to generate the documentation for your project
4. Now customize the configuration file for graph generation and other personalized needs :
The configuration file is a plain text file; with “TAG“s to tailor the setting of Doxygen for a specific project. All the TAGs are pre-filled with default values; you have to just edit the value of the TAG which you want to change from the default behavior.
I made the changes to these TAGs for the reasons mentioned in statements beginning with hashes(#) :
( Listed below in the order of importance i though they are of )
#Only if this option is set, Doxygen uses the “dot” tool
#of Graphviz to generate graphs
HAVE_DOT = YES
# To make Doxygen generate a call dependency graph
# for every global function or class method
CALL_GRAPH = YES
# To make Doxygen generate a caller dependency graph
# for every global function or class method
CALLER_GRAPH = YES
# Since you’ll mostly be having newer version of dot(>1.8.10) ( in my case it was 2.38.0 )
# enabling this option will make dot run faster
DOT_MULTI_TARGETS = YES
# Since all of my code was in C, i enabled this option.
# and i see that Doxygen run completed sooner for my case after this option was enabled.
OPTIMIZE_OUTPUT_FOR_C = YES
# Since my code did not have any Doxygen style comments,
# i enabled this tag
EXTRACT_ALL = YES
# If you code is spread across sub-directories,
# enabling this option will make Doxygen walk through code in all of them
RECURSIVE = YES
# If you don’t need the LaTeX output;
# better disable this option; as it saves a lot of time during graph generation
GENERATE_LATEX = NO
# Modified the graph image file format to be svg ( default is png )
DOT_IMAGE_FORMAT = svg
# These other tags i enabled; don’t matter much for C code i guess
EXTRACT_PACKAGE = YES
EXTRACT_STATIC = YES
EXTRACT_LOCAL_CLASSES = YES
STRICT_PROTO_MATCHING = YES
5. Now that the configuration options have been set up as per your need; let me show you a sample execution and output
Searching for include files…
Searching for example files…
Searching for images…
.. <output trucated> ..
Patching output file 12/13
Patching output file 13/13
lookup cache used 21/65536 hits=107 misses=21
It will generate “html” directory in same path where it was executed.
Open the “index.html” file located inside the “html” sub-folder in a web-browser of your choice.
6. You’ll find the file dependecy and call graph ( and caller graph too ) by clicking on the filename under the Files tab of the output.
Sample screenshots from my example run :
A. File dependency view of File “tree_b.c” under Files tab.
In the end, i’ll highlight the fact that these call graphs are static and are derived from the source code.
This would be suitable for most cases if you are interested to understand the overall code-flow and code-layout of some new project you are thrown in to work on :-).
However, if you are debugging some complex issue and are interested to generate runtime call graph based on the execution path of a program; you could take the help of certain run time profilers with call graph functionality.