1 1.1 mrg #! /usr/bin/python2 2 1.1 mrg import os.path 3 1.1 mrg import sys 4 1.1 mrg import shlex 5 1.1 mrg import re 6 1.1 mrg 7 1.1 mrg from headerutils import * 8 1.1 mrg 9 1.1 mrg header_roots = { } 10 1.1 mrg extra_edges = list() 11 1.1 mrg verbose = False 12 1.1 mrg verbosity = 0 13 1.1 mrg nodes = list() 14 1.1 mrg 15 1.1 mrg def unpretty (name): 16 1.1 mrg if name[-2:] == "_h": 17 1.1 mrg name = name[:-2] + ".h" 18 1.1 mrg return name.replace("_", "-") 19 1.1 mrg 20 1.1 mrg def pretty_name (name): 21 1.1 mrg name = os.path.basename (name) 22 1.1 mrg return name.replace(".","_").replace("-","_").replace("/","_").replace("+","_"); 23 1.1 mrg 24 1.1 mrg depstring = ("In file included from", " from") 25 1.1 mrg 26 1.1 mrg # indentation indicates nesting levels of included files 27 1.1 mrg ignore = [ "coretypes_h", 28 1.1.1.4 mrg "insn_modes_h", 29 1.1 mrg "signop_h", 30 1.1 mrg "wide_int_h", 31 1.1.1.4 mrg "wide_int_print_h", 32 1.1.1.4 mrg "insn_modes_inline_h", 33 1.1.1.4 mrg "machmode_h", 34 1.1 mrg "double_int_h", 35 1.1 mrg "real_h", 36 1.1 mrg "fixed_value_h", 37 1.1 mrg "hash_table_h", 38 1.1 mrg "statistics_h", 39 1.1 mrg "ggc_h", 40 1.1 mrg "vec_h", 41 1.1 mrg "hashtab_h", 42 1.1 mrg "inchash_h", 43 1.1 mrg "mem_stats_traits_h", 44 1.1 mrg "hash_map_traits_h", 45 1.1 mrg "mem_stats_h", 46 1.1 mrg "hash_map_h", 47 1.1 mrg "hash_set_h", 48 1.1 mrg "input_h", 49 1.1 mrg "line_map_h", 50 1.1 mrg "is_a_h", 51 1.1 mrg "system_h", 52 1.1 mrg "config_h" ] 53 1.1 mrg 54 1.1 mrg def process_log_file (header, logfile): 55 1.1 mrg if header_roots.get (header) != None: 56 1.1 mrg print "Error: already processed log file: " + header + ".log" 57 1.1 mrg return 58 1.1 mrg hname = pretty_name (header) 59 1.1 mrg header_roots[hname] = { } 60 1.1 mrg 61 1.1 mrg sline = list(); 62 1.1 mrg incfrom = list() 63 1.1 mrg newinc = True 64 1.1 mrg for line in logfile: 65 1.1 mrg if len (line) > 21 and line[:21] in depstring: 66 1.1 mrg if newinc: 67 1.1 mrg incfrom = list() 68 1.1 mrg newinc = False 69 1.1 mrg fn = re.findall(ur".*/(.*?):", line) 70 1.1 mrg if len(fn) != 1: 71 1.1 mrg continue 72 1.1 mrg if fn[0][-2:] != ".h": 73 1.1 mrg continue 74 1.1 mrg n = pretty_name (fn[0]) 75 1.1 mrg if n not in ignore: 76 1.1 mrg incfrom.append (n) 77 1.1 mrg continue 78 1.1 mrg newinc = True 79 1.1 mrg note = re.findall (ur"^.*note: (.*)", line) 80 1.1 mrg if len(note) > 0: 81 1.1 mrg sline.append (("note", note[0])) 82 1.1 mrg else: 83 1.1 mrg err_msg = re.findall (ur"^.*: error: (.*)", line) 84 1.1 mrg if len(err_msg) == 1: 85 1.1 mrg msg = err_msg[0] 86 1.1 mrg if (len (re.findall("error: forward declaration", line))) != 0: 87 1.1 mrg continue 88 1.1 mrg path = re.findall (ur"^(.*?):.*error: ", line) 89 1.1 mrg if len(path) != 1: 90 1.1 mrg continue 91 1.1 mrg if path[0][-2:] != ".h": 92 1.1 mrg continue 93 1.1 mrg fname = pretty_name (path[0]) 94 1.1 mrg if fname in ignore or fname[0:3] == "gt_": 95 1.1 mrg continue 96 1.1 mrg sline.append (("error", msg, fname, incfrom)) 97 1.1 mrg 98 1.1 mrg print str(len(sline)) + " lines to process" 99 1.1 mrg lastline = "note" 100 1.1 mrg for line in sline: 101 1.1 mrg if line[0] != "note" and lastline[0] == "error": 102 1.1 mrg fname = lastline[2] 103 1.1 mrg msg = lastline[1] 104 1.1 mrg incfrom = lastline[3] 105 1.1 mrg string = "" 106 1.1 mrg ofname = fname 107 1.1 mrg if len(incfrom) != 0: 108 1.1 mrg for t in incfrom: 109 1.1 mrg string = string + t + " : " 110 1.1 mrg ee = (fname, t) 111 1.1 mrg if ee not in extra_edges: 112 1.1 mrg extra_edges.append (ee) 113 1.1 mrg fname = t 114 1.1 mrg print string 115 1.1 mrg 116 1.1 mrg if hname not in nodes: 117 1.1 mrg nodes.append(hname) 118 1.1 mrg if fname not in nodes: 119 1.1 mrg nodes.append (ofname) 120 1.1 mrg for y in incfrom: 121 1.1 mrg if y not in nodes: 122 1.1 mrg nodes.append (y) 123 1.1 mrg 124 1.1 mrg 125 1.1 mrg if header_roots[hname].get(fname) == None: 126 1.1 mrg header_roots[hname][fname] = list() 127 1.1 mrg if msg not in header_roots[hname][fname]: 128 1.1 mrg print string + ofname + " : " +msg 129 1.1 mrg header_roots[hname][fname].append (msg) 130 1.1 mrg lastline = line; 131 1.1 mrg 132 1.1 mrg 133 1.1 mrg dotname = "graph.dot" 134 1.1 mrg graphname = "graph.png" 135 1.1 mrg 136 1.1 mrg 137 1.1 mrg def build_dot_file (file_list): 138 1.1 mrg output = open(dotname, "w") 139 1.1 mrg output.write ("digraph incweb {\n"); 140 1.1 mrg for x in file_list: 141 1.1 mrg if os.path.exists (x) and x[-4:] == ".log": 142 1.1 mrg header = x[:-4] 143 1.1 mrg logfile = open(x).read().splitlines() 144 1.1 mrg process_log_file (header, logfile) 145 1.1 mrg elif os.path.exists (x + ".log"): 146 1.1 mrg logfile = open(x + ".log").read().splitlines() 147 1.1 mrg process_log_file (x, logfile) 148 1.1 mrg 149 1.1 mrg for n in nodes: 150 1.1 mrg fn = unpretty(n) 151 1.1 mrg label = n + " [ label = \"" + fn + "\" ];" 152 1.1 mrg output.write (label + "\n") 153 1.1 mrg if os.path.exists (fn): 154 1.1 mrg h = open(fn).read().splitlines() 155 1.1 mrg for l in h: 156 1.1 mrg t = find_pound_include (l, True, False) 157 1.1 mrg if t != "": 158 1.1 mrg t = pretty_name (t) 159 1.1 mrg if t in ignore or t[-2:] != "_h": 160 1.1 mrg continue 161 1.1 mrg if t not in nodes: 162 1.1 mrg nodes.append (t) 163 1.1 mrg ee = (t, n) 164 1.1 mrg if ee not in extra_edges: 165 1.1 mrg extra_edges.append (ee) 166 1.1 mrg 167 1.1 mrg depcount = list() 168 1.1 mrg for h in header_roots: 169 1.1 mrg for dep in header_roots[h]: 170 1.1 mrg label = " [ label = "+ str(len(header_roots[h][dep])) + " ];" 171 1.1 mrg string = h + " -> " + dep + label 172 1.1 mrg output.write (string + "\n"); 173 1.1 mrg if verbose: 174 1.1 mrg depcount.append ((h, dep, len(header_roots[h][dep]))) 175 1.1 mrg 176 1.1 mrg for ee in extra_edges: 177 1.1 mrg string = ee[0] + " -> " + ee[1] + "[ color=red ];" 178 1.1 mrg output.write (string + "\n"); 179 1.1 mrg 180 1.1 mrg 181 1.1 mrg if verbose: 182 1.1 mrg depcount.sort(key=lambda tup:tup[2]) 183 1.1 mrg for x in depcount: 184 1.1 mrg print " ("+str(x[2])+ ") : " + x[0] + " -> " + x[1] 185 1.1 mrg if (x[2] <= verbosity): 186 1.1 mrg for l in header_roots[x[0]][x[1]]: 187 1.1 mrg print " " + l 188 1.1 mrg 189 1.1 mrg output.write ("}\n"); 190 1.1 mrg 191 1.1 mrg 192 1.1 mrg files = list() 193 1.1 mrg dohelp = False 194 1.1 mrg edge_thresh = 0 195 1.1 mrg for arg in sys.argv[1:]: 196 1.1 mrg if arg[0:2] == "-o": 197 1.1 mrg dotname = arg[2:]+".dot" 198 1.1 mrg graphname = arg[2:]+".png" 199 1.1 mrg elif arg[0:2] == "-h": 200 1.1 mrg dohelp = True 201 1.1 mrg elif arg[0:2] == "-v": 202 1.1 mrg verbose = True 203 1.1 mrg if len(arg) > 2: 204 1.1 mrg verbosity = int (arg[2:]) 205 1.1 mrg if (verbosity == 9): 206 1.1 mrg verbosity = 9999 207 1.1 mrg elif arg[0:1] == "-": 208 1.1 mrg print "Unrecognized option " + arg 209 1.1 mrg dohelp = True 210 1.1 mrg else: 211 1.1 mrg files.append (arg) 212 1.1 mrg 213 1.1 mrg if len(sys.argv) == 1: 214 1.1 mrg dohelp = True 215 1.1 mrg 216 1.1 mrg if dohelp: 217 1.1 mrg print "Parses the log files from the reduce-headers tool to generate" 218 1.1 mrg print "dependency graphs for the include web for specified files." 219 1.1 mrg print "Usage: [-nnum] [-h] [-v[n]] [-ooutput] file1 [[file2] ... [filen]]" 220 1.1 mrg print " -ooutput : Specifies output to output.dot and output.png" 221 1.1 mrg print " Defaults to 'graph.dot and graph.png" 222 1.1 mrg print " -vn : verbose mode, shows the number of connections, and if n" 223 1.1 mrg print " is specified, show the messages if # < n. 9 is infinity" 224 1.1 mrg print " -h : help" 225 1.1 mrg else: 226 1.1 mrg print files 227 1.1 mrg build_dot_file (files) 228 1.1 mrg os.system ("dot -Tpng " + dotname + " -o" + graphname) 229 1.1 mrg 230 1.1 mrg 231