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