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