mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			596 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			596 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
| #! /usr/bin/python2
 | |
| import os.path
 | |
| import sys
 | |
| import shlex
 | |
| import re
 | |
| import tempfile
 | |
| import copy
 | |
| 
 | |
| from headerutils import *
 | |
| 
 | |
| requires = { }
 | |
| provides = { }
 | |
| 
 | |
| no_remove = [ "system.h", "coretypes.h", "config.h" , "bconfig.h", "backend.h" ]
 | |
| 
 | |
| # These targets are the ones which provide "coverage".  Typically, if any
 | |
| # target is going to fail compilation, it's one of these.  This was determined
 | |
| # during the initial runs of reduce-headers... On a full set of target builds,
 | |
| # every failure which occured was triggered by one of these.  
 | |
| # This list is used during target-list construction simply to put any of these
 | |
| # *first* in the candidate list, increasing the probability that a failure is 
 | |
| # found quickly.
 | |
| target_priority = [
 | |
|     "aarch64-linux-gnu",
 | |
|     "arm-netbsdelf",
 | |
|     "c6x-elf",
 | |
|     "epiphany-elf",
 | |
|     "hppa2.0-hpux10.1",
 | |
|     "i686-mingw32crt",
 | |
|     "i686-pc-msdosdjgpp",
 | |
|     "mipsel-elf",
 | |
|     "powerpc-eabisimaltivec",
 | |
|     "rs6000-ibm-aix5.1.0",
 | |
|     "sh-superh-elf",
 | |
|     "sparc64-elf",
 | |
|     "spu-elf"
 | |
| ]
 | |
| 
 | |
| 
 | |
| target_dir = ""
 | |
| build_dir = ""
 | |
| ignore_list = list()
 | |
| target_builds = list()
 | |
| 
 | |
| target_dict = { }
 | |
| header_dict = { }
 | |
| search_path = [ ".", "../include", "../libcpp/include" ]
 | |
| 
 | |
| remove_count = { }
 | |
| 
 | |
| 
 | |
| # Given a header name, normalize it.  ie.  cp/cp-tree.h could be in gcc, while
 | |
| # the same header could be referenced from within the cp subdirectory as
 | |
| # just cp-tree.h
 | |
| # for now, just assume basenames are unique
 | |
| 
 | |
| def normalize_header (header):
 | |
|   return os.path.basename (header)
 | |
| 
 | |
| 
 | |
| # Adds a header file and its sub-includes to the global dictionary if they
 | |
| # aren't already there.  Specify s_path since different build directories may
 | |
| # append themselves on demand to the global list.
 | |
| # return entry for the specified header, knowing all sub entries are completed
 | |
| 
 | |
| def get_header_info (header, s_path):
 | |
|   global header_dict
 | |
|   global empty_iinfo
 | |
|   process_list = list ()
 | |
|   location = ""
 | |
|   bname = ""
 | |
|   bname_iinfo = empty_iinfo
 | |
|   for path in s_path:
 | |
|     if os.path.exists (path + "/" + header):
 | |
|       location = path + "/" + header
 | |
|       break
 | |
| 
 | |
|   if location:
 | |
|     bname = normalize_header (location)
 | |
|     if header_dict.get (bname):
 | |
|       bname_iinfo = header_dict[bname]
 | |
|       loc2 = ii_path (bname_iinfo)+ "/" + bname
 | |
|       if loc2[:2] == "./":
 | |
|         loc2 = loc2[2:]
 | |
|       if location[:2] == "./":
 | |
|         location = location[2:]
 | |
|       if loc2 != location:
 | |
|         # Don't use the cache if it isnt the right one.
 | |
|         bname_iinfo = process_ii_macro (location)
 | |
|       return bname_iinfo
 | |
| 
 | |
|     bname_iinfo = process_ii_macro (location)
 | |
|     header_dict[bname] = bname_iinfo
 | |
|     # now decend into the include tree
 | |
|     for i in ii_include_list (bname_iinfo):
 | |
|       get_header_info (i, s_path)
 | |
|   else:
 | |
|     # if the file isnt in the source directories, look in the build and target
 | |
|     # directories. If it is here, then aggregate all the versions.
 | |
|     location = build_dir + "/gcc/" + header
 | |
|     build_inc = target_inc = False
 | |
