blob: 04aa4207c05571370c06686afb7fa036945a6a56 [file] [log] [blame]
#!/usr/bin/env python
# Copyright 2017 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
################################################################################
from __future__ import print_function
import os
import subprocess
import sys
import msan_build
GCC_ONLY_ARGS = [
'-aux-info',
]
def InvokedAsGcc():
"""Return whether or not we're pretending to be GCC."""
return sys.argv[0].endswith('gcc') or sys.argv[0].endswith('g++')
def Is32Bit(args):
"""Return whether or not we're 32-bit."""
M32_BIT_ARGS = [
'-m32',
'-mx32',
]
return any(arg in M32_BIT_ARGS for arg in args)
def FilterWlArg(arg):
"""Remove -z,defs and equivalents from a single -Wl option."""
parts = arg.split(',')[1:]
filtered = []
for part in parts:
if part == 'defs':
removed = filtered.pop()
assert removed == '-z'
continue
if part == '--no-undefined':
continue
filtered.append(part)
if filtered:
return '-Wl,' + ','.join(filtered)
# Filtered entire argument.
return None
def _RemoveLastMatching(l, find):
for i in xrange(len(l) - 1, -1, -1):
if l[i] == find:
del l[i]
return
raise IndexError('Not found')
def RemoveZDefs(args):
"""Remove unsupported -Wl,-z,defs linker option."""
filtered = []
for arg in args:
if arg == '-Wl,defs':
_RemoveLastMatching(filtered, '-Wl,-z')
continue
if arg == '-Wl,--no-undefined':
continue
if arg.startswith('-Wl,'):
arg = FilterWlArg(arg)
if not arg:
continue
filtered.append(arg)
return filtered
def GetCompilerArgs(args, is_cxx):
"""Generate compiler args."""
compiler_args = args[1:]
if Is32Bit(args):
# 32 bit builds not supported.
compiler_args.extend([
'-fno-sanitize=memory',
'-fno-sanitize-memory-track-origins',
])
return compiler_args
compiler_args = RemoveZDefs(compiler_args)
compiler_args.extend([
# FORTIFY_SOURCE is not supported by sanitizers.
'-U_FORTIFY_SOURCE',
'-Wp,-U_FORTIFY_SOURCE',
# Reduce binary size.
'-gline-tables-only',
# Disable all warnings.
'-w',
# LTO isn't supported.
'-fno-lto',
])
if InvokedAsGcc():
compiler_args.extend([
# For better compatibility with flags passed via -Wa,...
'-fno-integrated-as',
])
if '-fsanitize=memory' not in args:
# If MSan flags weren't added for some reason, add them here.
compiler_args.extend(msan_build.GetInjectedFlags())
if is_cxx:
compiler_args.append('-stdlib=libc++')
return compiler_args
def FindRealClang():
"""Return path to real clang."""
return os.environ['REAL_CLANG_PATH']
def FallbackToGcc(args):
"""Check whether if we should fall back to GCC."""
if not InvokedAsGcc():
return False
return any(arg in GCC_ONLY_ARGS for arg in args[1:])
def main(args):
if FallbackToGcc(args):
sys.exit(subprocess.call(['/usr/bin/' + os.path.basename(args[0])] +
args[1:]))
is_cxx = args[0].endswith('++')
real_clang = FindRealClang()
if is_cxx:
real_clang += '++'
args = [real_clang] + GetCompilerArgs(args, is_cxx)
debug_log_path = os.getenv('WRAPPER_DEBUG_LOG_PATH')
if debug_log_path:
with open(debug_log_path, 'a') as f:
f.write(str(args) + '\n')
sys.exit(subprocess.call(args))
if __name__ == '__main__':
main(sys.argv)