blob: 2ff178bb192db871786cc8e4a9b04ae87134210e [file] [log] [blame]
#!/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)