Skip to content

Instantly share code, notes, and snippets.

@dorchard
Created August 9, 2024 15:54
Show Gist options
  • Save dorchard/378a6f47f8e60d2873b2e41ff357a798 to your computer and use it in GitHub Desktop.
Save dorchard/378a6f47f8e60d2873b2e41ff357a798 to your computer and use it in GitHub Desktop.
Quick and dirty script to turn a Makefile into a dependency graph for object file (.o) dependencies
# Run with
#
# python graph.py makefilename
#
# which generates dependencies.dot which can be compiled with graphviz
# to a png via:
#
# dot -Tpng dependencies.dot -o dependencies.png
#
#
import re
import sys
def parse_makefile(filename):
"""Parse the Makefile and extract targets and their dependencies."""
with open(filename, 'r') as f:
lines = f.readlines()
dependency_graph = {}
# Unsplit continuation lines
lines_new = []
i = 0
while (i < (len(lines)-1)):
line = lines[i].strip()
new_line = ""
line_next = ""
while len(line) > 0 and line[-1] == "\\":
line_next = lines[i+1].strip()
new_line = new_line + " " + line[0:-1]
line = line_next
i+=1
new_line = new_line + " " + line
lines_new.append(new_line)
i+=1
target_pattern = re.compile(r'^([a-zA-Z0-9\_]+)\.o(\s)*:\s*(.*)$')
for line in lines_new:
match = target_pattern.match(line.strip())
if match:
target, space, dependencies = match.groups()
dependencies = dependencies.split()
dependency_graph[target] = dependencies
print(target + ": " + str(dependencies))
return dependency_graph
def generate_dot(dependency_graph, output_filename):
"""Generate a DOT file from the dependency graph."""
with open(output_filename, 'w') as f:
f.write("digraph MakefileDependencies {\n")
f.write(" rankdir=LR;\n") # Left to right layout
for target, dependencies in dependency_graph.items():
for dep in dependencies:
f.write(f' "{dep}" -> "{target}.o";\n')
f.write("}\n")
def main(args):
makefile = args[1] # Input Makefile
dotfile = "dependencies.dot" # Output DOT file
dependency_graph = parse_makefile(makefile)
generate_dot(dependency_graph, dotfile)
print(f"DOT file generated: {dotfile}")
if __name__ == "__main__":
main(sys.argv)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment