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.args = argv
     31     self.execargs = []
     32     self.real_compiler = None
     33     self.argv0 = None
     34     self.append_flags = []
     35     self.prepend_flags = []
     36     self.custom_flags = {
     37       '--gomacc-path': None
     38     }
     39 
     40   def set_real_compiler(self):
     41     """Find the real compiler with the absolute path."""
     42     compiler_path = os.path.dirname(os.path.abspath(__file__))
     43     if os.path.islink(__file__):
     44       compiler = os.path.basename(os.readlink(__file__))
     45     else:
     46       compiler = os.path.basename(os.path.abspath(__file__))
     47     self.real_compiler = os.path.join(
     48         compiler_path,
     49         compiler + '.real')
     50     self.argv0 = self.real_compiler
     51 
     52   def process_gomacc_command(self):
     53     """Return the gomacc command if '--gomacc-path' is set."""
     54     gomacc = self.custom_flags['--gomacc-path']
     55     if gomacc and os.path.isfile(gomacc):
     56       self.argv0 = gomacc
     57       self.execargs += [gomacc]
     58 
     59   def parse_custom_flags(self):
     60     i = 0
     61     args = []
     62     while i < len(self.args):
     63       if self.args[i] in self.custom_flags:
     64         if i >= len(self.args) - 1:
     65           sys.exit('The value of {} is not set.'.format(self.args[i]))
     66         self.custom_flags[self.args[i]] = self.args[i + 1]
     67         i = i + 2
     68       else:
     69         args.append(self.args[i])
     70         i = i + 1
     71     self.args = args
     72 
     73   def add_flags(self):
     74     self.args = self.prepend_flags + self.args + self.append_flags
     75 
     76   def prepare_compiler_args(self):
     77     self.set_real_compiler()
     78     self.parse_custom_flags()
     79     self.process_gomacc_command()
     80     self.add_flags()
     81     self.execargs += [self.real_compiler] + self.args
     82 
     83   def invoke_compiler(self):
     84     self.prepare_compiler_args()
     85     os.execv(self.argv0, self.execargs)
     86 
     87   def bisect(self):
     88     self.prepare_compiler_args()
     89     # Handle @file argument syntax with compiler
     90     idx = 0
     91     # The length of self.execargs can be changed during the @file argument
     92     # expansion, so we need to use while loop instead of for loop.
     93     while idx < len(self.execargs):
     94       if self.execargs[idx][0] == '@':
     95         args_in_file = ProcessArgFile(self.execargs[idx][1:])
     96         self.execargs = self.execargs[0:idx] + args_in_file + self.execargs[idx + 1:]
     97         # Skip update of idx, since we want to recursively expand response files.
     98       else:
     99         idx = idx + 1
    100     bisect_driver.bisect_driver(BISECT_STAGE, BISECT_DIR, self.execargs)
    101 
    102 
    103 def main(argv):
    104   cw = CompilerWrapper(argv[1:])
    105   if BISECT_STAGE and BISECT_STAGE in bisect_driver.VALID_MODES and '-o' in argv:
    106     cw.bisect()
    107   else:
    108     cw.invoke_compiler()
    109 
    110 
    111 if __name__ == '__main__':
    112   main(sys.argv)
    113