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