PR target/82112
[official-gcc.git] / contrib / header-tools / graph-header-logs
blobe537aaeac0c52548474985179ede40e33150cf06
1 #! /usr/bin/python2
2 import os.path
3 import sys
4 import shlex
5 import re
7 from headerutils import *
9 header_roots = { }
10 extra_edges = list()
11 verbose = False
12 verbosity = 0
13 nodes = list()
15 def unpretty (name):
16   if name[-2:] == "_h":
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",
28              "insn_modes_h",
29              "signop_h",
30              "wide_int_h",
31              "wide_int_print_h",
32              "insn_modes_inline_h",
33              "machmode_h",
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" ]
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))
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
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)
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;
133 dotname = "graph.dot"
134 graphname = "graph.png"
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)
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)
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])))
176   for ee in extra_edges:
177     string = ee[0] + " -> " + ee[1] + "[ color=red ];"
178     output.write (string + "\n");
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
189   output.write ("}\n");
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
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)