blob: b66c9ae030c6cf78e935f0ab7bb74b089302f688 [file] [log] [blame]
from __future__ import print_function
# We need to be very careful about adding imports to this function, as the
# imports will increase execution time, and this is called for every
# compiler invocation.
import os
import sys
WRAPPER_ONLY_OPTIONS = set((
'-print-cmdline',
'-nopie',
'-noccache',
'-clang-syntax',
))
X86_DISABLE_FLAGS = set(['-mno-movbe'])
#
# Flags to add when generating compiler wrapper for llvm-next.
# Real flags are added in llvm_next.flags file; this is normally
# an empty placeholder, to prevent needing multiple copies of
# clang_host_wrapper.body.
#
LLVM_NEXT_FLAGS_TO_ADD = set([])
# GCC flags to remove from the clang command line.
# TODO: Once clang supports GCC compatibility mode, remove
# these checks.
#
# Use of -Qunused-arguments allows this set to be small, just those
# that clang still warns about.
CLANG_UNSUPPORTED = set((
'-pass-exit-codes',
'-Wclobbered',
'-Wunsafe-loop-optimizations',
'-Wlogical-op',
'-Wmissing-parameter-type',
'-Woverride-init',
'-Wold-style-declaration',
'-Wno-psabi',
'-mno-movbe',
))
# Flags not supported by GCC.
GCC_UNSUPPORTED = set(['-Xcompiler'])
# Flags not supported by sanitizers (ASan etc.)
UNSUPPORTED_ASAN_FLAGS = set((
'-Wl,--no-undefined',
'-Wl,-z,defs',
'-D_FORTIFY_SOURCE=1',
'-D_FORTIFY_SOURCE=2',
))
FUZZER_FLAGS_TO_ADD = set((
# TODO: This flag should be removed once fuzzer works with new pass manager
'-fno-experimental-new-pass-manager',
))
CLANG_UNSUPPORTED_PREFIXES = ('-Wstrict-aliasing=', '-finline-limit=')
# clang with '-ftrapv' generates 'call __mulodi4', which is only implemented
# in compiler-rt library. However compiler-rt library only has i386/x86_64
# backends (see '/usr/lib/clang/3.7.0/lib/linux/libclang_rt.*'). GCC, on the
# other hand, generate 'call __mulvdi3', which is implemented in libgcc. See
# bug chromium:503229.
CLANG_ARM_OPTIONS_TO_BE_DISCARDED = set(['-ftrapv'])
# Conversion for flags supported by clang but not gcc.
CLANG_TO_GCC = {
'-march=goldmont': '-march=silvermont',
'-march=goldmont-plus': '-march=silvermont',
'-march=skylake': '-march=corei7',
}
# Clang may use different options for the same or similar functionality.
GCC_TO_CLANG = {
'-Wno-error=unused-but-set-variable': '-Wno-error=unused-variable',
'-Wno-error=maybe-uninitialized': '-Wno-error=uninitialized',
'-Wno-unused-but-set-variable': '-Wno-unused-variable',
'-Wunused-but-set-variable': '-Wunused-variable',
'-Wno-error=cpp': '-Wno-#warnings',
}
def handle_exec_exception(exc, argv0, use_ccache, execargs):
"""Analyze compiler execution errors."""
import errno
if use_ccache and exc.errno == errno.ENOENT:
print('error: make sure you install ccache\n', file=sys.stderr)
print(
'error: execution of (%s, %s) failed' % (argv0, execargs),
file=sys.stderr)
raise
def has_sanitizer_flags(args):
"""Returns true if ASan/MSan flags are present."""
if any([x.startswith('-fsanitize') for x in args]):
return True
return False
def has_fuzzer_flags(args):
"""Returns true if fuzzer flags are present."""
if any([(x.startswith('-fsanitize') and 'fuzzer' in x) for x in args]):
return True
return False
def startswith_i86(s):
"""Returns true if s starts with i.86."""
return s[0] + s[2:4] == 'i86'
def find_source_file(arg_list):
"""Find c source file in arg list, if it exists."""
c_endings = ('.c', '.cc', '.cpp', '.C', '.cxx', '.c++')
num_args = len(arg_list)
i = 1 # Start with second arg
while i < num_args:
arg = arg_list[i]
for ext in c_endings:
if arg.endswith(ext) and arg_list[i-1] != '-o':
return arg
i += 1
return ''
def double_build_with_wno_error(cmd,
new_warnings_dir='/tmp/fatal_clang_warnings'):
import subprocess
def run_clang(extra_args):
p = subprocess.Popen(
cmd + extra_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
exit_code = p.wait()
return exit_code, stdout, stderr
# Note that some tools depend on output appearing on the right std stream
# (e.g. `go vet`).
#
# FIXME: Interleaving as clang does would be nice, but it appears that all
# diags/complaints appear on stderr before anything can appear on stdout, and
# trying to do that might be somewhat race-prone.
original_exit_code, original_stdout, original_stderr = run_clang([])
stdout_to_dump, stderr_to_dump = original_stdout, original_stderr
try:
# The only way we can do anything useful is if it looks like the failure
# was -Werror-related.
if not (original_exit_code and '-Werror' in original_stderr):
return original_exit_code
retry_exit_code, retry_stdout, retry_stderr = run_clang(['-Wno-error'])
# If -Wno-error fixed us, pretend that we never ran without -Wno-error.
# Otherwise, pretend that we never ran the second invocation. Since -Werror
# is an issue, log in either case.
if not retry_exit_code:
stdout_to_dump, stderr_to_dump = retry_stdout, retry_stderr
finally:
sys.stdout.write(stdout_to_dump)
sys.stderr.write(stderr_to_dump)
import errno
import json
import tempfile
# All of the below is basically logging. If we fail at any point, it's
# reasonable for that to fail the build. This is all meant for FYI-like
# builders in the first place.
# Ensure that our mode below will pass through unharmed.
old_umask = os.umask(0)
try:
# Allow root and regular users to write to this without issue.
os.makedirs(new_warnings_dir, mode=0o777)
except OSError as e:
if e.errno != errno.EEXIST:
raise
os.umask(old_umask)
# Have some tag to show that files aren't fully written. It would be sad if
# an interrupted build (or out of disk space, or similar) caused tools to
# have to be overly-defensive.
incomplete_suffix = '.incomplete'
# Coming up with a consistent name for this is difficult (compiler command's
# SHA can clash in the case of identically named files in different
# directories, or similar); let's use a random one.
file_handle, file_name = tempfile.mkstemp(
prefix='warnings_report',
suffix='.json' + incomplete_suffix,
dir=new_warnings_dir,
text=True)
os.fchmod(file_handle, 0o666)
output_to_log = '\n'.join(
piece for piece in [original_stderr, original_stdout] if piece)
with os.fdopen(file_handle, 'w') as report_file:
json_data = {
'cwd': os.getcwd(),
'command': cmd,
'stdout': output_to_log,
}
json.dump(json_data, report_file)
os.rename(file_name, file_name[:-len(incomplete_suffix)])
return retry_exit_code