|     if os.path.exists (location):
 | |
|       build_inc = True
 | |
|     for x in target_dict:
 | |
|       location = target_dict[x] + "/gcc/" + header
 | |
|       if os.path.exists (location):
 | |
|         target_inc = True
 | |
|         break
 | |
| 
 | |
|     if (build_inc or target_inc):
 | |
|       bname = normalize_header(header)
 | |
|       defines = set()
 | |
|       consumes = set()
 | |
|       incl = set()
 | |
|       if build_inc:
 | |
|         iinfo = process_ii_macro (build_dir + "/gcc/" + header)
 | |
|         defines = set (ii_macro_define (iinfo))
 | |
|         consumes = set (ii_macro_consume (iinfo))
 | |
|         incl = set (ii_include_list (iinfo))
 | |
| 
 | |
|       if (target_inc):
 | |
|         for x in target_dict:
 | |
|           location = target_dict[x] + "/gcc/" + header
 | |
|           if os.path.exists (location):
 | |
|             iinfo = process_ii_macro (location)
 | |
|             defines.update (ii_macro_define (iinfo))
 | |
|             consumes.update (ii_macro_consume (iinfo))
 | |
|             incl.update (ii_include_list (iinfo))
 | |
| 
 | |
|       bname_iinfo = (header, "build", list(incl), list(), list(consumes), list(defines), list(), list())
 | |
| 
 | |
|       header_dict[bname] = bname_iinfo
 | |
|       for i in incl:
 | |
|         get_header_info (i, s_path)
 | |
| 
 | |
|   return bname_iinfo
 | |
| 
 | |
| 
 | |
| # return a list of all headers brought in by this header
 | |
| def all_headers (fname):
 | |
|   global header_dict
 | |
|   headers_stack = list()
 | |
|   headers_list = list()
 | |
|   if header_dict.get (fname) == None:
 | |
|     return list ()
 | |
|   for y in ii_include_list (header_dict[fname]):
 | |
|     headers_stack.append (y)
 | |
| 
 | |
|   while headers_stack:
 | |
|     h = headers_stack.pop ()
 | |
|     hn = normalize_header (h)
 | |
|     if hn not in headers_list:
 | |
|       headers_list.append (hn)
 | |
|       if header_dict.get(hn):
 | |
|         for y in ii_include_list (header_dict[hn]):
 | |
|           if normalize_header (y) not in headers_list:
 | |
|             headers_stack.append (y)
 | |
| 
 | |
|   return headers_list
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| # Search bld_dir for all target tuples, confirm that they have a build path with
 | |
| # bld_dir/target-tuple/gcc, and build a dictionary of build paths indexed by
 | |
| # target tuple..
 | |
| 
 | |
| def build_target_dict (bld_dir, just_these):
 | |
|   global target_dict
 | |
|   target_doct = { }
 | |
|   error = False
 | |
|   if os.path.exists (bld_dir):
 | |
|     if just_these:
 | |
|       ls = just_these
 | |
|     else:
 | |
|       ls = os.listdir(bld_dir)
 | |
|     for t in ls:
 | |
|       if t.find("-") != -1:
 | |
|         target = t.strip()
 | |
|         tpath = bld_dir + "/" + target
 | |
|         if not os.path.exists (tpath + "/gcc"):
 | |
|           print "Error: gcc build directory for target " + t + " Does not exist: " + tpath + "/gcc"
 | |
|           error = True
 | |
|         else:
 | |
|           target_dict[target] = tpath
 | |
| 
 | |
|   if error:
 | |
|     target_dict = { }
 | |
| 
 | |
| def get_obj_name (src_file):
 | |
|   if src_file[-2:] == ".c":
 | |
|     return src_file.replace (".c", ".o")
 | |
|   elif src_file[-3:] == ".cc":
 | |
|     return src_file.replace (".cc", ".o")
 | |
|   return ""
 | |
| 
 | |
| def target_obj_exists (target, obj_name):
 | |
|   global target_dict
 | |
|   # look in a subdir if src has a subdir, then check gcc base directory.
 | |
|   if target_dict.get(target):
 | |
|     obj = target_dict[target] + "/gcc/" + obj_name
 | |
|     if not os.path.exists (obj):
 | |
