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