7 from headerutils import *
17 name = name[:-2] + ".h"
18 return name.replace("_", "-")
20 def pretty_name (name):
21 name = os.path.basename (name)
22 return name.replace(".","_").replace("-","_").replace("/","_").replace("+","_");
24 depstring = ("In file included from", " from")
26 # indentation indicates nesting levels of included files
27 ignore = [ "coretypes_h",
51 def process_log_file (header, logfile):
52 if header_roots.get (header) != None:
53 print "Error: already processed log file: " + header + ".log"
55 hname = pretty_name (header)
56 header_roots[hname] = { }
62 if len (line) > 21 and line[:21] in depstring:
66 fn = re.findall(ur".*/(.*?):", line)
69 if fn[0][-2:] != ".h":
71 n = pretty_name (fn[0])
76 note = re.findall (ur"^.*note: (.*)", line)
78 sline.append (("note", note[0]))
80 err_msg = re.findall (ur"^.*: error: (.*)", line)
83 if (len (re.findall("error: forward declaration", line))) != 0:
85 path = re.findall (ur"^(.*?):.*error: ", line)
88 if path[0][-2:] != ".h":
90 fname = pretty_name (path[0])
91 if fname in ignore or fname[0:3] == "gt_":
93 sline.append (("error", msg, fname, incfrom))
95 print str(len(sline)) + " lines to process"
98 if line[0] != "note" and lastline[0] == "error":
101 incfrom = lastline[3]
104 if len(incfrom) != 0:
106 string = string + t + " : "
108 if ee not in extra_edges:
109 extra_edges.append (ee)
113 if hname not in nodes:
115 if fname not in nodes:
116 nodes.append (ofname)
122 if header_roots[hname].get(fname) == None:
123 header_roots[hname][fname] = list()
124 if msg not in header_roots[hname][fname]:
125 print string + ofname + " : " +msg
126 header_roots[hname][fname].append (msg)
130 dotname = "graph.dot"
131 graphname = "graph.png"
134 def build_dot_file (file_list):
135 output = open(dotname, "w")
136 output.write ("digraph incweb {\n");
138 if os.path.exists (x) and x[-4:] == ".log":
140 logfile = open(x).read().splitlines()
141 process_log_file (header, logfile)
142 elif os.path.exists (x + ".log"):
143 logfile = open(x + ".log").read().splitlines()
144 process_log_file (x, logfile)
148 label = n + " [ label = \"" + fn + "\" ];"
149 output.write (label + "\n")
150 if os.path.exists (fn):
151 h = open(fn).read().splitlines()
153 t = find_pound_include (l, True, False)
156 if t in ignore or t[-2:] != "_h":
161 if ee not in extra_edges:
162 extra_edges.append (ee)
165 for h in header_roots:
166 for dep in header_roots[h]:
167 label = " [ label = "+ str(len(header_roots[h][dep])) + " ];"
168 string = h + " -> " + dep + label
169 output.write (string + "\n");
171 depcount.append ((h, dep, len(header_roots[h][dep])))
173 for ee in extra_edges:
174 string = ee[0] + " -> " + ee[1] + "[ color=red ];"
175 output.write (string + "\n");
179 depcount.sort(key=lambda tup:tup[2])
181 print " ("+str(x[2])+ ") : " + x[0] + " -> " + x[1]
182 if (x[2] <= verbosity):
183 for l in header_roots[x[0]][x[1]]:
186 output.write ("}\n");
192 for arg in sys.argv[1:]:
194 dotname = arg[2:]+".dot"
195 graphname = arg[2:]+".png"
196 elif arg[0:2] == "-h":
198 elif arg[0:2] == "-v":
201 verbosity = int (arg[2:])
204 elif arg[0:1] == "-":
205 print "Unrecognized option " + arg
210 if len(sys.argv) == 1:
214 print "Parses the log files from the reduce-headers tool to generate"
215 print "dependency graphs for the include web for specified files."
216 print "Usage: [-nnum] [-h] [-v[n]] [-ooutput] file1 [[file2] ... [filen]]"
217 print " -ooutput : Specifies output to output.dot and output.png"
218 print " Defaults to 'graph.dot and graph.png"
219 print " -vn : verbose mode, shows the number of connections, and if n"
220 print " is specified, show the messages if # < n. 9 is infinity"
224 build_dot_file (files)
225 os.system ("dot -Tpng " + dotname + " -o" + graphname)