|       obj = target_dict[target] + "/gcc/" + os.path.basename(obj_name)
 | |
|     if os.path.exists (obj):
 | |
|       return True
 | |
|   return False
 | |
|  
 | |
| # Given a src file, return a list of targets which may build this file.
 | |
| def find_targets (src_file):
 | |
|   global target_dict
 | |
|   targ_list = list()
 | |
|   obj_name = get_obj_name (src_file)
 | |
|   if not obj_name:
 | |
|     print "Error: " + src_file + " - Cannot determine object name."
 | |
|     return list()
 | |
| 
 | |
|   # Put the high priority targets which tend to trigger failures first
 | |
|   for target in target_priority:
 | |
|     if target_obj_exists (target, obj_name):
 | |
|       targ_list.append ((target, target_dict[target]))
 | |
| 
 | |
|   for target in target_dict:
 | |
|     if target not in target_priority and target_obj_exists (target, obj_name):
 | |
|       targ_list.append ((target, target_dict[target]))
 | |
|         
 | |
|   return targ_list
 | |
| 
 | |
| 
 | |
| def try_to_remove (src_file, h_list, verbose):
 | |
|   global target_dict
 | |
|   global header_dict
 | |
|   global build_dir
 | |
| 
 | |
|   # build from scratch each time
 | |
|   header_dict = { }
 | |
|   summary = ""
 | |
|   rmcount = 0
 | |
| 
 | |
|   because = { }
 | |
|   src_info = process_ii_macro_src (src_file)
 | |
|   src_data = ii_src (src_info)
 | |
|   if src_data:
 | |
|     inclist = ii_include_list_non_cond (src_info)
 | |
|     # work is done if there are no includes to check
 | |
|     if not inclist:
 | |
|       return src_file + ": No include files to attempt to remove"
 | |
| 
 | |
|     # work on the include list in reverse.
 | |
|     inclist.reverse()
 | |
| 
 | |
|     # Get the target list 
 | |
|     targ_list = list()
 | |
|     targ_list = find_targets (src_file)
 | |
| 
 | |
|     spath = search_path
 | |
|     if os.path.dirname (src_file):
 | |
|       spath.append (os.path.dirname (src_file))
 | |
| 
 | |
|     hostbuild = True
 | |
|     if src_file.find("config/") != -1:
 | |
|       # config files dont usually build on the host
 | |
|       hostbuild = False
 | |
|       obn = get_obj_name (os.path.basename (src_file))
 | |
|       if obn and os.path.exists (build_dir + "/gcc/" + obn):
 | |
|         hostbuild = True
 | |
|       if not target_dict:
 | |
|         summary = src_file + ": Target builds are required for config files.  None found."
 | |
|         print summary
 | |
|         return summary
 | |
|       if not targ_list:
 | |
|         summary =src_file + ": Cannot find any targets which build this file."
 | |
|         print summary
 | |
|         return summary
 | |
| 
 | |
|     if hostbuild:
 | |
|       # confirm it actually builds before we do anything
 | |
|       print "Confirming source file builds"
 | |
|       res = get_make_output (build_dir + "/gcc", "all")
 | |
|       if res[0] != 0:
 | |
|         message = "Error: " + src_file + " does not build currently."
 | |
|         summary = src_file + " does not build on host."
 | |
|         print message
 | |
|         print res[1]
 | |
|         if verbose:
 | |
|           verbose.write (message + "\n")
 | |
|           verbose.write (res[1]+ "\n")
 | |
|         return summary
 | |
| 
 | |
|     src_requires = set (ii_macro_consume (src_info))
 | |
|     for macro in src_requires:
 | |
|       because[macro] = src_file
 | |
|     header_seen = list ()
 | |
| 
 | |
|     os.rename (src_file, src_file + ".bak")
 | |
|     src_orig = copy.deepcopy (src_data)
 | |
|     src_tmp = copy.deepcopy (src_data)
 | |
| 
 | |
|     try:
 | |
|       # process the includes from bottom to top.  This is because we know that
 | |
|       # later includes have are known to be needed, so any dependency from this 
 | |
|       # header is a true dependency
 | |
|       for inc_file in inclist:
 | |
|         inc_file_norm = normalize_header (inc_file)
 | |
|         
 | |
|         if inc_file in no_remove:
 | |
