| #!/usr/bin/python |
| |
| import os |
| import shlex |
| import sys |
| |
| BISECT_STAGE = os.environ.get('BISECT_STAGE') |
| |
| # We do not need bisect functionality with Goma and clang. |
| # Goma server does not have bisect_driver, so we only import |
| # bisect_driver when needed. See http://b/34862041 |
| # We should be careful when doing imports because of Goma. |
| if BISECT_STAGE: |
| import bisect_driver |
| |
| DEFAULT_BISECT_DIR = os.path.expanduser('~/ANDROID_BISECT') |
| BISECT_DIR = os.environ.get('BISECT_DIR') or DEFAULT_BISECT_DIR |
| |
| |
| def ProcessArgFile(arg_file): |
| args = [] |
| # Read in entire file at once and parse as if in shell |
| with open(arg_file, 'rb') as f: |
| args.extend(shlex.split(f.read())) |
| return args |
| |
| |
| class CompilerWrapper(): |
| def __init__(self, argv): |
| self.args = argv |
| self.execargs = [] |
| self.real_compiler = None |
| self.argv0 = None |
| self.append_flags = [] |
| self.prepend_flags = [] |
| self.custom_flags = { |
| '--gomacc-path': None |
| } |
| |
| def set_real_compiler(self): |
| """Find the real compiler with the absolute path.""" |
| compiler_path = os.path.dirname(os.path.abspath(__file__)) |
| if os.path.islink(__file__): |
| compiler = os.path.basename(os.readlink(__file__)) |
| else: |
| compiler = os.path.basename(os.path.abspath(__file__)) |
| self.real_compiler = os.path.join( |
| compiler_path, |
| compiler + '.real') |
| self.argv0 = self.real_compiler |
| |
| def process_gomacc_command(self): |
| """Return the gomacc command if '--gomacc-path' is set.""" |
| gomacc = self.custom_flags['--gomacc-path'] |
| if gomacc and os.path.isfile(gomacc): |
| self.argv0 = gomacc |
| self.execargs += [gomacc] |
| |
| def parse_custom_flags(self): |
| i = 0 |
| args = [] |
| while i < len(self.args): |
| if self.args[i] in self.custom_flags: |
| if i >= len(self.args) - 1: |
| sys.exit('The value of {} is not set.'.format(self.args[i])) |
| self.custom_flags[self.args[i]] = self.args[i + 1] |
| i = i + 2 |
| else: |
| args.append(self.args[i]) |
| i = i + 1 |
| self.args = args |
| |
| def add_flags(self): |
| self.args = self.prepend_flags + self.args + self.append_flags |
| |
| def prepare_compiler_args(self): |
| self.set_real_compiler() |
| self.parse_custom_flags() |
| self.process_gomacc_command() |
| self.add_flags() |
| self.execargs += [self.real_compiler] + self.args |
| |
| def invoke_compiler(self): |
| self.prepare_compiler_args() |
| os.execv(self.argv0, self.execargs) |
| |
| def bisect(self): |
| self.prepare_compiler_args() |
| # Handle @file argument syntax with compiler |
| idx = 0 |
| # The length of self.execargs can be changed during the @file argument |
| # expansion, so we need to use while loop instead of for loop. |
| while idx < len(self.execargs): |
| if self.execargs[idx][0] == '@': |
| args_in_file = ProcessArgFile(self.execargs[idx][1:]) |
| self.execargs = self.execargs[0:idx] + args_in_file + self.execargs[idx + 1:] |
| # Skip update of idx, since we want to recursively expand response files. |
| else: |
| idx = idx + 1 |
| bisect_driver.bisect_driver(BISECT_STAGE, BISECT_DIR, self.execargs) |
| |
| |
| def main(argv): |
| cw = CompilerWrapper(argv[1:]) |
| if BISECT_STAGE and BISECT_STAGE in bisect_driver.VALID_MODES and '-o' in argv: |
| cw.bisect() |
| else: |
| cw.invoke_compiler() |
| |
| |
| if __name__ == '__main__': |
| main(sys.argv) |