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