Home | History | Annotate | Download | only in bin
      1 #!/usr/bin/python
      2 
      3 import os
      4 import shlex
      5 import sys
      6 
      7 BISECT_STAGE = os.environ.get('BISECT_STAGE')
      8 
      9 # We do not need bisect functionality with Goma and clang.
     10 # Goma server does not have bisect_driver, so we only import
     11 # bisect_driver when needed. See http://b/34862041
     12 # We should be careful when doing imports because of Goma.
     13 if BISECT_STAGE:
     14   import bisect_driver
     15 
     16 DEFAULT_BISECT_DIR = os.path.expanduser('~/ANDROID_BISECT')
     17 BISECT_DIR = os.environ.get('BISECT_DIR') or DEFAULT_BISECT_DIR
     18 
     19 
     20 def ProcessArgFile(arg_file):
     21   args = []
     22   # Read in entire file at once and parse as if in shell
     23   with open(arg_file, 'rb') as f:
     24     args.extend(shlex.split(f.read()))
     25   return args
     26 
     27 
     28 class CompilerWrapper():
     29   def __init__(self, argv):
     30     self.argv0_current = argv[0]
     31     self.args = argv[1:]
     32     self.execargs = []
     33     self.real_compiler = None
     34     self.argv0 = None
     35     self.append_flags = []
     36     self.prepend_flags = []
     37     self.custom_flags = {
     38       '--gomacc-path': None
     39     }
     40 
     41   def set_real_compiler(self):
     42     """Find the real compiler with the absolute path."""
     43     compiler_path = os.path.dirname(self.argv0_current)
     44     if os.path.islink(__file__):
     45       compiler = os.path.basename(os.readlink(__file__))
     46     else:
     47       compiler = os.path.basename(os.path.abspath(__file__))
     48     self.real_compiler = os.path.join(
     49         compiler_path,
     50         compiler + '.real')
     51     self.argv0 = self.real_compiler
     52 
     53   def process_gomacc_command(self):
     54     """Return the gomacc command if '--gomacc-path' is set."""
     55     gomacc = self.custom_flags['--gomacc-path']
     56     if gomacc and os.path.isfile(gomacc):
     57       self.argv0 = gomacc
     58       self.execargs += [gomacc]
     59 
     60   def parse_custom_flags(self):
     61     i = 0
     62     args = []
     63     while i < len(self.args):
     64       if self.args[i] in self.custom_flags:
     65         if i >= len(self.args) - 1:
     66           sys.exit('The value of {} is not set.'.format(self.args[i]))
     67         self.custom_flags[self.args[i]] = self.args[i + 1]
     68         i = i + 2
     69       else:
     70         args.append(self.args[i])
     71         i = i + 1
     72     self.args = args
     73 
     74   def add_flags(self):
     75     self.args = self.prepend_flags + self.args + self.append_flags
     76 
     77   def prepare_compiler_args(self):
     78     self.set_real_compiler()
     79     self.parse_custom_flags()
     80     self.process_gomacc_command()
     81     self.add_flags()
     82     self.execargs += [self.real_compiler] + self.args
     83 
     84   def invoke_compiler(self):
     85     self.prepare_compiler_args()
     86     os.execv(self.argv0, self.execargs)
     87 
     88   def bisect(self):
     89     self.prepare_compiler_args()
     90     # Handle @file argument syntax with compiler
     91     idx = 0
     92     # The length of self.execargs can be changed during the @file argument
     93     # expansion, so we need to use while loop instead of for loop.
     94     while idx < len(self.execargs):
     95       if self.execargs[idx][0] == '@':
     96         args_in_file = ProcessArgFile(self.execargs[idx][1:])
     97         self.execargs = self.execargs[0:idx] + args_in_file + self.execargs[idx + 1:]
     98         # Skip update of idx, since we want to recursively expand response files.
     99       else:
    100         idx = idx + 1
    101     bisect_driver.bisect_driver(BISECT_STAGE, BISECT_DIR, self.execargs)
    102 
    103 
    104 def main(argv):
    105   cw = CompilerWrapper(argv)
    106   if BISECT_STAGE and BISECT_STAGE in bisect_driver.VALID_MODES and '-o' in argv:
    107     cw.bisect()
    108   else:
    109     cw.invoke_compiler()
    110 
    111 
    112 if __name__ == '__main__':
    113   main(sys.argv)
    114