Collect C++ lcov coverage if runtime object not in runfiles
Before this commit, collecting C++ coverage in lcov format would fail
at the llvm-cov export step if a shared library listed in the
runtime_objects_list.txt was not contained in the runfiles of the top-
level target. This can happen e.g. if a cc_library depends on a
java_binary that has a cc_binary shared library in its resources.
This is fixed by not including objects that don't exist at runtime
in the llvm-cov invocation.
Fixes #15121.
Closes #15118.
PiperOrigin-RevId: 442799461
diff --git a/src/test/shell/bazel/bazel_coverage_cc_test_llvm.sh b/src/test/shell/bazel/bazel_coverage_cc_test_llvm.sh
index 07cc3ff..be3b1ed 100755
--- a/src/test/shell/bazel/bazel_coverage_cc_test_llvm.sh
+++ b/src/test/shell/bazel/bazel_coverage_cc_test_llvm.sh
@@ -146,7 +146,77 @@
LF:7
end_of_record"
- assert_equals "$(cat $(get_coverage_file_path_from_test_log))" "$expected_result"
+ assert_equals "$expected_result" "$(cat $(get_coverage_file_path_from_test_log))"
}
+function test_cc_test_with_runtime_objects_not_in_runfiles() {
+ local -r llvm_profdata="/usr/bin/llvm-profdata-9"
+ if [[ ! -x ${llvm_profdata} ]]; then
+ return
+ fi
+
+ local -r clang="/usr/bin/clang-9"
+ if [[ ! -x ${clang} ]]; then
+ return
+ fi
+
+ local -r llvm_cov="/usr/bin/llvm-cov-9"
+ if [[ ! -x ${llvm_cov} ]]; then
+ return
+ fi
+
+ cat << EOF > BUILD
+cc_test(
+ name = "main",
+ srcs = ["main.cpp"],
+ data = [":jar"],
+)
+
+java_binary(
+ name = "jar",
+ resources = [":shared_lib"],
+ create_executable = False,
+)
+
+cc_binary(
+ name = "shared_lib",
+ linkshared = True,
+)
+EOF
+
+ cat << EOF > main.cpp
+#include <iostream>
+
+int main(int argc, char const *argv[])
+{
+ if (argc < 5) {
+ std::cout << "Hello World!" << std::endl;
+ }
+}
+EOF
+
+
+ BAZEL_USE_LLVM_NATIVE_COVERAGE=1 GCOV=$llvm_profdata CC=$clang \
+ BAZEL_LLVM_COV=$llvm_cov bazel coverage --experimental_generate_llvm_lcov \
+ --test_output=all --instrument_test_targets \
+ //:main &>$TEST_log || fail "Coverage for //:main failed"
+
+ local expected_result="SF:main.cpp
+FN:4,main
+FNDA:1,main
+FNF:1
+FNH:1
+DA:4,1
+DA:5,1
+DA:6,1
+DA:7,1
+DA:8,1
+LH:5
+LF:5
+end_of_record"
+
+ assert_equals "$expected_result" "$(cat $(get_coverage_file_path_from_test_log))"
+}
+
+
run_suite "test tests"
\ No newline at end of file
diff --git a/tools/test/collect_cc_coverage.sh b/tools/test/collect_cc_coverage.sh
index c339659..f532e9b 100755
--- a/tools/test/collect_cc_coverage.sh
+++ b/tools/test/collect_cc_coverage.sh
@@ -85,7 +85,9 @@
while read -r line; do
if [[ ${line: -24} == "runtime_objects_list.txt" ]]; then
while read -r line_runtime_object; do
+ if [[ -e "${RUNFILES_DIR}/${TEST_WORKSPACE}/${line_runtime_object}" ]]; then
object_param+=" -object ${RUNFILES_DIR}/${TEST_WORKSPACE}/${line_runtime_object}"
+ fi
done < "${line}"
fi
done < "${COVERAGE_MANIFEST}"