find-includes-cycles.py 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. #! /usr/bin/env python
  2. '''
  3. Run this script from Source/Core/ to find all the #include cycles.
  4. '''
  5. import subprocess
  6. def get_local_includes_for(path):
  7. lines = open(path).read().split('\n')
  8. includes = [l.strip() for l in lines if l.strip().startswith('#include')]
  9. return [i.split()[1][1:-1] for i in includes if '"' in i.split()[1]]
  10. def find_all_files():
  11. '''Could probably use os.walk, but meh.'''
  12. f = subprocess.check_output(['find', '.', '-name', '*.h'],
  13. universal_newlines=True).strip().split('\n')
  14. return [p[2:] for p in f]
  15. def make_include_graph():
  16. return { f: get_local_includes_for(f) for f in find_all_files() }
  17. def strongly_connected_components(graph):
  18. """
  19. Tarjan's Algorithm (named for its discoverer, Robert Tarjan) is a graph theory algorithm
  20. for finding the strongly connected components of a graph.
  21. Based on: http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
  22. """
  23. index_counter = [0]
  24. stack = []
  25. lowlinks = {}
  26. index = {}
  27. result = []
  28. def strongconnect(node):
  29. # set the depth index for this node to the smallest unused index
  30. index[node] = index_counter[0]
  31. lowlinks[node] = index_counter[0]
  32. index_counter[0] += 1
  33. stack.append(node)
  34. # Consider successors of `node`
  35. try:
  36. successors = graph[node]
  37. except:
  38. successors = []
  39. for successor in successors:
  40. if successor not in lowlinks:
  41. # Successor has not yet been visited; recurse on it
  42. strongconnect(successor)
  43. lowlinks[node] = min(lowlinks[node],lowlinks[successor])
  44. elif successor in stack:
  45. # the successor is in the stack and hence in the current strongly connected component (SCC)
  46. lowlinks[node] = min(lowlinks[node],index[successor])
  47. # If `node` is a root node, pop the stack and generate an SCC
  48. if lowlinks[node] == index[node]:
  49. connected_component = []
  50. while True:
  51. successor = stack.pop()
  52. connected_component.append(successor)
  53. if successor == node: break
  54. component = tuple(connected_component)
  55. # storing the result
  56. result.append(component)
  57. for node in graph:
  58. if node not in lowlinks:
  59. strongconnect(node)
  60. return result
  61. if __name__ == '__main__':
  62. comp = strongly_connected_components(make_include_graph())
  63. for c in comp:
  64. if len(c) != 1:
  65. print(c)