#!/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)