graph-header-logs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. #! /usr/bin/python2
  2. import os.path
  3. import sys
  4. import shlex
  5. import re
  6. from headerutils import *
  7. header_roots = { }
  8. extra_edges = list()
  9. verbose = False
  10. verbosity = 0
  11. nodes = list()
  12. def unpretty (name):
  13. if name[-2:] == "_h":
  14. name = name[:-2] + ".h"
  15. return name.replace("_", "-")
  16. def pretty_name (name):
  17. name = os.path.basename (name)
  18. return name.replace(".","_").replace("-","_").replace("/","_").replace("+","_");
  19. depstring = ("In file included from", " from")
  20. # indentation indicates nesting levels of included files
  21. ignore = [ "coretypes_h",
  22. "insn_modes_h",
  23. "signop_h",
  24. "wide_int_h",
  25. "wide_int_print_h",
  26. "insn_modes_inline_h",
  27. "machmode_h",
  28. "double_int_h",
  29. "real_h",
  30. "fixed_value_h",
  31. "hash_table_h",
  32. "statistics_h",
  33. "ggc_h",
  34. "vec_h",
  35. "hashtab_h",
  36. "inchash_h",
  37. "mem_stats_traits_h",
  38. "hash_map_traits_h",
  39. "mem_stats_h",
  40. "hash_map_h",
  41. "hash_set_h",
  42. "input_h",
  43. "line_map_h",
  44. "is_a_h",
  45. "system_h",
  46. "config_h" ]
  47. def process_log_file (header, logfile):
  48. if header_roots.get (header) != None:
  49. print "Error: already processed log file: " + header + ".log"
  50. return
  51. hname = pretty_name (header)
  52. header_roots[hname] = { }
  53. sline = list();
  54. incfrom = list()
  55. newinc = True
  56. for line in logfile:
  57. if len (line) > 21 and line[:21] in depstring:
  58. if newinc:
  59. incfrom = list()
  60. newinc = False
  61. fn = re.findall(ur".*/(.*?):", line)
  62. if len(fn) != 1:
  63. continue
  64. if fn[0][-2:] != ".h":
  65. continue
  66. n = pretty_name (fn[0])
  67. if n not in ignore:
  68. incfrom.append (n)
  69. continue
  70. newinc = True
  71. note = re.findall (ur"^.*note: (.*)", line)
  72. if len(note) > 0:
  73. sline.append (("note", note[0]))
  74. else:
  75. err_msg = re.findall (ur"^.*: error: (.*)", line)
  76. if len(err_msg) == 1:
  77. msg = err_msg[0]
  78. if (len (re.findall("error: forward declaration", line))) != 0:
  79. continue
  80. path = re.findall (ur"^(.*?):.*error: ", line)
  81. if len(path) != 1:
  82. continue
  83. if path[0][-2:] != ".h":
  84. continue
  85. fname = pretty_name (path[0])
  86. if fname in ignore or fname[0:3] == "gt_":
  87. continue
  88. sline.append (("error", msg, fname, incfrom))
  89. print str(len(sline)) + " lines to process"
  90. lastline = "note"
  91. for line in sline:
  92. if line[0] != "note" and lastline[0] == "error":
  93. fname = lastline[2]
  94. msg = lastline[1]
  95. incfrom = lastline[3]
  96. string = ""
  97. ofname = fname
  98. if len(incfrom) != 0:
  99. for t in incfrom:
  100. string = string + t + " : "
  101. ee = (fname, t)
  102. if ee not in extra_edges:
  103. extra_edges.append (ee)
  104. fname = t
  105. print string
  106. if hname not in nodes:
  107. nodes.append(hname)
  108. if fname not in nodes:
  109. nodes.append (ofname)
  110. for y in incfrom:
  111. if y not in nodes:
  112. nodes.append (y)
  113. if header_roots[hname].get(fname) == None:
  114. header_roots[hname][fname] = list()
  115. if msg not in header_roots[hname][fname]:
  116. print string + ofname + " : " +msg
  117. header_roots[hname][fname].append (msg)
  118. lastline = line;
  119. dotname = "graph.dot"
  120. graphname = "graph.png"
  121. def build_dot_file (file_list):
  122. output = open(dotname, "w")
  123. output.write ("digraph incweb {\n");
  124. for x in file_list:
  125. if os.path.exists (x) and x[-4:] == ".log":
  126. header = x[:-4]
  127. logfile = open(x).read().splitlines()
  128. process_log_file (header, logfile)
  129. elif os.path.exists (x + ".log"):
  130. logfile = open(x + ".log").read().splitlines()
  131. process_log_file (x, logfile)
  132. for n in nodes:
  133. fn = unpretty(n)
  134. label = n + " [ label = \"" + fn + "\" ];"
  135. output.write (label + "\n")
  136. if os.path.exists (fn):
  137. h = open(fn).read().splitlines()
  138. for l in h:
  139. t = find_pound_include (l, True, False)
  140. if t != "":
  141. t = pretty_name (t)
  142. if t in ignore or t[-2:] != "_h":
  143. continue
  144. if t not in nodes:
  145. nodes.append (t)
  146. ee = (t, n)
  147. if ee not in extra_edges:
  148. extra_edges.append (ee)
  149. depcount = list()
  150. for h in header_roots:
  151. for dep in header_roots[h]:
  152. label = " [ label = "+ str(len(header_roots[h][dep])) + " ];"
  153. string = h + " -> " + dep + label
  154. output.write (string + "\n");
  155. if verbose:
  156. depcount.append ((h, dep, len(header_roots[h][dep])))
  157. for ee in extra_edges:
  158. string = ee[0] + " -> " + ee[1] + "[ color=red ];"
  159. output.write (string + "\n");
  160. if verbose:
  161. depcount.sort(key=lambda tup:tup[2])
  162. for x in depcount:
  163. print " ("+str(x[2])+ ") : " + x[0] + " -> " + x[1]
  164. if (x[2] <= verbosity):
  165. for l in header_roots[x[0]][x[1]]:
  166. print " " + l
  167. output.write ("}\n");
  168. files = list()
  169. dohelp = False
  170. edge_thresh = 0
  171. for arg in sys.argv[1:]:
  172. if arg[0:2] == "-o":
  173. dotname = arg[2:]+".dot"
  174. graphname = arg[2:]+".png"
  175. elif arg[0:2] == "-h":
  176. dohelp = True
  177. elif arg[0:2] == "-v":
  178. verbose = True
  179. if len(arg) > 2:
  180. verbosity = int (arg[2:])
  181. if (verbosity == 9):
  182. verbosity = 9999
  183. elif arg[0:1] == "-":
  184. print "Unrecognized option " + arg
  185. dohelp = True
  186. else:
  187. files.append (arg)
  188. if len(sys.argv) == 1:
  189. dohelp = True
  190. if dohelp:
  191. print "Parses the log files from the reduce-headers tool to generate"
  192. print "dependency graphs for the include web for specified files."
  193. print "Usage: [-nnum] [-h] [-v[n]] [-ooutput] file1 [[file2] ... [filen]]"
  194. print " -ooutput : Specifies output to output.dot and output.png"
  195. print " Defaults to 'graph.dot and graph.png"
  196. print " -vn : verbose mode, shows the number of connections, and if n"
  197. print " is specified, show the messages if # < n. 9 is infinity"
  198. print " -h : help"
  199. else:
  200. print files
  201. build_dot_file (files)
  202. os.system ("dot -Tpng " + dotname + " -o" + graphname)