|           continue
 | |
|         if len (h_list) != 0 and inc_file_norm not in h_list:
 | |
|           continue
 | |
|         if inc_file_norm[0:3] == "gt-":
 | |
|           continue
 | |
|         if inc_file_norm[0:6] == "gtype-":
 | |
|           continue
 | |
|         if inc_file_norm.replace(".h",".c") == os.path.basename(src_file):
 | |
|           continue
 | |
|              
 | |
|         lookfor = ii_src_line(src_info)[inc_file]
 | |
|         src_tmp.remove (lookfor)
 | |
|         message = "Trying " + src_file + " without " + inc_file
 | |
|         print message
 | |
|         if verbose:
 | |
|           verbose.write (message + "\n")
 | |
|         out = open(src_file, "w")
 | |
|         for line in src_tmp:
 | |
|           out.write (line)
 | |
|         out.close()
 | |
|           
 | |
|         keep = False
 | |
|         if hostbuild:
 | |
|           res = get_make_output (build_dir + "/gcc", "all")
 | |
|         else:
 | |
|           res = (0, "")
 | |
| 
 | |
|         rc = res[0]
 | |
|         message = "Passed Host build"
 | |
|         if (rc != 0):
 | |
|           # host build failed
 | |
|           message  = "Compilation failed:\n";
 | |
|           keep = True
 | |
|         else:
 | |
|           if targ_list:
 | |
|             objfile = get_obj_name (src_file)
 | |
|             t1 = targ_list[0]
 | |
|             if objfile and os.path.exists(t1[1] +"/gcc/"+objfile):
 | |
|               res = get_make_output_parallel (targ_list, objfile, 0)
 | |
|             else:
 | |
|               res = get_make_output_parallel (targ_list, "all-gcc", 0)
 | |
|             rc = res[0]
 | |
|             if rc != 0:
 | |
|               message = "Compilation failed on TARGET : " + res[2]
 | |
|               keep = True
 | |
|             else:
 | |
|               message = "Passed host and target builds"
 | |
| 
 | |
|         if keep:
 | |
|           print message + "\n"
 | |
| 
 | |
|         if (rc != 0):
 | |
|           if verbose:
 | |
|             verbose.write (message + "\n");
 | |
|             verbose.write (res[1])
 | |
|             verbose.write ("\n");
 | |
|             if os.path.exists (inc_file):
 | |
|               ilog = open(inc_file+".log","a")
 | |
|               ilog.write (message + " for " + src_file + ":\n\n");
 | |
|               ilog.write ("============================================\n");
 | |
|               ilog.write (res[1])
 | |
|               ilog.write ("\n");
 | |
|               ilog.close()
 | |
|             if os.path.exists (src_file):
 | |
|               ilog = open(src_file+".log","a")
 | |
|               ilog.write (message + " for " +inc_file + ":\n\n");
 | |
|               ilog.write ("============================================\n");
 | |
|               ilog.write (res[1])
 | |
|               ilog.write ("\n");
 | |
|               ilog.close()
 | |
| 
 | |
|         # Given a sequence where :
 | |
|         # #include "tm.h"
 | |
|         # #include "target.h"  // includes tm.h
 | |
| 
 | |
|         # target.h was required, and when attempting to remove tm.h we'd see that
 | |
|         # all the macro defintions are "required" since they all look like:
 | |
|         # #ifndef HAVE_blah
 | |
|         # #define HAVE_blah
 | |
|         # endif
 | |
| 
 | |
|         # when target.h was found to be required, tm.h will be tagged as included.
 | |
|         # so when we get this far, we know we dont have to check the macros for
 | |
|         # tm.h since we know it is already been included.
 | |
| 
 | |
|         if inc_file_norm not in header_seen:
 | |
|           iinfo = get_header_info (inc_file, spath)
 | |
|           newlist = all_headers (inc_file_norm)
 | |
|           if ii_path(iinfo) == "build" and not target_dict:
 | |
|             keep = True
 | |
|             text = message + " : Will not remove a build file without some targets."
 | |
|             print text
 | |
|             ilog = open(src_file+".log","a")
 | |
|             ilog.write (text +"\n")
 | |
|             ilog.write ("============================================\n");
 | |
|             ilog.close()
 | |
