From 65bbfdb8123b4ea3e15b967b5b03b4b4335c0040 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Fri, 21 Feb 2014 03:16:25 +0100 Subject: [PATCH] Add a tools that detects include cycles in the Dolphin codebase. --- Tools/find-includes-cycles.py | 80 +++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100755 Tools/find-includes-cycles.py diff --git a/Tools/find-includes-cycles.py b/Tools/find-includes-cycles.py new file mode 100755 index 0000000000..c4139cd7a0 --- /dev/null +++ b/Tools/find-includes-cycles.py @@ -0,0 +1,80 @@ +#! /usr/bin/env python + +''' +Run this script from Source/Core/ to find all the #include cycles. +''' + +import subprocess + +def get_local_includes_for(path): + lines = open(path).read().split('\n') + includes = [l.strip() for l in lines if l.strip().startswith('#include')] + return [i.split()[1][1:-1] for i in includes if '"' in i.split()[1]] + +def find_all_files(): + '''Could probably use os.walk, but meh.''' + f = subprocess.check_output(['find', '.', '-name', '*.h'], + universal_newlines=True).strip().split('\n') + return [p[2:] for p in f] + +def make_include_graph(): + return { f: get_local_includes_for(f) for f in find_all_files() } + +def strongly_connected_components(graph): + """ + Tarjan's Algorithm (named for its discoverer, Robert Tarjan) is a graph theory algorithm + for finding the strongly connected components of a graph. + + Based on: http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm + """ + + index_counter = [0] + stack = [] + lowlinks = {} + index = {} + result = [] + + def strongconnect(node): + # set the depth index for this node to the smallest unused index + index[node] = index_counter[0] + lowlinks[node] = index_counter[0] + index_counter[0] += 1 + stack.append(node) + + # Consider successors of `node` + try: + successors = graph[node] + except: + successors = [] + for successor in successors: + if successor not in lowlinks: + # Successor has not yet been visited; recurse on it + strongconnect(successor) + lowlinks[node] = min(lowlinks[node],lowlinks[successor]) + elif successor in stack: + # the successor is in the stack and hence in the current strongly connected component (SCC) + lowlinks[node] = min(lowlinks[node],index[successor]) + + # If `node` is a root node, pop the stack and generate an SCC + if lowlinks[node] == index[node]: + connected_component = [] + + while True: + successor = stack.pop() + connected_component.append(successor) + if successor == node: break + component = tuple(connected_component) + # storing the result + result.append(component) + + for node in graph: + if node not in lowlinks: + strongconnect(node) + + return result + +if __name__ == '__main__': + comp = strongly_connected_components(make_include_graph()) + for c in comp: + if len(c) != 1: + print(c)