blob: e537aaeac0c52548474985179ede40e33150cf06 [file] [log] [blame]
#! /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)