PR 68115/libfortran
[official-gcc.git] / contrib / header-tools / graph-header-logs
blobd4febd7f5710360eb9c6ddc95b0e2db2671407e8
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              "machmode_h",
29              "signop_h",
30              "wide_int_h",
31              "double_int_h",
32              "real_h",
33              "fixed_value_h",
34              "hash_table_h",
35                "statistics_h",
36                "ggc_h",
37                "vec_h",
38                "hashtab_h",
39                "inchash_h",
40                "mem_stats_traits_h",
41                "hash_map_traits_h",
42                "mem_stats_h",
43                "hash_map_h",
44              "hash_set_h",
45              "input_h",
46                "line_map_h",
47              "is_a_h",
48            "system_h",
49            "config_h" ]
51 def process_log_file (header, logfile):
52   if header_roots.get (header) != None:
53     print "Error: already processed log file: " + header + ".log"
54     return
55   hname = pretty_name (header)
56   header_roots[hname] = { }
57   
58   sline = list();
59   incfrom = list()
60   newinc = True
61   for line in logfile:
62     if len (line) > 21 and line[:21] in depstring:
63       if newinc:
64         incfrom = list()
65         newinc = False
66       fn = re.findall(ur".*/(.*?):", line)
67       if len(fn) != 1:
68         continue
69       if fn[0][-2:] != ".h":
70         continue
71       n = pretty_name (fn[0])
72       if n not in ignore:
73         incfrom.append (n)
74       continue
75     newinc = True
76     note = re.findall (ur"^.*note: (.*)", line)
77     if len(note) > 0:
78       sline.append (("note", note[0]))
79     else:
80       err_msg = re.findall (ur"^.*: error: (.*)", line)
81       if len(err_msg) == 1:
82         msg = err_msg[0]
83         if (len (re.findall("error: forward declaration", line))) != 0:
84           continue
85         path = re.findall (ur"^(.*?):.*error: ", line)
86         if len(path) != 1:
87           continue
88         if path[0][-2:] != ".h":
89           continue
90         fname = pretty_name (path[0])
91         if fname in ignore or fname[0:3] == "gt_":
92           continue
93         sline.append (("error", msg, fname, incfrom))
95   print str(len(sline)) + " lines to process"
96   lastline = "note"
97   for line in sline:
98     if line[0] != "note" and lastline[0] == "error":
99       fname = lastline[2]
100       msg = lastline[1]
101       incfrom = lastline[3]
102       string = ""
103       ofname = fname
104       if len(incfrom) != 0:
105         for t in incfrom:
106           string = string + t + " : "
107           ee = (fname, t)
108           if ee not in extra_edges:
109             extra_edges.append (ee)
110           fname = t
111           print string
113       if hname not in nodes:
114         nodes.append(hname)
115       if fname not in nodes:
116         nodes.append (ofname)
117       for y in incfrom:
118         if y not in nodes:
119           nodes.append (y)
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)
127     lastline = line;
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");
137   for x in file_list:
138     if os.path.exists (x) and x[-4:] == ".log":
139       header =  x[:-4]
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)
146   for n in nodes:
147     fn = unpretty(n)
148     label = n + " [ label = \"" + fn  + "\" ];"
149     output.write (label + "\n")
150     if os.path.exists (fn):
151       h = open(fn).read().splitlines()
152       for l in h:
153         t = find_pound_include (l, True, False)
154         if t != "":
155           t = pretty_name (t)
156           if t in ignore or t[-2:] != "_h":
157             continue
158           if t not in nodes:
159             nodes.append (t)
160           ee = (t, n)
161           if ee not in extra_edges:
162             extra_edges.append (ee)
164   depcount = list()
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");
170       if verbose:
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");
177   
178   if verbose:
179     depcount.sort(key=lambda tup:tup[2])
180     for x in depcount:
181       print " ("+str(x[2])+ ") : " + x[0] + " -> " + x[1]
182       if (x[2] <= verbosity):
183         for l in header_roots[x[0]][x[1]]:
184           print "            " + l
186   output.write ("}\n");
189 files = list()
190 dohelp = False
191 edge_thresh = 0
192 for arg in sys.argv[1:]:
193   if arg[0:2] == "-o":
194     dotname = arg[2:]+".dot"
195     graphname = arg[2:]+".png"
196   elif arg[0:2] == "-h":
197     dohelp = True
198   elif arg[0:2] == "-v":
199     verbose = True
200     if len(arg) > 2:
201       verbosity = int (arg[2:])
202       if (verbosity == 9):
203         verbosity = 9999
204   elif arg[0:1] == "-":
205     print "Unrecognized option " + arg
206     dohelp = True
207   else:
208     files.append (arg)
209     
210 if len(sys.argv) == 1:
211   dohelp = True
213 if dohelp:
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"
221   print "       -h : help"
222 else:
223   print files
224   build_dot_file (files)
225   os.system ("dot -Tpng " + dotname + " -o" + graphname)