|             ilog = open("reduce-headers-kept.log","a")
 | |
|             ilog.write (src_file + " " + text +"\n")
 | |
|             ilog.close()
 | |
|         else:
 | |
|           newlist = list()
 | |
|         if not keep and inc_file_norm not in header_seen:
 | |
|           # now look for any macro requirements.
 | |
|           for h in newlist:
 | |
|             if not h in header_seen:
 | |
|               if header_dict.get(h):
 | |
|                 defined = ii_macro_define (header_dict[h])
 | |
|                 for dep in defined:
 | |
|                   if dep in src_requires and dep not in ignore_list:
 | |
|                     keep = True;
 | |
|                     text = message + ", but must keep " + inc_file + " because it provides " + dep 
 | |
|                     if because.get(dep) != None:
 | |
|                       text = text + " Possibly required by " + because[dep]
 | |
|                     print text
 | |
|                     ilog = open(inc_file+".log","a")
 | |
|                     ilog.write (because[dep]+": Requires [dep] in "+src_file+"\n")
 | |
|                     ilog.write ("============================================\n");
 | |
|                     ilog.close()
 | |
|                     ilog = open(src_file+".log","a")
 | |
|                     ilog.write (text +"\n")
 | |
|                     ilog.write ("============================================\n");
 | |
|                     ilog.close()
 | |
|                     ilog = open("reduce-headers-kept.log","a")
 | |
|                     ilog.write (src_file + " " + text +"\n")
 | |
|                     ilog.close()
 | |
|                     if verbose:
 | |
|                       verbose.write (text + "\n")
 | |
| 
 | |
|         if keep:
 | |
|           # add all headers 'consumes' to src_requires list, and mark as seen
 | |
|           for h in newlist:
 | |
|             if not h in header_seen:
 | |
|               header_seen.append (h)
 | |
|               if header_dict.get(h):
 | |
|                 consume = ii_macro_consume (header_dict[h])
 | |
|                 for dep in consume:
 | |
|                   if dep not in src_requires:
 | |
|                     src_requires.add (dep)
 | |
|                     if because.get(dep) == None:
 | |
|                       because[dep] = inc_file
 | |
| 
 | |
|           src_tmp = copy.deepcopy (src_data)
 | |
|         else:
 | |
|           print message + "  --> removing " + inc_file + "\n"
 | |
|           rmcount += 1
 | |
|           if verbose:
 | |
|             verbose.write (message + "  --> removing " + inc_file + "\n")
 | |
|           if remove_count.get(inc_file) == None:
 | |
|             remove_count[inc_file] = 1
 | |
|           else:
 | |
|             remove_count[inc_file] += 1
 | |
|           src_data = copy.deepcopy (src_tmp)
 | |
|     except:
 | |
|       print "Interuption: restoring original file"
 | |
|       out = open(src_file, "w")
 | |
|       for line in src_orig:
 | |
|         out.write (line)
 | |
|       out.close()
 | |
|       raise
 | |
| 
 | |
|     # copy current version, since it is the "right" one now.
 | |
|     out = open(src_file, "w")
 | |
|     for line in src_data:
 | |
|       out.write (line)
 | |
|     out.close()
 | |
|     
 | |
|     # Try a final host bootstrap build to make sure everything is kosher.
 | |
|     if hostbuild:
 | |
|       res = get_make_output (build_dir, "all")
 | |
|       rc = res[0]
 | |
|       if (rc != 0):
 | |
|         # host build failed! return to original version
 | |
|         print "Error: " + src_file + " Failed to bootstrap at end!!! restoring."
 | |
|         print "        Bad version at " + src_file + ".bad"
 | |
|         os.rename (src_file, src_file + ".bad")
 | |
|         out = open(src_file, "w")
 | |
|         for line in src_orig:
 | |
|           out.write (line)
 | |
|         out.close()
 | |
|         return src_file + ": failed to build after reduction.  Restored original"
 | |
| 
 | |
|     if src_data == src_orig:
 | |
|       summary = src_file + ": No change."
 | |
|     else:
 | |
|       summary = src_file + ": Reduction performed, "+str(rmcount)+" includes removed."
 | |
|   print summary
 | |
|   return summary
 | |
| 
 | |
| only_h = list ()
 | |
| ignore_cond = False
 | |
