|  | #! /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) | 
|  |  | 
|  |  |