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