gcc-order-headers revision 1.1 1 1.1 mrg #! /usr/bin/python2
2 1.1 mrg import os
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 import Queue
9 1.1 mrg
10 1.1 mrg file_list = list ()
11 1.1 mrg usage = False
12 1.1 mrg
13 1.1 mrg ignore_conditional = False
14 1.1 mrg
15 1.1 mrg order = [
16 1.1 mrg "system.h",
17 1.1 mrg "coretypes.h",
18 1.1 mrg "backend.h",
19 1.1 mrg "target.h",
20 1.1 mrg "rtl.h",
21 1.1 mrg "c-family/c-target.h",
22 1.1 mrg "c-family/c-target-def.h",
23 1.1 mrg "tree.h",
24 1.1 mrg "cp/cp-tree.h",
25 1.1 mrg "c-family/c-common.h", # these must come before diagnostic.h
26 1.1 mrg "c/c-tree.h",
27 1.1 mrg "fortran/gfortran.h",
28 1.1 mrg "gimple.h",
29 1.1 mrg "cfghooks.h",
30 1.1 mrg "df.h",
31 1.1 mrg "tm_p.h",
32 1.1 mrg "gimple-iterators.h",
33 1.1 mrg "ssa.h",
34 1.1 mrg "expmed.h",
35 1.1 mrg "optabs.h",
36 1.1 mrg "regs.h",
37 1.1 mrg "ira.h",
38 1.1 mrg "ira-int.h",
39 1.1 mrg "gimple-streamer.h"
40 1.1 mrg
41 1.1 mrg ]
42 1.1 mrg
43 1.1 mrg exclude_special = [ "bversion.h", "obstack.h", "insn-codes.h", "hooks.h" ]
44 1.1 mrg
45 1.1 mrg # includes is a dictionary indexed by a header files basename.
46 1.1 mrg # it consists of a 2 element tuple:
47 1.1 mrg # [0] - Name of header file which included this header.
48 1.1 mrg # [1] - vector of header file names included by this file.
49 1.1 mrg
50 1.1 mrg includes = { }
51 1.1 mrg
52 1.1 mrg # when a header is included multiple times, indexing this dictionary will
53 1.1 mrg # return a vector of all the headers which included it.
54 1.1 mrg dups = { }
55 1.1 mrg
56 1.1 mrg # When creating the master list, do not descend into these files for what
57 1.1 mrg # they include. Simply put the file itself in the list. This is primarily
58 1.1 mrg # required because the front end files inlcude orders tend to be at odds with
59 1.1 mrg # the order of middle end files, and its impossible to synchronize them.\
60 1.1 mrg # They are ordered such that everything resolves properly.
61 1.1 mrg exclude_processing = [ "tree-vectorizer.h" , "c-target.h", "c-target-def.h", "cp-tree.h", "c-common.h", "c-tree.h", "gfortran.h" ]
62 1.1 mrg
63 1.1 mrg master_list = list ()
64 1.1 mrg # where include file comes from in src
65 1.1 mrg h_from = { }
66 1.1 mrg
67 1.1 mrg # create the master ordering list... this is the desired order of headers
68 1.1 mrg def create_master_list (fn, verbose):
69 1.1 mrg if fn not in exclude_processing:
70 1.1 mrg for x in includes[fn][1]:
71 1.1 mrg create_master_list (x, verbose)
72 1.1 mrg if not fn in master_list:
73 1.1 mrg # Don't put diagnostic*.h into the ordering list. It is special since
74 1.1 mrg # various front ends have to set GCC_DIAG_STYLE before including it.
75 1.1 mrg # for each file, we'll tailor where it belongs by looking at the include
76 1.1 mrg # list and determine its position appropriately.
77 1.1 mrg if fn != "diagnostic.h" and fn != "diagnostic-core.h":
78 1.1 mrg master_list.append (fn)
79 1.1 mrg if (verbose):
80 1.1 mrg print fn + " included by: " + includes[fn][0]
81 1.1 mrg
82 1.1 mrg
83 1.1 mrg
84 1.1 mrg def print_dups ():
85 1.1 mrg if dups:
86 1.1 mrg print "\nduplicated includes"
87 1.1 mrg for i in dups:
88 1.1 mrg string = "dup : " + i + " : "
89 1.1 mrg string += includes[i][0]
90 1.1 mrg for i2 in dups[i]:
91 1.1 mrg string += ", "+i2
92 1.1 mrg print string
93 1.1 mrg
94 1.1 mrg
95 1.1 mrg def process_known_dups ():
96 1.1 mrg # rtl.h gets tagged as a duplicate includer for all of coretypes.h, but that
97 1.1 mrg # is really for only generator files
98 1.1 mrg rtl_remove = includes["coretypes.h"][1] + ["statistics.h", "vec.h"]
99 1.1 mrg if dups:
100 1.1 mrg for i in rtl_remove:
101 1.1 mrg if dups[i] and "rtl.h" in dups[i]:
102 1.1 mrg dups[i].remove("rtl.h")
103 1.1 mrg if not dups[i]:
104 1.1 mrg dups.pop (i, None)
105 1.1 mrg
106 1.1 mrg # make sure diagnostic.h is the owner of diagnostic-core.h
107 1.1 mrg if includes["diagnostic-core.h"][0] != "diagnostic.h":
108 1.1 mrg dups["diagnostic-core.h"].append (includes["diagnostic-core.h"][0])
109 1.1 mrg includes["diagnostic-core.h"] = ("diagnostic.h", includes["diagnostic-core.h"][1])
110 1.1 mrg
111 1.1 mrg # This function scans back thorugh the list of headers which included other
112 1.1 mrg # headers to determine what file in HEADER_LIST brought 'HEADER' in.
113 1.1 mrg def indirectly_included (header, header_list):
114 1.1 mrg nm = os.path.basename (header)
115 1.1 mrg while nm and includes.get(nm):
116 1.1 mrg if includes[nm][0] in header_list:
117 1.1 mrg return includes[nm][0]
118 1.1 mrg nm = includes[nm][0]
119 1.1 mrg
120 1.1 mrg # diagnostic.h and diagnostic-core.h may not show up because we removed them
121 1.1 mrg # from the header list to manually position in an appropriate place. They have
122 1.1 mrg # specific requirements that they need to occur after certain FE files which
123 1.1 mrg # may overide the definition of GCC_DIAG_STYLE.
124 1.1 mrg # Check the dup list for whete they may have been included from and return
125 1.1 mrg # that header.
126 1.1 mrg if header == "diagnostic-core.h":
127 1.1 mrg if dups.get("diagnostic-core.h"):
128 1.1 mrg for f in dups["diagnostic-core.h"]:
129 1.1 mrg if f in header_list:
130 1.1 mrg return f
131 1.1 mrg else:
132 1.1 mrg if header in header_list:
133 1.1 mrg return header
134 1.1 mrg # Now check if diagnostics is included indirectly anywhere
135 1.1 mrg header = "diagnostic.h"
136 1.1 mrg
137 1.1 mrg if header == "diagnostic.h":
138 1.1 mrg if dups.get("diagnostic.h"):
139 1.1 mrg for f in dups["diagnostic.h"]:
140 1.1 mrg if f in header_list:
141 1.1 mrg return f
142 1.1 mrg else:
143 1.1 mrg if header in header_list:
144 1.1 mrg return header
145 1.1 mrg
146 1.1 mrg return ""
147 1.1 mrg
148 1.1 mrg
149 1.1 mrg # This function will take a list of headers from a source file and return
150 1.1 mrg # the desired new new order of the canonical headers in DESIRED_ORDER.
151 1.1 mrg def get_new_order (src_h, desired_order):
152 1.1 mrg new_order = list ()
153 1.1 mrg for h in desired_order:
154 1.1 mrg if h in master_list:
155 1.1 mrg # Create the list of nested headers which included this file.
156 1.1 mrg iclist = list ()
157 1.1 mrg ib = includes[h][0]
158 1.1 mrg while ib:
159 1.1 mrg iclist.insert(0, ib)
160 1.1 mrg ib = includes[ib][0]
161 1.1 mrg if iclist:
162 1.1 mrg for x in iclist:
163 1.1 mrg # If header is in the source code, and we are allowed to look inside
164 1.1 mrg if x in src_h and x not in exclude_processing:
165 1.1 mrg if x not in new_order and x[:10] != "diagnostic" and h not in exclude_special:
166 1.1 mrg new_order.append (x)
167 1.1 mrg break;
168 1.1 mrg else:
169 1.1 mrg if h not in new_order:
170 1.1 mrg new_order.append (h)
171 1.1 mrg
172 1.1 mrg f = ""
173 1.1 mrg if "diagnostic.h" in src_h:
174 1.1 mrg f = "diagnostic.h"
175 1.1 mrg elif "diagnostic-core.h" in src_h:
176 1.1 mrg f = "diagnostic-core.h"
177 1.1 mrg
178 1.1 mrg
179 1.1 mrg # If either diagnostic header was directly included in the main file, check to
180 1.1 mrg # see if its already included indirectly, or whether we need to add it to the
181 1.1 mrg # end of the canonically orders headers.
182 1.1 mrg if f:
183 1.1 mrg ii = indirectly_included (f, src_h)
184 1.1 mrg if not ii or ii == f:
185 1.1 mrg new_order.append (f)
186 1.1 mrg
187 1.1 mrg return new_order
188 1.1 mrg
189 1.1 mrg
190 1.1 mrg
191 1.1 mrg # stack of files to process
192 1.1 mrg process_stack = list ()
193 1.1 mrg
194 1.1 mrg def process_one (info):
195 1.1 mrg i = info[0]
196 1.1 mrg owner = info[1]
197 1.1 mrg name = os.path.basename(i)
198 1.1 mrg if os.path.exists (i):
199 1.1 mrg if includes.get(name) == None:
200 1.1 mrg l = find_unique_include_list (i)
201 1.1 mrg # create a list which has just basenames in it
202 1.1 mrg new_list = list ()
203 1.1 mrg for x in l:
204 1.1 mrg new_list.append (os.path.basename (x))
205 1.1 mrg process_stack.append((x, name))
206 1.1 mrg includes[name] = (owner, new_list)
207 1.1 mrg elif owner:
208 1.1 mrg if dups.get(name) == None:
209 1.1 mrg dups[name] = [ owner ]
210 1.1 mrg else:
211 1.1 mrg dups[name].append (owner)
212 1.1 mrg else:
213 1.1 mrg # seed tm.h with options.h since it is a build file and won't be seen.
214 1.1 mrg if not includes.get(name):
215 1.1 mrg if name == "tm.h":
216 1.1 mrg includes[name] = (owner, [ "options.h" ])
217 1.1 mrg includes["options.h"] = ("tm.h", list ())
218 1.1 mrg else:
219 1.1 mrg includes[name] = (owner, list ())
220 1.1 mrg
221 1.1 mrg
222 1.1 mrg show_master = False
223 1.1 mrg
224 1.1 mrg for arg in sys.argv[1:]:
225 1.1 mrg if arg[0:1] == "-":
226 1.1 mrg if arg[0:2] == "-h":
227 1.1 mrg usage = True
228 1.1 mrg elif arg[0:2] == "-i":
229 1.1 mrg ignore_conditional = True
230 1.1 mrg elif arg[0:2] == "-v":
231 1.1 mrg show_master = True
232 1.1 mrg else:
233 1.1 mrg print "Error: unrecognized option " + arg
234 1.1 mrg elif os.path.exists(arg):
235 1.1 mrg file_list.append (arg)
236 1.1 mrg else:
237 1.1 mrg print "Error: file " + arg + " Does not exist."
238 1.1 mrg usage = True
239 1.1 mrg
240 1.1 mrg if not file_list and not show_master:
241 1.1 mrg usage = True
242 1.1 mrg
243 1.1 mrg if not usage and not os.path.exists ("coretypes.h"):
244 1.1 mrg usage = True
245 1.1 mrg print "Error: Must run command in main gcc source directory containing coretypes.h\n"
246 1.1 mrg
247 1.1 mrg # process diagnostic.h first.. it's special since GCC_DIAG_STYLE can be
248 1.1 mrg # overridden by languages, but must be done so by a file included BEFORE it.
249 1.1 mrg # so make sure it isn't seen as included by one of those files by making it
250 1.1 mrg # appear to be included by the src file.
251 1.1 mrg process_stack.insert (0, ("diagnostic.h", ""))
252 1.1 mrg
253 1.1 mrg # Add the list of files in reverse order since it is processed as a stack later
254 1.1 mrg for i in order:
255 1.1 mrg process_stack.insert (0, (i, "") )
256 1.1 mrg
257 1.1 mrg # build up the library of what header files include what other files.
258 1.1 mrg while process_stack:
259 1.1 mrg info = process_stack.pop ()
260 1.1 mrg process_one (info)
261 1.1 mrg
262 1.1 mrg # Now create the master ordering list
263 1.1 mrg for i in order:
264 1.1 mrg create_master_list (os.path.basename (i), show_master)
265 1.1 mrg
266 1.1 mrg # handle warts in the duplicate list
267 1.1 mrg process_known_dups ()
268 1.1 mrg desired_order = master_list
269 1.1 mrg
270 1.1 mrg if show_master:
271 1.1 mrg print " Canonical order of gcc include files: "
272 1.1 mrg for x in master_list:
273 1.1 mrg print x
274 1.1 mrg print " "
275 1.1 mrg
276 1.1 mrg if usage:
277 1.1 mrg print "gcc-order-headers [-i] [-v] file1 [filen]"
278 1.1 mrg print " Ensures gcc's headers files are included in a normalized form with"
279 1.1 mrg print " redundant headers removed. The original files are saved in filename.bak"
280 1.1 mrg print " Outputs a list of files which changed."
281 1.1 mrg print " -i ignore conditional compilation."
282 1.1 mrg print " Use after examining the file to be sure includes within #ifs are safe"
283 1.1 mrg print " Any headers within conditional sections will be ignored."
284 1.1 mrg print " -v Show the canonical order of known headers"
285 1.1 mrg sys.exit(0)
286 1.1 mrg
287 1.1 mrg
288 1.1 mrg didnt_do = list ()
289 1.1 mrg
290 1.1 mrg for fn in file_list:
291 1.1 mrg nest = 0
292 1.1 mrg src_h = list ()
293 1.1 mrg src_line = { }
294 1.1 mrg
295 1.1 mrg master_list = list ()
296 1.1 mrg
297 1.1 mrg includes = { }
298 1.1 mrg dups = { }
299 1.1 mrg
300 1.1 mrg iinfo = process_ii_src (fn)
301 1.1 mrg src = ii_src (iinfo)
302 1.1 mrg include_list = ii_include_list (iinfo)
303 1.1 mrg
304 1.1 mrg if ii_include_list_cond (iinfo):
305 1.1 mrg if not ignore_conditional:
306 1.1 mrg print fn + ": Cannot process due to conditional compilation of includes"
307 1.1 mrg didnt_do.append (fn)
308 1.1 mrg src = list ()
309 1.1 mrg
310 1.1 mrg if not src:
311 1.1 mrg continue
312 1.1 mrg
313 1.1 mrg process_stack = list ()
314 1.1 mrg # prime the stack with headers in the main ordering list so we get them in
315 1.1 mrg # this order.
316 1.1 mrg for d in order:
317 1.1 mrg if d in include_list:
318 1.1 mrg process_stack.insert (0, (d, ""))
319 1.1 mrg
320 1.1 mrg for d in include_list:
321 1.1 mrg nm = os.path.basename(d)
322 1.1 mrg src_h.append (nm)
323 1.1 mrg iname = d
324 1.1 mrg iname2 = os.path.dirname (fn) + "/" + d
325 1.1 mrg if not os.path.exists (d) and os.path.exists (iname2):
326 1.1 mrg iname = iname2
327 1.1 mrg if iname not in process_stack:
328 1.1 mrg process_stack.insert (0, (iname, ""))
329 1.1 mrg src_line[nm] = ii_src_line(iinfo)[d]
330 1.1 mrg if src_line[nm].find("/*") != -1 and src_line[nm].find("*/") == -1:
331 1.1 mrg # this means we have a multi line comment, abort!'
332 1.1 mrg print fn + ": Cannot process due to a multi-line comment :"
333 1.1 mrg print " " + src_line[nm]
334 1.1 mrg if fn not in didnt_do:
335 1.1 mrg didnt_do.append (fn)
336 1.1 mrg src = list ()
337 1.1 mrg
338 1.1 mrg if not src:
339 1.1 mrg continue
340 1.1 mrg
341 1.1 mrg # Now create the list of includes as seen by the source file.
342 1.1 mrg while process_stack:
343 1.1 mrg info = process_stack.pop ()
344 1.1 mrg process_one (info)
345 1.1 mrg
346 1.1 mrg for i in include_list:
347 1.1 mrg create_master_list (os.path.basename (i), False)
348 1.1 mrg
349 1.1 mrg new_src = list ()
350 1.1 mrg header_added = list ()
351 1.1 mrg new_order = list ()
352 1.1 mrg for line in src:
353 1.1 mrg d = find_pound_include (line, True, True)
354 1.1 mrg if not d or d[-2:] != ".h":
355 1.1 mrg new_src.append (line)
356 1.1 mrg else:
357 1.1 mrg if d == order[0] and not new_order:
358 1.1 mrg new_order = get_new_order (src_h, desired_order)
359 1.1 mrg for i in new_order:
360 1.1 mrg new_src.append (src_line[i])
361 1.1 mrg # if not seen, add it.
362 1.1 mrg if i not in header_added:
363 1.1 mrg header_added.append (i)
364 1.1 mrg else:
365 1.1 mrg nm = os.path.basename(d)
366 1.1 mrg if nm not in header_added:
367 1.1 mrg iby = indirectly_included (nm, src_h)
368 1.1 mrg if not iby:
369 1.1 mrg new_src.append (line)
370 1.1 mrg header_added.append (nm)
371 1.1 mrg
372 1.1 mrg if src != new_src:
373 1.1 mrg os.rename (fn, fn + ".bak")
374 1.1 mrg fl = open(fn,"w")
375 1.1 mrg for line in new_src:
376 1.1 mrg fl.write (line)
377 1.1 mrg fl.close ()
378 1.1 mrg print fn
379 1.1 mrg
380 1.1 mrg
381 1.1 mrg if didnt_do:
382 1.1 mrg print "\n\n Did not process the following files due to conditional dependencies:"
383 1.1 mrg str = ""
384 1.1 mrg for x in didnt_do:
385 1.1 mrg str += x + " "
386 1.1 mrg print str
387 1.1 mrg print "\n"
388 1.1 mrg print "Please examine to see if they are safe to process, and re-try with -i. "
389 1.1 mrg print "Safeness is determined by checking whether any of the reordered headers are"
390 1.1 mrg print "within a conditional and could be hauled out of the conditional, thus changing"
391 1.1 mrg print "what the compiler will see."
392 1.1 mrg print "Multi-line comments after a #include can also cause failuer, they must be turned"
393 1.1 mrg print "into single line comments or removed."
394 1.1 mrg
395 1.1 mrg
396 1.1 mrg
397 1.1 mrg
398