Support exporting coverage data in lcov format
TEST=coverage.py --format lcov works and coverage_test.py passes
BUG=b:196885721
Change-Id: Ia37165fb20b9a7e0976f1ec51f1e1d9b5e2d8fde
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3098794
Reviewed-by: Yuke Liao <[email protected]>
Commit-Queue: Akekawit Jitprasert <[email protected]>
Cr-Commit-Position: refs/heads/main@{#914805}
diff --git a/tools/code_coverage/coverage.py b/tools/code_coverage/coverage.py
index dda605f..9c519a9 100755
--- a/tools/code_coverage/coverage.py
+++ b/tools/code_coverage/coverage.py
@@ -124,6 +124,9 @@
# Name of the file with summary information generated by llvm-cov export.
SUMMARY_FILE_NAME = os.extsep.join(['summary', 'json'])
+# Name of the coverage file in lcov format generated by llvm-cov export.
+LCOV_FILE_NAME = os.extsep.join(['coverage', 'lcov'])
+
# Build arg required for generating code coverage data.
CLANG_COVERAGE_BUILD_ARG = 'use_clang_coverage'
@@ -248,6 +251,40 @@
logging.debug('Finished running "llvm-cov show" command.')
+def _GeneratePerFileLineByLineCoverageInLcov(binary_paths, profdata_file_path, filters,
+ ignore_filename_regex):
+ """Generates per file line-by-line coverage using "llvm-cov export".
+
+ Args:
+ binary_paths: A list of paths to the instrumented binaries.
+ profdata_file_path: A path to the profdata file.
+ filters: A list of directories and files to get coverage for.
+ ignore_filename_regex: A regular expression for skipping source code files
+ with certain file paths.
+ """
+ logging.debug('Generating per file line by line coverage reports using '
+ '"llvm-cov export" command.')
+ for path in binary_paths:
+ if not os.path.exists(path):
+ logging.error("Binary %s does not exist", path)
+ subprocess_cmd = [
+ LLVM_COV_PATH, 'export', '-format=lcov',
+ '-instr-profile=' + profdata_file_path, binary_paths[0]
+ ]
+ subprocess_cmd.extend(
+ ['-object=' + binary_path for binary_path in binary_paths[1:]])
+ _AddArchArgumentForIOSIfNeeded(subprocess_cmd, len(binary_paths))
+ subprocess_cmd.extend(filters)
+ if ignore_filename_regex:
+ subprocess_cmd.append('-ignore-filename-regex=%s' % ignore_filename_regex)
+
+ # Write output on the disk to be used by code coverage bot.
+ with open(_GetLcovFilePath(), 'w') as f:
+ subprocess.check_call(subprocess_cmd, stdout=f)
+
+ logging.debug('Finished running "llvm-cov export" command.')
+
+
def _GetLogsDirectoryPath():
"""Path to the logs directory."""
return os.path.join(
@@ -268,6 +305,13 @@
SUMMARY_FILE_NAME)
+def _GetLcovFilePath():
+ """The LCOV file that contains coverage data written by llvm-cov export."""
+ return os.path.join(
+ coverage_utils.GetCoverageReportRootDirPath(OUTPUT_DIR),
+ LCOV_FILE_NAME)
+
+
def _CreateCoverageProfileDataForTargets(targets, commands, jobs_count=None):
"""Builds and runs target to generate the coverage profile data.
@@ -973,8 +1017,8 @@
'--format',
type=str,
default='html',
- help='Output format of the "llvm-cov show" command. The supported '
- 'formats are "text" and "html".')
+ help='Output format of the "llvm-cov show/export" command. The '
+ 'supported formats are "text", "html" and "lcov".')
arg_parser.add_argument(
'-v',
@@ -1083,14 +1127,21 @@
binary_paths.extend(
coverage_utils.GetSharedLibraries(binary_paths, BUILD_DIR, otool_path))
- assert args.format == 'html' or args.format == 'text', (
- '%s is not a valid output format for "llvm-cov show". Only "text" and '
- '"html" formats are supported.' % (args.format))
+ assert args.format in ['html', 'lcov', 'text'], (
+ '%s is not a valid output format for "llvm-cov show/export". Only '
+ '"text", "html" and "lcov" formats are supported.' % (args.format))
logging.info('Generating code coverage report in %s (this can take a while '
'depending on size of target!).' % (args.format))
per_file_summary_data = _GeneratePerFileCoverageSummary(
binary_paths, profdata_file_path, absolute_filter_paths,
args.ignore_filename_regex)
+
+ if args.format == 'lcov':
+ _GeneratePerFileLineByLineCoverageInLcov(
+ binary_paths, profdata_file_path, absolute_filter_paths,
+ args.ignore_filename_regex)
+ return
+
_GeneratePerFileLineByLineCoverageInFormat(
binary_paths, profdata_file_path, absolute_filter_paths,
args.ignore_filename_regex, args.format)