summaryrefslogtreecommitdiff
path: root/deps/v8/build/toolchain/clang_code_coverage_wrapper.py
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/build/toolchain/clang_code_coverage_wrapper.py')
-rwxr-xr-xdeps/v8/build/toolchain/clang_code_coverage_wrapper.py149
1 files changed, 149 insertions, 0 deletions
diff --git a/deps/v8/build/toolchain/clang_code_coverage_wrapper.py b/deps/v8/build/toolchain/clang_code_coverage_wrapper.py
new file mode 100755
index 0000000000..9697805690
--- /dev/null
+++ b/deps/v8/build/toolchain/clang_code_coverage_wrapper.py
@@ -0,0 +1,149 @@
+#!/usr/bin/env python
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""Removes code coverage flags from invocations of the Clang C/C++ compiler.
+
+If the GN arg `use_clang_coverage=true`, this script will be invoked by default.
+GN will add coverage instrumentation flags to almost all source files.
+
+This script is used to remove instrumentation flags from a subset of the source
+files. By default, it will not remove flags from any files. If the option
+--files-to-instrument is passed, this script will remove flags from all files
+except the ones listed in --files-to-instrument.
+
+This script also contains hard-coded exclusion lists of files to never
+instrument, indexed by target operating system. Files in these lists have their
+flags removed in both modes. The OS can be selected with --target-os.
+
+The path to the coverage instrumentation input file should be relative to the
+root build directory, and the file consists of multiple lines where each line
+represents a path to a source file, and the specified paths must be relative to
+the root build directory. e.g. ../../base/task/post_task.cc for build
+directory 'out/Release'.
+
+One caveat with this compiler wrapper is that it may introduce unexpected
+behaviors in incremental builds when the file path to the coverage
+instrumentation input file changes between consecutive runs, so callers of this
+script are strongly advised to always use the same path such as
+"${root_build_dir}/coverage_instrumentation_input.txt".
+
+It's worth noting on try job builders, if the contents of the instrumentation
+file changes so that a file doesn't need to be instrumented any longer, it will
+be recompiled automatically because if try job B runs after try job A, the files
+that were instrumented in A will be updated (i.e., reverted to the checked in
+version) in B, and so they'll be considered out of date by ninja and recompiled.
+
+Example usage:
+ clang_code_coverage_wrapper.py \\
+ --files-to-instrument=coverage_instrumentation_input.txt
+"""
+
+import argparse
+import os
+import subprocess
+import sys
+
+# Flags used to enable coverage instrumentation.
+# Flags should be listed in the same order that they are added in
+# build/config/coverage/BUILD.gn
+_COVERAGE_FLAGS = [
+ '-fprofile-instr-generate', '-fcoverage-mapping',
+ # Following experimental flags remove unused header functions from the
+ # coverage mapping data embedded in the test binaries, and the reduction
+ # of binary size enables building Chrome's large unit test targets on
+ # MacOS. Please refer to crbug.com/796290 for more details.
+ '-mllvm', '-limited-coverage-experimental=true'
+]
+
+# Map of exclusion lists indexed by target OS.
+# If no target OS is defined, or one is defined that doesn't have a specific
+# entry, use the 'default' exclusion_list. Anything added to 'default' will
+# apply to all platforms that don't have their own specific list.
+_COVERAGE_EXCLUSION_LIST_MAP = {
+ 'default': [],
+ 'chromeos': [
+ # These files caused clang to crash while compiling them. They are
+ # excluded pending an investigation into the underlying compiler bug.
+ '../../third_party/webrtc/p2p/base/p2p_transport_channel.cc',
+ '../../third_party/icu/source/common/uts46.cpp',
+ '../../third_party/icu/source/common/ucnvmbcs.cpp',
+ '../../base/android/android_image_reader_compat.cc',
+ ]
+}
+
+
+def _remove_flags_from_command(command):
+ # We need to remove the coverage flags for this file, but we only want to
+ # remove them if we see the exact sequence defined in _COVERAGE_FLAGS.
+ # That ensures that we only remove the flags added by GN when
+ # "use_clang_coverage" is true. Otherwise, we would remove flags set by
+ # other parts of the build system.
+ start_flag = _COVERAGE_FLAGS[0]
+ num_flags = len(_COVERAGE_FLAGS)
+ start_idx = 0
+ try:
+ while True:
+ idx = command.index(start_flag, start_idx)
+ start_idx = idx + 1
+ if command[idx:idx+num_flags] == _COVERAGE_FLAGS:
+ del command[idx:idx+num_flags]
+ break
+ except ValueError:
+ pass
+
+def main():
+ # TODO(crbug.com/898695): Make this wrapper work on Windows platform.
+ arg_parser = argparse.ArgumentParser()
+ arg_parser.usage = __doc__
+ arg_parser.add_argument(
+ '--files-to-instrument',
+ type=str,
+ help='Path to a file that contains a list of file names to instrument.')
+ arg_parser.add_argument(
+ '--target-os',
+ required=False,
+ help='The OS to compile for.')
+ arg_parser.add_argument('args', nargs=argparse.REMAINDER)
+ parsed_args = arg_parser.parse_args()
+
+ if (parsed_args.files_to_instrument and
+ not os.path.isfile(parsed_args.files_to_instrument)):
+ raise Exception('Path to the coverage instrumentation file: "%s" doesn\'t '
+ 'exist.' % parsed_args.files_to_instrument)
+
+ compile_command = parsed_args.args
+ if not any('clang' in s for s in compile_command):
+ return subprocess.call(compile_command)
+
+ try:
+ # The command is assumed to use Clang as the compiler, and the path to the
+ # source file is behind the -c argument, and the path to the source path is
+ # relative to the root build directory. For example:
+ # clang++ -fvisibility=hidden -c ../../base/files/file_path.cc -o \
+ # obj/base/base/file_path.o
+ index_dash_c = compile_command.index('-c')
+ except ValueError:
+ print '-c argument is not found in the compile command.'
+ raise
+
+ if index_dash_c + 1 >= len(compile_command):
+ raise Exception('Source file to be compiled is missing from the command.')
+
+ compile_source_file = compile_command[index_dash_c + 1]
+ target_os = parsed_args.target_os
+ if target_os not in _COVERAGE_EXCLUSION_LIST_MAP:
+ target_os = 'default'
+ exclusion_list = _COVERAGE_EXCLUSION_LIST_MAP[target_os]
+
+ if compile_source_file in exclusion_list:
+ _remove_flags_from_command(compile_command)
+ elif parsed_args.files_to_instrument:
+ with open(parsed_args.files_to_instrument) as f:
+ if compile_source_file not in f.read():
+ _remove_flags_from_command(compile_command)
+
+ return subprocess.call(compile_command)
+
+if __name__ == '__main__':
+ sys.exit(main())