diff contrib/header-tools/graph-header-logs @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/header-tools/graph-header-logs	Fri Oct 27 22:46:09 2017 +0900
@@ -0,0 +1,230 @@
+#! /usr/bin/python2
+import os.path
+import sys
+import shlex
+import re
+
+from headerutils import *
+
+header_roots = { }
+extra_edges = list()
+verbose = False
+verbosity = 0
+nodes = list()
+
+def unpretty (name):
+  if name[-2:] == "_h":
+    name = name[:-2] + ".h"
+  return name.replace("_", "-")
+
+def pretty_name (name):
+  name = os.path.basename (name)
+  return name.replace(".","_").replace("-","_").replace("/","_").replace("+","_");
+
+depstring = ("In file included from", "                 from")
+
+# indentation indicates nesting levels of included files
+ignore = [ "coretypes_h",
+             "insn_modes_h",
+             "signop_h",
+             "wide_int_h",
+             "wide_int_print_h",
+             "insn_modes_inline_h",
+             "machmode_h",
+             "double_int_h",
+             "real_h",
+             "fixed_value_h",
+             "hash_table_h",
+               "statistics_h",
+               "ggc_h",
+               "vec_h",
+               "hashtab_h",
+               "inchash_h",
+               "mem_stats_traits_h",
+               "hash_map_traits_h",
+               "mem_stats_h",
+               "hash_map_h",
+             "hash_set_h",
+             "input_h",
+               "line_map_h",
+             "is_a_h",
+           "system_h",
+           "config_h" ]
+
+def process_log_file (header, logfile):
+  if header_roots.get (header) != None:
+    print "Error: already processed log file: " + header + ".log"
+    return
+  hname = pretty_name (header)
+  header_roots[hname] = { }
+  
+  sline = list();
+  incfrom = list()
+  newinc = True
+  for line in logfile:
+    if len (line) > 21 and line[:21] in depstring:
+      if newinc:
+        incfrom = list()
+        newinc = False
+      fn = re.findall(ur".*/(.*?):", line)
+      if len(fn) != 1:
+        continue
+      if fn[0][-2:] != ".h":
+        continue
+      n = pretty_name (fn[0])
+      if n not in ignore:
+        incfrom.append (n)
+      continue
+    newinc = True
+    note = re.findall (ur"^.*note: (.*)", line)
+    if len(note) > 0:
+      sline.append (("note", note[0]))
+    else:
+      err_msg = re.findall (ur"^.*: error: (.*)", line)
+      if len(err_msg) == 1:
+        msg = err_msg[0]
+        if (len (re.findall("error: forward declaration", line))) != 0:
+          continue
+        path = re.findall (ur"^(.*?):.*error: ", line)
+        if len(path) != 1:
+          continue
+        if path[0][-2:] != ".h":
+          continue
+        fname = pretty_name (path[0])
+        if fname in ignore or fname[0:3] == "gt_":
+          continue
+        sline.append (("error", msg, fname, incfrom))
+
+  print str(len(sline)) + " lines to process"
+  lastline = "note"
+  for line in sline:
+    if line[0] != "note" and lastline[0] == "error":
+      fname = lastline[2]
+      msg = lastline[1]
+      incfrom = lastline[3]
+      string = ""
+      ofname = fname
+      if len(incfrom) != 0:
+        for t in incfrom:
+          string = string + t + " : "
+          ee = (fname, t)
+          if ee not in extra_edges:
+            extra_edges.append (ee)
+          fname = t
+          print string
+
+      if hname not in nodes:
+        nodes.append(hname)
+      if fname not in nodes:
+        nodes.append (ofname)
+      for y in incfrom:
+        if y not in nodes:
+          nodes.append (y)
+
+
+      if header_roots[hname].get(fname) == None:
+        header_roots[hname][fname] = list()
+      if msg not in header_roots[hname][fname]:
+        print string + ofname + " : " +msg
+        header_roots[hname][fname].append (msg)
+    lastline = line;
+
+
+dotname = "graph.dot"
+graphname = "graph.png"
+
+
+def build_dot_file (file_list):
+  output = open(dotname, "w")
+  output.write ("digraph incweb {\n");
+  for x in file_list:
+    if os.path.exists (x) and x[-4:] == ".log":
+      header =  x[:-4]
+      logfile = open(x).read().splitlines()
+      process_log_file (header, logfile)
+    elif os.path.exists (x + ".log"):
+      logfile = open(x + ".log").read().splitlines()
+      process_log_file (x, logfile)
+
+  for n in nodes:
+    fn = unpretty(n)
+    label = n + " [ label = \"" + fn  + "\" ];"
+    output.write (label + "\n")
+    if os.path.exists (fn):
+      h = open(fn).read().splitlines()
+      for l in h:
+        t = find_pound_include (l, True, False)
+        if t != "":
+          t = pretty_name (t)
+          if t in ignore or t[-2:] != "_h":
+            continue
+          if t not in nodes:
+            nodes.append (t)
+          ee = (t, n)
+          if ee not in extra_edges:
+            extra_edges.append (ee)
+
+  depcount = list()
+  for h in header_roots:
+    for dep in header_roots[h]:
+      label = " [ label = "+ str(len(header_roots[h][dep])) + " ];"
+      string = h + " -> " + dep + label
+      output.write (string + "\n");
+      if verbose:
+        depcount.append ((h, dep, len(header_roots[h][dep])))
+
+  for ee in extra_edges:
+    string = ee[0] + " -> " + ee[1] + "[ color=red ];"
+    output.write (string + "\n");
+
+  
+  if verbose:
+    depcount.sort(key=lambda tup:tup[2])
+    for x in depcount:
+      print " ("+str(x[2])+ ") : " + x[0] + " -> " + x[1]
+      if (x[2] <= verbosity):
+        for l in header_roots[x[0]][x[1]]:
+          print "            " + l
+
+  output.write ("}\n");
+
+
+files = list()
+dohelp = False
+edge_thresh = 0
+for arg in sys.argv[1:]:
+  if arg[0:2] == "-o":
+    dotname = arg[2:]+".dot"
+    graphname = arg[2:]+".png"
+  elif arg[0:2] == "-h":
+    dohelp = True
+  elif arg[0:2] == "-v":
+    verbose = True
+    if len(arg) > 2:
+      verbosity = int (arg[2:])
+      if (verbosity == 9):
+        verbosity = 9999
+  elif arg[0:1] == "-":
+    print "Unrecognized option " + arg
+    dohelp = True
+  else:
+    files.append (arg)
+    
+if len(sys.argv) == 1:
+  dohelp = True
+
+if dohelp:
+  print "Parses the log files from the reduce-headers tool to generate"
+  print "dependency graphs for the include web for specified files."
+  print "Usage:  [-nnum] [-h] [-v[n]] [-ooutput] file1 [[file2] ... [filen]]"
+  print "       -ooutput : Specifies output to output.dot and output.png"
+  print "                  Defaults to 'graph.dot and graph.png"
+  print "       -vn : verbose mode, shows the number of connections, and if n"
+  print "             is specified, show the messages if # < n. 9 is infinity"
+  print "       -h : help"
+else:
+  print files
+  build_dot_file (files)
+  os.system ("dot -Tpng " + dotname + " -o" + graphname)
+
+