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