Home | History | Annotate | Line # | Download | only in header-tools
      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