xref: /netbsd-src/external/gpl3/gcc.old/dist/contrib/header-tools/graph-header-logs (revision a2dc1f3faca890bc62c61c70cbcb4657d1fe6044)
136ac495dSmrg#! /usr/bin/python2
236ac495dSmrgimport os.path
336ac495dSmrgimport sys
436ac495dSmrgimport shlex
536ac495dSmrgimport re
636ac495dSmrg
736ac495dSmrgfrom headerutils import *
836ac495dSmrg
936ac495dSmrgheader_roots = { }
1036ac495dSmrgextra_edges = list()
1136ac495dSmrgverbose = False
1236ac495dSmrgverbosity = 0
1336ac495dSmrgnodes = list()
1436ac495dSmrg
1536ac495dSmrgdef unpretty (name):
1636ac495dSmrg  if name[-2:] == "_h":
1736ac495dSmrg    name = name[:-2] + ".h"
1836ac495dSmrg  return name.replace("_", "-")
1936ac495dSmrg
2036ac495dSmrgdef pretty_name (name):
2136ac495dSmrg  name = os.path.basename (name)
2236ac495dSmrg  return name.replace(".","_").replace("-","_").replace("/","_").replace("+","_");
2336ac495dSmrg
2436ac495dSmrgdepstring = ("In file included from", "                 from")
2536ac495dSmrg
2636ac495dSmrg# indentation indicates nesting levels of included files
2736ac495dSmrgignore = [ "coretypes_h",
28*a2dc1f3fSmrg             "insn_modes_h",
2936ac495dSmrg             "signop_h",
3036ac495dSmrg             "wide_int_h",
31*a2dc1f3fSmrg             "wide_int_print_h",
32*a2dc1f3fSmrg             "insn_modes_inline_h",
33*a2dc1f3fSmrg             "machmode_h",
3436ac495dSmrg             "double_int_h",
3536ac495dSmrg             "real_h",
3636ac495dSmrg             "fixed_value_h",
3736ac495dSmrg             "hash_table_h",
3836ac495dSmrg               "statistics_h",
3936ac495dSmrg               "ggc_h",
4036ac495dSmrg               "vec_h",
4136ac495dSmrg               "hashtab_h",
4236ac495dSmrg               "inchash_h",
4336ac495dSmrg               "mem_stats_traits_h",
4436ac495dSmrg               "hash_map_traits_h",
4536ac495dSmrg               "mem_stats_h",
4636ac495dSmrg               "hash_map_h",
4736ac495dSmrg             "hash_set_h",
4836ac495dSmrg             "input_h",
4936ac495dSmrg               "line_map_h",
5036ac495dSmrg             "is_a_h",
5136ac495dSmrg           "system_h",
5236ac495dSmrg           "config_h" ]
5336ac495dSmrg
5436ac495dSmrgdef process_log_file (header, logfile):
5536ac495dSmrg  if header_roots.get (header) != None:
5636ac495dSmrg    print "Error: already processed log file: " + header + ".log"
5736ac495dSmrg    return
5836ac495dSmrg  hname = pretty_name (header)
5936ac495dSmrg  header_roots[hname] = { }
6036ac495dSmrg
6136ac495dSmrg  sline = list();
6236ac495dSmrg  incfrom = list()
6336ac495dSmrg  newinc = True
6436ac495dSmrg  for line in logfile:
6536ac495dSmrg    if len (line) > 21 and line[:21] in depstring:
6636ac495dSmrg      if newinc:
6736ac495dSmrg        incfrom = list()
6836ac495dSmrg        newinc = False
6936ac495dSmrg      fn = re.findall(ur".*/(.*?):", line)
7036ac495dSmrg      if len(fn) != 1:
7136ac495dSmrg        continue
7236ac495dSmrg      if fn[0][-2:] != ".h":
7336ac495dSmrg        continue
7436ac495dSmrg      n = pretty_name (fn[0])
7536ac495dSmrg      if n not in ignore:
7636ac495dSmrg        incfrom.append (n)
7736ac495dSmrg      continue
7836ac495dSmrg    newinc = True
7936ac495dSmrg    note = re.findall (ur"^.*note: (.*)", line)
8036ac495dSmrg    if len(note) > 0:
8136ac495dSmrg      sline.append (("note", note[0]))
8236ac495dSmrg    else:
8336ac495dSmrg      err_msg = re.findall (ur"^.*: error: (.*)", line)
8436ac495dSmrg      if len(err_msg) == 1:
8536ac495dSmrg        msg = err_msg[0]
8636ac495dSmrg        if (len (re.findall("error: forward declaration", line))) != 0:
8736ac495dSmrg          continue
8836ac495dSmrg        path = re.findall (ur"^(.*?):.*error: ", line)
8936ac495dSmrg        if len(path) != 1:
9036ac495dSmrg          continue
9136ac495dSmrg        if path[0][-2:] != ".h":
9236ac495dSmrg          continue
9336ac495dSmrg        fname = pretty_name (path[0])
9436ac495dSmrg        if fname in ignore or fname[0:3] == "gt_":
9536ac495dSmrg          continue
9636ac495dSmrg        sline.append (("error", msg, fname, incfrom))
9736ac495dSmrg
9836ac495dSmrg  print str(len(sline)) + " lines to process"
9936ac495dSmrg  lastline = "note"
10036ac495dSmrg  for line in sline:
10136ac495dSmrg    if line[0] != "note" and lastline[0] == "error":
10236ac495dSmrg      fname = lastline[2]
10336ac495dSmrg      msg = lastline[1]
10436ac495dSmrg      incfrom = lastline[3]
10536ac495dSmrg      string = ""
10636ac495dSmrg      ofname = fname
10736ac495dSmrg      if len(incfrom) != 0:
10836ac495dSmrg        for t in incfrom:
10936ac495dSmrg          string = string + t + " : "
11036ac495dSmrg          ee = (fname, t)
11136ac495dSmrg          if ee not in extra_edges:
11236ac495dSmrg            extra_edges.append (ee)
11336ac495dSmrg          fname = t
11436ac495dSmrg          print string
11536ac495dSmrg
11636ac495dSmrg      if hname not in nodes:
11736ac495dSmrg        nodes.append(hname)
11836ac495dSmrg      if fname not in nodes:
11936ac495dSmrg        nodes.append (ofname)
12036ac495dSmrg      for y in incfrom:
12136ac495dSmrg        if y not in nodes:
12236ac495dSmrg          nodes.append (y)
12336ac495dSmrg
12436ac495dSmrg
12536ac495dSmrg      if header_roots[hname].get(fname) == None:
12636ac495dSmrg        header_roots[hname][fname] = list()
12736ac495dSmrg      if msg not in header_roots[hname][fname]:
12836ac495dSmrg        print string + ofname + " : " +msg
12936ac495dSmrg        header_roots[hname][fname].append (msg)
13036ac495dSmrg    lastline = line;
13136ac495dSmrg
13236ac495dSmrg
13336ac495dSmrgdotname = "graph.dot"
13436ac495dSmrggraphname = "graph.png"
13536ac495dSmrg
13636ac495dSmrg
13736ac495dSmrgdef build_dot_file (file_list):
13836ac495dSmrg  output = open(dotname, "w")
13936ac495dSmrg  output.write ("digraph incweb {\n");
14036ac495dSmrg  for x in file_list:
14136ac495dSmrg    if os.path.exists (x) and x[-4:] == ".log":
14236ac495dSmrg      header =  x[:-4]
14336ac495dSmrg      logfile = open(x).read().splitlines()
14436ac495dSmrg      process_log_file (header, logfile)
14536ac495dSmrg    elif os.path.exists (x + ".log"):
14636ac495dSmrg      logfile = open(x + ".log").read().splitlines()
14736ac495dSmrg      process_log_file (x, logfile)
14836ac495dSmrg
14936ac495dSmrg  for n in nodes:
15036ac495dSmrg    fn = unpretty(n)
15136ac495dSmrg    label = n + " [ label = \"" + fn  + "\" ];"
15236ac495dSmrg    output.write (label + "\n")
15336ac495dSmrg    if os.path.exists (fn):
15436ac495dSmrg      h = open(fn).read().splitlines()
15536ac495dSmrg      for l in h:
15636ac495dSmrg        t = find_pound_include (l, True, False)
15736ac495dSmrg        if t != "":
15836ac495dSmrg          t = pretty_name (t)
15936ac495dSmrg          if t in ignore or t[-2:] != "_h":
16036ac495dSmrg            continue
16136ac495dSmrg          if t not in nodes:
16236ac495dSmrg            nodes.append (t)
16336ac495dSmrg          ee = (t, n)
16436ac495dSmrg          if ee not in extra_edges:
16536ac495dSmrg            extra_edges.append (ee)
16636ac495dSmrg
16736ac495dSmrg  depcount = list()
16836ac495dSmrg  for h in header_roots:
16936ac495dSmrg    for dep in header_roots[h]:
17036ac495dSmrg      label = " [ label = "+ str(len(header_roots[h][dep])) + " ];"
17136ac495dSmrg      string = h + " -> " + dep + label
17236ac495dSmrg      output.write (string + "\n");
17336ac495dSmrg      if verbose:
17436ac495dSmrg        depcount.append ((h, dep, len(header_roots[h][dep])))
17536ac495dSmrg
17636ac495dSmrg  for ee in extra_edges:
17736ac495dSmrg    string = ee[0] + " -> " + ee[1] + "[ color=red ];"
17836ac495dSmrg    output.write (string + "\n");
17936ac495dSmrg
18036ac495dSmrg
18136ac495dSmrg  if verbose:
18236ac495dSmrg    depcount.sort(key=lambda tup:tup[2])
18336ac495dSmrg    for x in depcount:
18436ac495dSmrg      print " ("+str(x[2])+ ") : " + x[0] + " -> " + x[1]
18536ac495dSmrg      if (x[2] <= verbosity):
18636ac495dSmrg        for l in header_roots[x[0]][x[1]]:
18736ac495dSmrg          print "            " + l
18836ac495dSmrg
18936ac495dSmrg  output.write ("}\n");
19036ac495dSmrg
19136ac495dSmrg
19236ac495dSmrgfiles = list()
19336ac495dSmrgdohelp = False
19436ac495dSmrgedge_thresh = 0
19536ac495dSmrgfor arg in sys.argv[1:]:
19636ac495dSmrg  if arg[0:2] == "-o":
19736ac495dSmrg    dotname = arg[2:]+".dot"
19836ac495dSmrg    graphname = arg[2:]+".png"
19936ac495dSmrg  elif arg[0:2] == "-h":
20036ac495dSmrg    dohelp = True
20136ac495dSmrg  elif arg[0:2] == "-v":
20236ac495dSmrg    verbose = True
20336ac495dSmrg    if len(arg) > 2:
20436ac495dSmrg      verbosity = int (arg[2:])
20536ac495dSmrg      if (verbosity == 9):
20636ac495dSmrg        verbosity = 9999
20736ac495dSmrg  elif arg[0:1] == "-":
20836ac495dSmrg    print "Unrecognized option " + arg
20936ac495dSmrg    dohelp = True
21036ac495dSmrg  else:
21136ac495dSmrg    files.append (arg)
21236ac495dSmrg
21336ac495dSmrgif len(sys.argv) == 1:
21436ac495dSmrg  dohelp = True
21536ac495dSmrg
21636ac495dSmrgif dohelp:
21736ac495dSmrg  print "Parses the log files from the reduce-headers tool to generate"
21836ac495dSmrg  print "dependency graphs for the include web for specified files."
21936ac495dSmrg  print "Usage:  [-nnum] [-h] [-v[n]] [-ooutput] file1 [[file2] ... [filen]]"
22036ac495dSmrg  print "       -ooutput : Specifies output to output.dot and output.png"
22136ac495dSmrg  print "                  Defaults to 'graph.dot and graph.png"
22236ac495dSmrg  print "       -vn : verbose mode, shows the number of connections, and if n"
22336ac495dSmrg  print "             is specified, show the messages if # < n. 9 is infinity"
22436ac495dSmrg  print "       -h : help"
22536ac495dSmrgelse:
22636ac495dSmrg  print files
22736ac495dSmrg  build_dot_file (files)
22836ac495dSmrg  os.system ("dot -Tpng " + dotname + " -o" + graphname)
22936ac495dSmrg
23036ac495dSmrg
231