From bb6f1a7ce79168055ccd62629da07d46a52b930d Mon Sep 17 00:00:00 2001 From: Fabian Meumertzheim Date: Tue, 19 Apr 2022 06:51:28 -0700 Subject: [PATCH] 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 --- .../bazel/bazel_coverage_cc_test_llvm.sh | 72 ++++++++++++++++++- tools/test/collect_cc_coverage.sh | 2 + 2 files changed, 73 insertions(+), 1 deletion(-) 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 07cc3fffda758b..be3b1ed0938e6f 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 @@ LH:5 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 + +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 c339659961abbf..f532e9be31a86e 100755 --- a/tools/test/collect_cc_coverage.sh +++ b/tools/test/collect_cc_coverage.sh @@ -85,7 +85,9 @@ function llvm_coverage_lcov() { 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}"