| 
 | |
| usage = False
 | |
| src = list()
 | |
| only_targs = list ()
 | |
| for x in sys.argv[1:]:
 | |
|   if x[0:2] == "-b":
 | |
|     build_dir = x[2:]
 | |
|   elif x[0:2] == "-f":
 | |
|     fn = normalize_header (x[2:])
 | |
|     if fn not in only_h:
 | |
|       only_h.append (fn)
 | |
|   elif x[0:2] == "-h":
 | |
|     usage = True
 | |
|   elif x[0:2] == "-d":
 | |
|     ignore_cond = True
 | |
|   elif x[0:2] == "-D":
 | |
|     ignore_list.append(x[2:])
 | |
|   elif x[0:2] == "-T":
 | |
|     only_targs.append(x[2:])
 | |
|   elif x[0:2] == "-t":
 | |
|     target_dir = x[2:]
 | |
|   elif x[0] == "-":
 | |
|     print "Error:  Unrecognized option " + x
 | |
|     usgae = True
 | |
|   else:
 | |
|     if not os.path.exists (x):
 | |
|       print "Error: specified file " + x + " does not exist."
 | |
|       usage = True
 | |
|     else:
 | |
|       src.append (x)
 | |
| 
 | |
| if target_dir:
 | |
|   build_target_dict (target_dir, only_targs)
 | |
| 
 | |
| if build_dir == "" and target_dir == "":
 | |
|   print "Error: Must specify a build directory, and/or a target directory."
 | |
|   usage = True
 | |
| 
 | |
| if build_dir and not os.path.exists (build_dir):
 | |
|     print "Error: specified build directory does not exist : " + build_dir
 | |
|     usage = True
 | |
| 
 | |
| if target_dir and not os.path.exists (target_dir):
 | |
|     print "Error: specified target directory does not exist : " + target_dir
 | |
|     usage = True
 | |
| 
 | |
| if usage:
 | |
|   print "Attempts to remove extraneous include files from source files."
 | |
|   print " "
 | |
|   print "Should be run from the main gcc source directory, and works on a target"
 | |
|   print "directory, as we attempt to make the 'all' target."
 | |
|   print " "
 | |
|   print "By default, gcc-reorder-includes is run on each file before attempting"
 | |
|   print "to remove includes. this removes duplicates and puts some headers in a"
 | |
|   print "canonical ordering"
 | |
|   print " "
 | |
|   print "The build directory should be ready to compile via make. Time is saved"
 | |
|   print "if the build is already complete, so that only changes need to be built."
 | |
|   print " "
 | |
|   print "Usage: [options] file1.c [file2.c] ... [filen.c]"
 | |
|   print "      -bdir    : the root build directory to attempt buiding .o files."
 | |
|   print "      -tdir    : the target build directory"
 | |
|   print "      -d       : Ignore conditional macro dependencies."
 | |
|   print " "
 | |
|   print "      -Dmacro  : Ignore a specific macro for dependencies"
 | |
|   print "      -Ttarget : Only consider target in target directory."
 | |
|   print "      -fheader : Specifies a specific .h file to be considered."
 | |
|   print " "
 | |
|   print "      -D, -T, and -f can be specified mulitple times and are aggregated."
 | |
|   print " "
 | |
|   print "  The original file will be in filen.bak"
 | |
|   print " "
 | |
|   sys.exit (0)
 | |
|  
 | |
| if only_h:
 | |
|   print "Attempting to remove only these files:"
 | |
|   for x in only_h:
 | |
|     print x
 | |
|   print " "
 | |
| 
 | |
| logfile = open("reduce-headers.log","w")
 | |
| 
 | |
| for x in src:
 | |
|   msg = try_to_remove (x, only_h, logfile)
 | |
|   ilog = open("reduce-headers.sum","a")
 | |
|   ilog.write (msg + "\n")
 | |
|   ilog.close()
 | |
| 
 | |
| ilog = open("reduce-headers.sum","a")
 | |
| ilog.write ("===============================================================\n")
 | |
| for x in remove_count:
 | |
|   msg = x + ": Removed " + str(remove_count[x]) + " times."
 | |
|   print msg
 | |
|   logfile.write (msg + "\n")
 | |
|   ilog.write (msg + "\n")
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 |