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