| 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 |