Graphing Fortran Projects
Currently, I am refactoring the code that I work on and I wanted to see how the different modules
depend on each other. Doxygen generates graphs of how individual functions and routines call each
other, which is pretty nifty, but it doesn’t seem to do it for the modules. Looking into how doxygen
generates these graphs, I found out it uses the graphviz package, in particular dot
.
Dot is a very simple language used to describe graphs. Wikipedia has some nice examples.
I wrote a short python function to crudely extract the module dependencies from my code and put them into a dot graph:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import re | |
def build_graph(files,exclude=['hdf5','h5lt','mpi']): | |
"""Build a dot graph of the Fortran modules in a list of files, | |
excluding modules named in the list exclude""" | |
# Start the graph | |
graph = "digraph G {\n" | |
deps = {} | |
p = re.compile("^(?:module|program) ([a-zA-Z0-9_]*)", | |
re.IGNORECASE+re.MULTILINE) | |
for mod in files: | |
with open(mod,'r') as f: | |
contents = f.read() | |
# Get the true module name | |
# Careful! It only gets the first module in the file! | |
mod_name = re.search(p,contents).group(1) | |
# Find all the USE statements and get the module | |
deps[mod_name] = re.findall("USE ([a-zA-Z0-9_]*)",contents) | |
for k in deps: | |
# Remove duplicates and unwanted modules | |
deps[k] = list(set(deps[k]) - set(exclude)) | |
for v in deps[k]: | |
# Add the edges to the graph | |
edge = k + " -> " + v + ";\n" | |
graph = graph + edge | |
# Close the graph and return it | |
graph = graph + "}" | |
return graph | |
Writing the output of this function to a file and running dot
on it produces lovely images like
this:
…I’m not sure if my refactoring is making it better or worse.