Created
August 9, 2024 15:54
-
-
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
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
# 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