136ac495dSmrg#! /usr/bin/python2 236ac495dSmrgimport os.path 336ac495dSmrgimport sys 436ac495dSmrgimport shlex 536ac495dSmrgimport re 636ac495dSmrg 736ac495dSmrgfrom headerutils import * 836ac495dSmrg 936ac495dSmrgheader_roots = { } 1036ac495dSmrgextra_edges = list() 1136ac495dSmrgverbose = False 1236ac495dSmrgverbosity = 0 1336ac495dSmrgnodes = list() 1436ac495dSmrg 1536ac495dSmrgdef unpretty (name): 1636ac495dSmrg if name[-2:] == "_h": 1736ac495dSmrg name = name[:-2] + ".h" 1836ac495dSmrg return name.replace("_", "-") 1936ac495dSmrg 2036ac495dSmrgdef pretty_name (name): 2136ac495dSmrg name = os.path.basename (name) 2236ac495dSmrg return name.replace(".","_").replace("-","_").replace("/","_").replace("+","_"); 2336ac495dSmrg 2436ac495dSmrgdepstring = ("In file included from", " from") 2536ac495dSmrg 2636ac495dSmrg# indentation indicates nesting levels of included files 2736ac495dSmrgignore = [ "coretypes_h", 28*a2dc1f3fSmrg "insn_modes_h", 2936ac495dSmrg "signop_h", 3036ac495dSmrg "wide_int_h", 31*a2dc1f3fSmrg "wide_int_print_h", 32*a2dc1f3fSmrg "insn_modes_inline_h", 33*a2dc1f3fSmrg "machmode_h", 3436ac495dSmrg "double_int_h", 3536ac495dSmrg "real_h", 3636ac495dSmrg "fixed_value_h", 3736ac495dSmrg "hash_table_h", 3836ac495dSmrg "statistics_h", 3936ac495dSmrg "ggc_h", 4036ac495dSmrg "vec_h", 4136ac495dSmrg "hashtab_h", 4236ac495dSmrg "inchash_h", 4336ac495dSmrg "mem_stats_traits_h", 4436ac495dSmrg "hash_map_traits_h", 4536ac495dSmrg "mem_stats_h", 4636ac495dSmrg "hash_map_h", 4736ac495dSmrg "hash_set_h", 4836ac495dSmrg "input_h", 4936ac495dSmrg "line_map_h", 5036ac495dSmrg "is_a_h", 5136ac495dSmrg "system_h", 5236ac495dSmrg "config_h" ] 5336ac495dSmrg 5436ac495dSmrgdef process_log_file (header, logfile): 5536ac495dSmrg if header_roots.get (header) != None: 5636ac495dSmrg print "Error: already processed log file: " + header + ".log" 5736ac495dSmrg return 5836ac495dSmrg hname = pretty_name (header) 5936ac495dSmrg header_roots[hname] = { } 6036ac495dSmrg 6136ac495dSmrg sline = list(); 6236ac495dSmrg incfrom = list() 6336ac495dSmrg newinc = True 6436ac495dSmrg for line in logfile: 6536ac495dSmrg if len (line) > 21 and line[:21] in depstring: 6636ac495dSmrg if newinc: 6736ac495dSmrg incfrom = list() 6836ac495dSmrg newinc = False 6936ac495dSmrg fn = re.findall(ur".*/(.*?):", line) 7036ac495dSmrg if len(fn) != 1: 7136ac495dSmrg continue 7236ac495dSmrg if fn[0][-2:] != ".h": 7336ac495dSmrg continue 7436ac495dSmrg n = pretty_name (fn[0]) 7536ac495dSmrg if n not in ignore: 7636ac495dSmrg incfrom.append (n) 7736ac495dSmrg continue 7836ac495dSmrg newinc = True 7936ac495dSmrg note = re.findall (ur"^.*note: (.*)", line) 8036ac495dSmrg if len(note) > 0: 8136ac495dSmrg sline.append (("note", note[0])) 8236ac495dSmrg else: 8336ac495dSmrg err_msg = re.findall (ur"^.*: error: (.*)", line) 8436ac495dSmrg if len(err_msg) == 1: 8536ac495dSmrg msg = err_msg[0] 8636ac495dSmrg if (len (re.findall("error: forward declaration", line))) != 0: 8736ac495dSmrg continue 8836ac495dSmrg path = re.findall (ur"^(.*?):.*error: ", line) 8936ac495dSmrg if len(path) != 1: 9036ac495dSmrg continue 9136ac495dSmrg if path[0][-2:] != ".h": 9236ac495dSmrg continue 9336ac495dSmrg fname = pretty_name (path[0]) 9436ac495dSmrg if fname in ignore or fname[0:3] == "gt_": 9536ac495dSmrg continue 9636ac495dSmrg sline.append (("error", msg, fname, incfrom)) 9736ac495dSmrg 9836ac495dSmrg print str(len(sline)) + " lines to process" 9936ac495dSmrg lastline = "note" 10036ac495dSmrg for line in sline: 10136ac495dSmrg if line[0] != "note" and lastline[0] == "error": 10236ac495dSmrg fname = lastline[2] 10336ac495dSmrg msg = lastline[1] 10436ac495dSmrg incfrom = lastline[3] 10536ac495dSmrg string = "" 10636ac495dSmrg ofname = fname 10736ac495dSmrg if len(incfrom) != 0: 10836ac495dSmrg for t in incfrom: 10936ac495dSmrg string = string + t + " : " 11036ac495dSmrg ee = (fname, t) 11136ac495dSmrg if ee not in extra_edges: 11236ac495dSmrg extra_edges.append (ee) 11336ac495dSmrg fname = t 11436ac495dSmrg print string 11536ac495dSmrg 11636ac495dSmrg if hname not in nodes: 11736ac495dSmrg nodes.append(hname) 11836ac495dSmrg if fname not in nodes: 11936ac495dSmrg nodes.append (ofname) 12036ac495dSmrg for y in incfrom: 12136ac495dSmrg if y not in nodes: 12236ac495dSmrg nodes.append (y) 12336ac495dSmrg 12436ac495dSmrg 12536ac495dSmrg if header_roots[hname].get(fname) == None: 12636ac495dSmrg header_roots[hname][fname] = list() 12736ac495dSmrg if msg not in header_roots[hname][fname]: 12836ac495dSmrg print string + ofname + " : " +msg 12936ac495dSmrg header_roots[hname][fname].append (msg) 13036ac495dSmrg lastline = line; 13136ac495dSmrg 13236ac495dSmrg 13336ac495dSmrgdotname = "graph.dot" 13436ac495dSmrggraphname = "graph.png" 13536ac495dSmrg 13636ac495dSmrg 13736ac495dSmrgdef build_dot_file (file_list): 13836ac495dSmrg output = open(dotname, "w") 13936ac495dSmrg output.write ("digraph incweb {\n"); 14036ac495dSmrg for x in file_list: 14136ac495dSmrg if os.path.exists (x) and x[-4:] == ".log": 14236ac495dSmrg header = x[:-4] 14336ac495dSmrg logfile = open(x).read().splitlines() 14436ac495dSmrg process_log_file (header, logfile) 14536ac495dSmrg elif os.path.exists (x + ".log"): 14636ac495dSmrg logfile = open(x + ".log").read().splitlines() 14736ac495dSmrg process_log_file (x, logfile) 14836ac495dSmrg 14936ac495dSmrg for n in nodes: 15036ac495dSmrg fn = unpretty(n) 15136ac495dSmrg label = n + " [ label = \"" + fn + "\" ];" 15236ac495dSmrg output.write (label + "\n") 15336ac495dSmrg if os.path.exists (fn): 15436ac495dSmrg h = open(fn).read().splitlines() 15536ac495dSmrg for l in h: 15636ac495dSmrg t = find_pound_include (l, True, False) 15736ac495dSmrg if t != "": 15836ac495dSmrg t = pretty_name (t) 15936ac495dSmrg if t in ignore or t[-2:] != "_h": 16036ac495dSmrg continue 16136ac495dSmrg if t not in nodes: 16236ac495dSmrg nodes.append (t) 16336ac495dSmrg ee = (t, n) 16436ac495dSmrg if ee not in extra_edges: 16536ac495dSmrg extra_edges.append (ee) 16636ac495dSmrg 16736ac495dSmrg depcount = list() 16836ac495dSmrg for h in header_roots: 16936ac495dSmrg for dep in header_roots[h]: 17036ac495dSmrg label = " [ label = "+ str(len(header_roots[h][dep])) + " ];" 17136ac495dSmrg string = h + " -> " + dep + label 17236ac495dSmrg output.write (string + "\n"); 17336ac495dSmrg if verbose: 17436ac495dSmrg depcount.append ((h, dep, len(header_roots[h][dep]))) 17536ac495dSmrg 17636ac495dSmrg for ee in extra_edges: 17736ac495dSmrg string = ee[0] + " -> " + ee[1] + "[ color=red ];" 17836ac495dSmrg output.write (string + "\n"); 17936ac495dSmrg 18036ac495dSmrg 18136ac495dSmrg if verbose: 18236ac495dSmrg depcount.sort(key=lambda tup:tup[2]) 18336ac495dSmrg for x in depcount: 18436ac495dSmrg print " ("+str(x[2])+ ") : " + x[0] + " -> " + x[1] 18536ac495dSmrg if (x[2] <= verbosity): 18636ac495dSmrg for l in header_roots[x[0]][x[1]]: 18736ac495dSmrg print " " + l 18836ac495dSmrg 18936ac495dSmrg output.write ("}\n"); 19036ac495dSmrg 19136ac495dSmrg 19236ac495dSmrgfiles = list() 19336ac495dSmrgdohelp = False 19436ac495dSmrgedge_thresh = 0 19536ac495dSmrgfor arg in sys.argv[1:]: 19636ac495dSmrg if arg[0:2] == "-o": 19736ac495dSmrg dotname = arg[2:]+".dot" 19836ac495dSmrg graphname = arg[2:]+".png" 19936ac495dSmrg elif arg[0:2] == "-h": 20036ac495dSmrg dohelp = True 20136ac495dSmrg elif arg[0:2] == "-v": 20236ac495dSmrg verbose = True 20336ac495dSmrg if len(arg) > 2: 20436ac495dSmrg verbosity = int (arg[2:]) 20536ac495dSmrg if (verbosity == 9): 20636ac495dSmrg verbosity = 9999 20736ac495dSmrg elif arg[0:1] == "-": 20836ac495dSmrg print "Unrecognized option " + arg 20936ac495dSmrg dohelp = True 21036ac495dSmrg else: 21136ac495dSmrg files.append (arg) 21236ac495dSmrg 21336ac495dSmrgif len(sys.argv) == 1: 21436ac495dSmrg dohelp = True 21536ac495dSmrg 21636ac495dSmrgif dohelp: 21736ac495dSmrg print "Parses the log files from the reduce-headers tool to generate" 21836ac495dSmrg print "dependency graphs for the include web for specified files." 21936ac495dSmrg print "Usage: [-nnum] [-h] [-v[n]] [-ooutput] file1 [[file2] ... [filen]]" 22036ac495dSmrg print " -ooutput : Specifies output to output.dot and output.png" 22136ac495dSmrg print " Defaults to 'graph.dot and graph.png" 22236ac495dSmrg print " -vn : verbose mode, shows the number of connections, and if n" 22336ac495dSmrg print " is specified, show the messages if # < n. 9 is infinity" 22436ac495dSmrg print " -h : help" 22536ac495dSmrgelse: 22636ac495dSmrg print files 22736ac495dSmrg build_dot_file (files) 22836ac495dSmrg os.system ("dot -Tpng " + dotname + " -o" + graphname) 22936ac495dSmrg 23036ac495dSmrg 231