Home | History | Annotate | Line # | Download | only in header-tools
      1  1.1  mrg #! /usr/bin/python2
      2  1.1  mrg import os.path
      3  1.1  mrg import sys
      4  1.1  mrg import shlex
      5  1.1  mrg import re
      6  1.1  mrg import tempfile
      7  1.1  mrg import copy
      8  1.1  mrg 
      9  1.1  mrg from headerutils import *
     10  1.1  mrg 
     11  1.1  mrg requires = { }
     12  1.1  mrg provides = { }
     13  1.1  mrg 
     14  1.1  mrg no_remove = [ "system.h", "coretypes.h", "config.h" , "bconfig.h", "backend.h" ]
     15  1.1  mrg 
     16  1.1  mrg # These targets are the ones which provide "coverage".  Typically, if any
     17  1.1  mrg # target is going to fail compilation, it's one of these.  This was determined
     18  1.1  mrg # during the initial runs of reduce-headers... On a full set of target builds,
     19  1.1  mrg # every failure which occured was triggered by one of these.  
     20  1.1  mrg # This list is used during target-list construction simply to put any of these
     21  1.1  mrg # *first* in the candidate list, increasing the probability that a failure is 
     22  1.1  mrg # found quickly.
     23  1.1  mrg target_priority = [
     24  1.1  mrg     "aarch64-linux-gnu",
     25  1.1  mrg     "arm-netbsdelf",
     26  1.1  mrg     "c6x-elf",
     27  1.1  mrg     "epiphany-elf",
     28  1.1  mrg     "hppa2.0-hpux10.1",
     29  1.1  mrg     "i686-mingw32crt",
     30  1.1  mrg     "i686-pc-msdosdjgpp",
     31  1.1  mrg     "mipsel-elf",
     32  1.1  mrg     "powerpc-eabisimaltivec",
     33  1.1  mrg     "rs6000-ibm-aix5.1.0",
     34  1.1  mrg     "sh-superh-elf",
     35  1.4  mrg     "sparc64-elf"
     36  1.1  mrg ]
     37  1.1  mrg 
     38  1.1  mrg 
     39  1.1  mrg target_dir = ""
     40  1.1  mrg build_dir = ""
     41  1.1  mrg ignore_list = list()
     42  1.1  mrg target_builds = list()
     43  1.1  mrg 
     44  1.1  mrg target_dict = { }
     45  1.1  mrg header_dict = { }
     46  1.1  mrg search_path = [ ".", "../include", "../libcpp/include" ]
     47  1.1  mrg 
     48  1.1  mrg remove_count = { }
     49  1.1  mrg 
     50  1.1  mrg 
     51  1.1  mrg # Given a header name, normalize it.  ie.  cp/cp-tree.h could be in gcc, while
     52  1.1  mrg # the same header could be referenced from within the cp subdirectory as
     53  1.1  mrg # just cp-tree.h
     54  1.1  mrg # for now, just assume basenames are unique
     55  1.1  mrg 
     56  1.1  mrg def normalize_header (header):
     57  1.1  mrg   return os.path.basename (header)
     58  1.1  mrg 
     59  1.1  mrg 
     60  1.1  mrg # Adds a header file and its sub-includes to the global dictionary if they
     61  1.1  mrg # aren't already there.  Specify s_path since different build directories may
     62  1.1  mrg # append themselves on demand to the global list.
     63  1.1  mrg # return entry for the specified header, knowing all sub entries are completed
     64  1.1  mrg 
     65  1.1  mrg def get_header_info (header, s_path):
     66  1.1  mrg   global header_dict
     67  1.1  mrg   global empty_iinfo
     68  1.1  mrg   process_list = list ()
     69  1.1  mrg   location = ""
     70  1.1  mrg   bname = ""
     71  1.1  mrg   bname_iinfo = empty_iinfo
     72  1.1  mrg   for path in s_path:
     73  1.1  mrg     if os.path.exists (path + "/" + header):
     74  1.1  mrg       location = path + "/" + header
     75  1.1  mrg       break
     76  1.1  mrg 
     77  1.1  mrg   if location:
     78  1.1  mrg     bname = normalize_header (location)
     79  1.1  mrg     if header_dict.get (bname):
     80  1.1  mrg       bname_iinfo = header_dict[bname]
     81  1.1  mrg       loc2 = ii_path (bname_iinfo)+ "/" + bname
     82  1.1  mrg       if loc2[:2] == "./":
     83  1.1  mrg         loc2 = loc2[2:]
     84  1.1  mrg       if location[:2] == "./":
     85  1.1  mrg         location = location[2:]
     86  1.1  mrg       if loc2 != location:
     87  1.1  mrg         # Don't use the cache if it isnt the right one.
     88  1.1  mrg         bname_iinfo = process_ii_macro (location)
     89  1.1  mrg       return bname_iinfo
     90  1.1  mrg 
     91  1.1  mrg     bname_iinfo = process_ii_macro (location)
     92  1.1  mrg     header_dict[bname] = bname_iinfo
     93  1.1  mrg     # now decend into the include tree
     94  1.1  mrg     for i in ii_include_list (bname_iinfo):
     95  1.1  mrg       get_header_info (i, s_path)
     96  1.1  mrg   else:
     97  1.1  mrg     # if the file isnt in the source directories, look in the build and target
     98  1.1  mrg     # directories. If it is here, then aggregate all the versions.
     99  1.1  mrg     location = build_dir + "/gcc/" + header
    100  1.1  mrg     build_inc = target_inc = False
    101  1.1  mrg     if os.path.exists (location):
    102  1.1  mrg       build_inc = True
    103  1.1  mrg     for x in target_dict:
    104  1.1  mrg       location = target_dict[x] + "/gcc/" + header
    105  1.1  mrg       if os.path.exists (location):
    106  1.1  mrg         target_inc = True
    107  1.1  mrg         break
    108  1.1  mrg 
    109  1.1  mrg     if (build_inc or target_inc):
    110  1.1  mrg       bname = normalize_header(header)
    111  1.1  mrg       defines = set()
    112  1.1  mrg       consumes = set()
    113  1.1  mrg       incl = set()
    114  1.1  mrg       if build_inc:
    115  1.1  mrg         iinfo = process_ii_macro (build_dir + "/gcc/" + header)
    116  1.1  mrg         defines = set (ii_macro_define (iinfo))
    117  1.1  mrg         consumes = set (ii_macro_consume (iinfo))
    118  1.1  mrg         incl = set (ii_include_list (iinfo))
    119  1.1  mrg 
    120  1.1  mrg       if (target_inc):
    121  1.1  mrg         for x in target_dict:
    122  1.1  mrg           location = target_dict[x] + "/gcc/" + header
    123  1.1  mrg           if os.path.exists (location):
    124  1.1  mrg             iinfo = process_ii_macro (location)
    125  1.1  mrg             defines.update (ii_macro_define (iinfo))
    126  1.1  mrg             consumes.update (ii_macro_consume (iinfo))
    127  1.1  mrg             incl.update (ii_include_list (iinfo))
    128  1.1  mrg 
    129  1.1  mrg       bname_iinfo = (header, "build", list(incl), list(), list(consumes), list(defines), list(), list())
    130  1.1  mrg 
    131  1.1  mrg       header_dict[bname] = bname_iinfo
    132  1.1  mrg       for i in incl:
    133  1.1  mrg         get_header_info (i, s_path)
    134  1.1  mrg 
    135  1.1  mrg   return bname_iinfo
    136  1.1  mrg 
    137  1.1  mrg 
    138  1.1  mrg # return a list of all headers brought in by this header
    139  1.1  mrg def all_headers (fname):
    140  1.1  mrg   global header_dict
    141  1.1  mrg   headers_stack = list()
    142  1.1  mrg   headers_list = list()
    143  1.1  mrg   if header_dict.get (fname) == None:
    144  1.1  mrg     return list ()
    145  1.1  mrg   for y in ii_include_list (header_dict[fname]):
    146  1.1  mrg     headers_stack.append (y)
    147  1.1  mrg 
    148  1.1  mrg   while headers_stack:
    149  1.1  mrg     h = headers_stack.pop ()
    150  1.1  mrg     hn = normalize_header (h)
    151  1.1  mrg     if hn not in headers_list:
    152  1.1  mrg       headers_list.append (hn)
    153  1.1  mrg       if header_dict.get(hn):
    154  1.1  mrg         for y in ii_include_list (header_dict[hn]):
    155  1.1  mrg           if normalize_header (y) not in headers_list:
    156  1.1  mrg             headers_stack.append (y)
    157  1.1  mrg 
    158  1.1  mrg   return headers_list
    159  1.1  mrg 
    160  1.1  mrg 
    161  1.1  mrg 
    162  1.1  mrg 
    163  1.1  mrg # Search bld_dir for all target tuples, confirm that they have a build path with
    164  1.1  mrg # bld_dir/target-tuple/gcc, and build a dictionary of build paths indexed by
    165  1.1  mrg # target tuple..
    166  1.1  mrg 
    167  1.1  mrg def build_target_dict (bld_dir, just_these):
    168  1.1  mrg   global target_dict
    169  1.1  mrg   target_doct = { }
    170  1.1  mrg   error = False
    171  1.1  mrg   if os.path.exists (bld_dir):
    172  1.1  mrg     if just_these:
    173  1.1  mrg       ls = just_these
    174  1.1  mrg     else:
    175  1.1  mrg       ls = os.listdir(bld_dir)
    176  1.1  mrg     for t in ls:
    177  1.1  mrg       if t.find("-") != -1:
    178  1.1  mrg         target = t.strip()
    179  1.1  mrg         tpath = bld_dir + "/" + target
    180  1.1  mrg         if not os.path.exists (tpath + "/gcc"):
    181  1.1  mrg           print "Error: gcc build directory for target " + t + " Does not exist: " + tpath + "/gcc"
    182  1.1  mrg           error = True
    183  1.1  mrg         else:
    184  1.1  mrg           target_dict[target] = tpath
    185  1.1  mrg 
    186  1.1  mrg   if error:
    187  1.1  mrg     target_dict = { }
    188  1.1  mrg 
    189  1.1  mrg def get_obj_name (src_file):
    190  1.1  mrg   if src_file[-2:] == ".c":
    191  1.1  mrg     return src_file.replace (".c", ".o")
    192  1.1  mrg   elif src_file[-3:] == ".cc":
    193  1.1  mrg     return src_file.replace (".cc", ".o")
    194  1.1  mrg   return ""
    195  1.1  mrg 
    196  1.1  mrg def target_obj_exists (target, obj_name):
    197  1.1  mrg   global target_dict
    198  1.1  mrg   # look in a subdir if src has a subdir, then check gcc base directory.
    199  1.1  mrg   if target_dict.get(target):
    200  1.1  mrg     obj = target_dict[target] + "/gcc/" + obj_name
    201  1.1  mrg     if not os.path.exists (obj):
    202  1.1  mrg       obj = target_dict[target] + "/gcc/" + os.path.basename(obj_name)
    203  1.1  mrg     if os.path.exists (obj):
    204  1.1  mrg       return True
    205  1.1  mrg   return False
    206  1.1  mrg  
    207  1.1  mrg # Given a src file, return a list of targets which may build this file.
    208  1.1  mrg def find_targets (src_file):
    209  1.1  mrg   global target_dict
    210  1.1  mrg   targ_list = list()
    211  1.1  mrg   obj_name = get_obj_name (src_file)
    212  1.1  mrg   if not obj_name:
    213  1.1  mrg     print "Error: " + src_file + " - Cannot determine object name."
    214  1.1  mrg     return list()
    215  1.1  mrg 
    216  1.1  mrg   # Put the high priority targets which tend to trigger failures first
    217  1.1  mrg   for target in target_priority:
    218  1.1  mrg     if target_obj_exists (target, obj_name):
    219  1.1  mrg       targ_list.append ((target, target_dict[target]))
    220  1.1  mrg 
    221  1.1  mrg   for target in target_dict:
    222  1.1  mrg     if target not in target_priority and target_obj_exists (target, obj_name):
    223  1.1  mrg       targ_list.append ((target, target_dict[target]))
    224  1.1  mrg         
    225  1.1  mrg   return targ_list
    226  1.1  mrg 
    227  1.1  mrg 
    228  1.1  mrg def try_to_remove (src_file, h_list, verbose):
    229  1.1  mrg   global target_dict
    230  1.1  mrg   global header_dict
    231  1.1  mrg   global build_dir
    232  1.1  mrg 
    233  1.1  mrg   # build from scratch each time
    234  1.1  mrg   header_dict = { }
    235  1.1  mrg   summary = ""
    236  1.1  mrg   rmcount = 0
    237  1.1  mrg 
    238  1.1  mrg   because = { }
    239  1.1  mrg   src_info = process_ii_macro_src (src_file)
    240  1.1  mrg   src_data = ii_src (src_info)
    241  1.1  mrg   if src_data:
    242  1.1  mrg     inclist = ii_include_list_non_cond (src_info)
    243  1.1  mrg     # work is done if there are no includes to check
    244  1.1  mrg     if not inclist:
    245  1.1  mrg       return src_file + ": No include files to attempt to remove"
    246  1.1  mrg 
    247  1.1  mrg     # work on the include list in reverse.
    248  1.1  mrg     inclist.reverse()
    249  1.1  mrg 
    250  1.1  mrg     # Get the target list 
    251  1.1  mrg     targ_list = list()
    252  1.1  mrg     targ_list = find_targets (src_file)
    253  1.1  mrg 
    254  1.1  mrg     spath = search_path
    255  1.1  mrg     if os.path.dirname (src_file):
    256  1.1  mrg       spath.append (os.path.dirname (src_file))
    257  1.1  mrg 
    258  1.1  mrg     hostbuild = True
    259  1.1  mrg     if src_file.find("config/") != -1:
    260  1.1  mrg       # config files dont usually build on the host
    261  1.1  mrg       hostbuild = False
    262  1.1  mrg       obn = get_obj_name (os.path.basename (src_file))
    263  1.1  mrg       if obn and os.path.exists (build_dir + "/gcc/" + obn):
    264  1.1  mrg         hostbuild = True
    265  1.1  mrg       if not target_dict:
    266  1.1  mrg         summary = src_file + ": Target builds are required for config files.  None found."
    267  1.1  mrg         print summary
    268  1.1  mrg         return summary
    269  1.1  mrg       if not targ_list:
    270  1.1  mrg         summary =src_file + ": Cannot find any targets which build this file."
    271  1.1  mrg         print summary
    272  1.1  mrg         return summary
    273  1.1  mrg 
    274  1.1  mrg     if hostbuild:
    275  1.1  mrg       # confirm it actually builds before we do anything
    276  1.1  mrg       print "Confirming source file builds"
    277  1.1  mrg       res = get_make_output (build_dir + "/gcc", "all")
    278  1.1  mrg       if res[0] != 0:
    279  1.1  mrg         message = "Error: " + src_file + " does not build currently."
    280  1.1  mrg         summary = src_file + " does not build on host."
    281  1.1  mrg         print message
    282  1.1  mrg         print res[1]
    283  1.1  mrg         if verbose:
    284  1.1  mrg           verbose.write (message + "\n")
    285  1.1  mrg           verbose.write (res[1]+ "\n")
    286  1.1  mrg         return summary
    287  1.1  mrg 
    288  1.1  mrg     src_requires = set (ii_macro_consume (src_info))
    289  1.1  mrg     for macro in src_requires:
    290  1.1  mrg       because[macro] = src_file
    291  1.1  mrg     header_seen = list ()
    292  1.1  mrg 
    293  1.1  mrg     os.rename (src_file, src_file + ".bak")
    294  1.1  mrg     src_orig = copy.deepcopy (src_data)
    295  1.1  mrg     src_tmp = copy.deepcopy (src_data)
    296  1.1  mrg 
    297  1.1  mrg     try:
    298  1.1  mrg       # process the includes from bottom to top.  This is because we know that
    299  1.1  mrg       # later includes have are known to be needed, so any dependency from this 
    300  1.1  mrg       # header is a true dependency
    301  1.1  mrg       for inc_file in inclist:
    302  1.1  mrg         inc_file_norm = normalize_header (inc_file)
    303  1.1  mrg         
    304  1.1  mrg         if inc_file in no_remove:
    305  1.1  mrg           continue
    306  1.1  mrg         if len (h_list) != 0 and inc_file_norm not in h_list:
    307  1.1  mrg           continue
    308  1.1  mrg         if inc_file_norm[0:3] == "gt-":
    309  1.1  mrg           continue
    310  1.1  mrg         if inc_file_norm[0:6] == "gtype-":
    311  1.1  mrg           continue
    312  1.1  mrg         if inc_file_norm.replace(".h",".c") == os.path.basename(src_file):
    313  1.1  mrg           continue
    314  1.1  mrg              
    315  1.1  mrg         lookfor = ii_src_line(src_info)[inc_file]
    316  1.1  mrg         src_tmp.remove (lookfor)
    317  1.1  mrg         message = "Trying " + src_file + " without " + inc_file
    318  1.1  mrg         print message
    319  1.1  mrg         if verbose:
    320  1.1  mrg           verbose.write (message + "\n")
    321  1.1  mrg         out = open(src_file, "w")
    322  1.1  mrg         for line in src_tmp:
    323  1.1  mrg           out.write (line)
    324  1.1  mrg         out.close()
    325  1.1  mrg           
    326  1.1  mrg         keep = False
    327  1.1  mrg         if hostbuild:
    328  1.1  mrg           res = get_make_output (build_dir + "/gcc", "all")
    329  1.1  mrg         else:
    330  1.1  mrg           res = (0, "")
    331  1.1  mrg 
    332  1.1  mrg         rc = res[0]
    333  1.1  mrg         message = "Passed Host build"
    334  1.1  mrg         if (rc != 0):
    335  1.1  mrg           # host build failed
    336  1.1  mrg           message  = "Compilation failed:\n";
    337  1.1  mrg           keep = True
    338  1.1  mrg         else:
    339  1.1  mrg           if targ_list:
    340  1.1  mrg             objfile = get_obj_name (src_file)
    341  1.1  mrg             t1 = targ_list[0]
    342  1.1  mrg             if objfile and os.path.exists(t1[1] +"/gcc/"+objfile):
    343  1.1  mrg               res = get_make_output_parallel (targ_list, objfile, 0)
    344  1.1  mrg             else:
    345  1.1  mrg               res = get_make_output_parallel (targ_list, "all-gcc", 0)
    346  1.1  mrg             rc = res[0]
    347  1.1  mrg             if rc != 0:
    348  1.1  mrg               message = "Compilation failed on TARGET : " + res[2]
    349  1.1  mrg               keep = True
    350  1.1  mrg             else:
    351  1.1  mrg               message = "Passed host and target builds"
    352  1.1  mrg 
    353  1.1  mrg         if keep:
    354  1.1  mrg           print message + "\n"
    355  1.1  mrg 
    356  1.1  mrg         if (rc != 0):
    357  1.1  mrg           if verbose:
    358  1.1  mrg             verbose.write (message + "\n");
    359  1.1  mrg             verbose.write (res[1])
    360  1.1  mrg             verbose.write ("\n");
    361  1.1  mrg             if os.path.exists (inc_file):
    362  1.1  mrg               ilog = open(inc_file+".log","a")
    363  1.1  mrg               ilog.write (message + " for " + src_file + ":\n\n");
    364  1.1  mrg               ilog.write ("============================================\n");
    365  1.1  mrg               ilog.write (res[1])
    366  1.1  mrg               ilog.write ("\n");
    367  1.1  mrg               ilog.close()
    368  1.1  mrg             if os.path.exists (src_file):
    369  1.1  mrg               ilog = open(src_file+".log","a")
    370  1.1  mrg               ilog.write (message + " for " +inc_file + ":\n\n");
    371  1.1  mrg               ilog.write ("============================================\n");
    372  1.1  mrg               ilog.write (res[1])
    373  1.1  mrg               ilog.write ("\n");
    374  1.1  mrg               ilog.close()
    375  1.1  mrg 
    376  1.1  mrg         # Given a sequence where :
    377  1.1  mrg         # #include "tm.h"
    378  1.1  mrg         # #include "target.h"  // includes tm.h
    379  1.1  mrg 
    380  1.1  mrg         # target.h was required, and when attempting to remove tm.h we'd see that
    381  1.1  mrg         # all the macro defintions are "required" since they all look like:
    382  1.1  mrg         # #ifndef HAVE_blah
    383  1.1  mrg         # #define HAVE_blah
    384  1.1  mrg         # endif
    385  1.1  mrg 
    386  1.1  mrg         # when target.h was found to be required, tm.h will be tagged as included.
    387  1.1  mrg         # so when we get this far, we know we dont have to check the macros for
    388  1.1  mrg         # tm.h since we know it is already been included.
    389  1.1  mrg 
    390  1.1  mrg         if inc_file_norm not in header_seen:
    391  1.1  mrg           iinfo = get_header_info (inc_file, spath)
    392  1.1  mrg           newlist = all_headers (inc_file_norm)
    393  1.1  mrg           if ii_path(iinfo) == "build" and not target_dict:
    394  1.1  mrg             keep = True
    395  1.1  mrg             text = message + " : Will not remove a build file without some targets."
    396  1.1  mrg             print text
    397  1.1  mrg             ilog = open(src_file+".log","a")
    398  1.1  mrg             ilog.write (text +"\n")
    399  1.1  mrg             ilog.write ("============================================\n");
    400  1.1  mrg             ilog.close()
    401  1.1  mrg             ilog = open("reduce-headers-kept.log","a")
    402  1.1  mrg             ilog.write (src_file + " " + text +"\n")
    403  1.1  mrg             ilog.close()
    404  1.1  mrg         else:
    405  1.1  mrg           newlist = list()
    406  1.1  mrg         if not keep and inc_file_norm not in header_seen:
    407  1.1  mrg           # now look for any macro requirements.
    408  1.1  mrg           for h in newlist:
    409  1.1  mrg             if not h in header_seen:
    410  1.1  mrg               if header_dict.get(h):
    411  1.1  mrg                 defined = ii_macro_define (header_dict[h])
    412  1.1  mrg                 for dep in defined:
    413  1.1  mrg                   if dep in src_requires and dep not in ignore_list:
    414  1.1  mrg                     keep = True;
    415  1.1  mrg                     text = message + ", but must keep " + inc_file + " because it provides " + dep 
    416  1.1  mrg                     if because.get(dep) != None:
    417  1.1  mrg                       text = text + " Possibly required by " + because[dep]
    418  1.1  mrg                     print text
    419  1.1  mrg                     ilog = open(inc_file+".log","a")
    420  1.1  mrg                     ilog.write (because[dep]+": Requires [dep] in "+src_file+"\n")
    421  1.1  mrg                     ilog.write ("============================================\n");
    422  1.1  mrg                     ilog.close()
    423  1.1  mrg                     ilog = open(src_file+".log","a")
    424  1.1  mrg                     ilog.write (text +"\n")
    425  1.1  mrg                     ilog.write ("============================================\n");
    426  1.1  mrg                     ilog.close()
    427  1.1  mrg                     ilog = open("reduce-headers-kept.log","a")
    428  1.1  mrg                     ilog.write (src_file + " " + text +"\n")
    429  1.1  mrg                     ilog.close()
    430  1.1  mrg                     if verbose:
    431  1.1  mrg                       verbose.write (text + "\n")
    432  1.1  mrg 
    433  1.1  mrg         if keep:
    434  1.1  mrg           # add all headers 'consumes' to src_requires list, and mark as seen
    435  1.1  mrg           for h in newlist:
    436  1.1  mrg             if not h in header_seen:
    437  1.1  mrg               header_seen.append (h)
    438  1.1  mrg               if header_dict.get(h):
    439  1.1  mrg                 consume = ii_macro_consume (header_dict[h])
    440  1.1  mrg                 for dep in consume:
    441  1.1  mrg                   if dep not in src_requires:
    442  1.1  mrg                     src_requires.add (dep)
    443  1.1  mrg                     if because.get(dep) == None:
    444  1.1  mrg                       because[dep] = inc_file
    445  1.1  mrg 
    446  1.1  mrg           src_tmp = copy.deepcopy (src_data)
    447  1.1  mrg         else:
    448  1.1  mrg           print message + "  --> removing " + inc_file + "\n"
    449  1.1  mrg           rmcount += 1
    450  1.1  mrg           if verbose:
    451  1.1  mrg             verbose.write (message + "  --> removing " + inc_file + "\n")
    452  1.1  mrg           if remove_count.get(inc_file) == None:
    453  1.1  mrg             remove_count[inc_file] = 1
    454  1.1  mrg           else:
    455  1.1  mrg             remove_count[inc_file] += 1
    456  1.1  mrg           src_data = copy.deepcopy (src_tmp)
    457  1.1  mrg     except:
    458  1.1  mrg       print "Interuption: restoring original file"
    459  1.1  mrg       out = open(src_file, "w")
    460  1.1  mrg       for line in src_orig:
    461  1.1  mrg         out.write (line)
    462  1.1  mrg       out.close()
    463  1.1  mrg       raise
    464  1.1  mrg 
    465  1.1  mrg     # copy current version, since it is the "right" one now.
    466  1.1  mrg     out = open(src_file, "w")
    467  1.1  mrg     for line in src_data:
    468  1.1  mrg       out.write (line)
    469  1.1  mrg     out.close()
    470  1.1  mrg     
    471  1.1  mrg     # Try a final host bootstrap build to make sure everything is kosher.
    472  1.1  mrg     if hostbuild:
    473  1.1  mrg       res = get_make_output (build_dir, "all")
    474  1.1  mrg       rc = res[0]
    475  1.1  mrg       if (rc != 0):
    476  1.1  mrg         # host build failed! return to original version
    477  1.1  mrg         print "Error: " + src_file + " Failed to bootstrap at end!!! restoring."
    478  1.1  mrg         print "        Bad version at " + src_file + ".bad"
    479  1.1  mrg         os.rename (src_file, src_file + ".bad")
    480  1.1  mrg         out = open(src_file, "w")
    481  1.1  mrg         for line in src_orig:
    482  1.1  mrg           out.write (line)
    483  1.1  mrg         out.close()
    484  1.1  mrg         return src_file + ": failed to build after reduction.  Restored original"
    485  1.1  mrg 
    486  1.1  mrg     if src_data == src_orig:
    487  1.1  mrg       summary = src_file + ": No change."
    488  1.1  mrg     else:
    489  1.1  mrg       summary = src_file + ": Reduction performed, "+str(rmcount)+" includes removed."
    490  1.1  mrg   print summary
    491  1.1  mrg   return summary
    492  1.1  mrg 
    493  1.1  mrg only_h = list ()
    494  1.1  mrg ignore_cond = False
    495  1.1  mrg 
    496  1.1  mrg usage = False
    497  1.1  mrg src = list()
    498  1.1  mrg only_targs = list ()
    499  1.1  mrg for x in sys.argv[1:]:
    500  1.1  mrg   if x[0:2] == "-b":
    501  1.1  mrg     build_dir = x[2:]
    502  1.1  mrg   elif x[0:2] == "-f":
    503  1.1  mrg     fn = normalize_header (x[2:])
    504  1.1  mrg     if fn not in only_h:
    505  1.1  mrg       only_h.append (fn)
    506  1.1  mrg   elif x[0:2] == "-h":
    507  1.1  mrg     usage = True
    508  1.1  mrg   elif x[0:2] == "-d":
    509  1.1  mrg     ignore_cond = True
    510  1.1  mrg   elif x[0:2] == "-D":
    511  1.1  mrg     ignore_list.append(x[2:])
    512  1.1  mrg   elif x[0:2] == "-T":
    513  1.1  mrg     only_targs.append(x[2:])
    514  1.1  mrg   elif x[0:2] == "-t":
    515  1.1  mrg     target_dir = x[2:]
    516  1.1  mrg   elif x[0] == "-":
    517  1.1  mrg     print "Error:  Unrecognized option " + x
    518  1.1  mrg     usgae = True
    519  1.1  mrg   else:
    520  1.1  mrg     if not os.path.exists (x):
    521  1.1  mrg       print "Error: specified file " + x + " does not exist."
    522  1.1  mrg       usage = True
    523  1.1  mrg     else:
    524  1.1  mrg       src.append (x)
    525  1.1  mrg 
    526  1.1  mrg if target_dir:
    527  1.1  mrg   build_target_dict (target_dir, only_targs)
    528  1.1  mrg 
    529  1.1  mrg if build_dir == "" and target_dir == "":
    530  1.1  mrg   print "Error: Must specify a build directory, and/or a target directory."
    531  1.1  mrg   usage = True
    532  1.1  mrg 
    533  1.1  mrg if build_dir and not os.path.exists (build_dir):
    534  1.1  mrg     print "Error: specified build directory does not exist : " + build_dir
    535  1.1  mrg     usage = True
    536  1.1  mrg 
    537  1.1  mrg if target_dir and not os.path.exists (target_dir):
    538  1.1  mrg     print "Error: specified target directory does not exist : " + target_dir
    539  1.1  mrg     usage = True
    540  1.1  mrg 
    541  1.1  mrg if usage:
    542  1.1  mrg   print "Attempts to remove extraneous include files from source files."
    543  1.1  mrg   print " "
    544  1.1  mrg   print "Should be run from the main gcc source directory, and works on a target"
    545  1.1  mrg   print "directory, as we attempt to make the 'all' target."
    546  1.1  mrg   print " "
    547  1.1  mrg   print "By default, gcc-reorder-includes is run on each file before attempting"
    548  1.1  mrg   print "to remove includes. this removes duplicates and puts some headers in a"
    549  1.1  mrg   print "canonical ordering"
    550  1.1  mrg   print " "
    551  1.1  mrg   print "The build directory should be ready to compile via make. Time is saved"
    552  1.1  mrg   print "if the build is already complete, so that only changes need to be built."
    553  1.1  mrg   print " "
    554  1.1  mrg   print "Usage: [options] file1.c [file2.c] ... [filen.c]"
    555  1.1  mrg   print "      -bdir    : the root build directory to attempt buiding .o files."
    556  1.1  mrg   print "      -tdir    : the target build directory"
    557  1.1  mrg   print "      -d       : Ignore conditional macro dependencies."
    558  1.1  mrg   print " "
    559  1.1  mrg   print "      -Dmacro  : Ignore a specific macro for dependencies"
    560  1.1  mrg   print "      -Ttarget : Only consider target in target directory."
    561  1.1  mrg   print "      -fheader : Specifies a specific .h file to be considered."
    562  1.1  mrg   print " "
    563  1.1  mrg   print "      -D, -T, and -f can be specified mulitple times and are aggregated."
    564  1.1  mrg   print " "
    565  1.1  mrg   print "  The original file will be in filen.bak"
    566  1.1  mrg   print " "
    567  1.1  mrg   sys.exit (0)
    568  1.1  mrg  
    569  1.1  mrg if only_h:
    570  1.1  mrg   print "Attempting to remove only these files:"
    571  1.1  mrg   for x in only_h:
    572  1.1  mrg     print x
    573  1.1  mrg   print " "
    574  1.1  mrg 
    575  1.1  mrg logfile = open("reduce-headers.log","w")
    576  1.1  mrg 
    577  1.1  mrg for x in src:
    578  1.1  mrg   msg = try_to_remove (x, only_h, logfile)
    579  1.1  mrg   ilog = open("reduce-headers.sum","a")
    580  1.1  mrg   ilog.write (msg + "\n")
    581  1.1  mrg   ilog.close()
    582  1.1  mrg 
    583  1.1  mrg ilog = open("reduce-headers.sum","a")
    584  1.1  mrg ilog.write ("===============================================================\n")
    585  1.1  mrg for x in remove_count:
    586  1.1  mrg   msg = x + ": Removed " + str(remove_count[x]) + " times."
    587  1.1  mrg   print msg
    588  1.1  mrg   logfile.write (msg + "\n")
    589  1.1  mrg   ilog.write (msg + "\n")
    590  1.1  mrg 
    591  1.1  mrg 
    592  1.1  mrg 
    593  1.1  mrg 
    594  1.1  mrg 
    595