From 82196add55cfe5ce4291f93176d5a52c35c2423d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Desbiens?= Date: Mon, 24 Aug 2026 14:51:47 -0400 Subject: [PATCH] Matched gcov to the compiler that produced the coverage data gcov reads a data format tied to the compiler that produced it. coverage.sh took whatever gcov was first on PATH, which was fine while the compiler was also whatever was first on PATH. #656 made cmake/linux.cmake honour CC and #657 made a compiler switch actually reconfigure the build, so that assumption no longer holds, and the first person to use the new capability would have hit this. Measured on dev with both of those merged: CC=gcc-14 ./run.sh build default_build_coverage # succeeds ./coverage.sh default_build_coverage # exit 64 gcov says why, if asked directly: tx_block_allocate.c.gcno:version 'B42*', prefer 'B33*' gcovr turns that into "GCOV returncode was 3" and exits 64 through a Python traceback, after the tests have already passed. It reads like a coverage bug rather than a toolchain mismatch, which is the part that would have cost someone an afternoon. gcov is now derived from CC rather than found on PATH, so the caller sets one variable instead of remembering two. GCOV still overrides, for a toolchain that does not follow the gcc/gcov naming, and a derived gcov that does not exist is reported as such instead of surfacing as a traceback. Verified, tx and smp, before and after: CC=gcc-14 was exit 64, now exit 0, 177 files and 1527/3827 lines CC unset exit 0, 177 files and 1527/3827 lines, unchanged CC=gcc-99 exit 1 naming gcov-99 and CC, rather than a traceback GCOV=gcov-14 with CC=gcc-99, exit 0, so the override still wins A mismatched pairing still fails, deliberately: reading a gcc-14 tree with the default gcc-13 gcov is exit 64 as before. Producing a number from mismatched data would be worse than refusing. Assisted-by: Claude Opus 5 --- test/smp/cmake/coverage.sh | 30 ++++++++++++++++++++++++++++-- test/tx/cmake/coverage.sh | 30 ++++++++++++++++++++++++++++-- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/test/smp/cmake/coverage.sh b/test/smp/cmake/coverage.sh index d35284f57..a7312e1f4 100755 --- a/test/smp/cmake/coverage.sh +++ b/test/smp/cmake/coverage.sh @@ -16,5 +16,31 @@ set -e cd $(dirname $0) threadx_smp=$(realpath ../../../common_smp/src) mkdir -p coverage_report/$1 -gcovr --object-directory=build/$1/threadx_smp/CMakeFiles/threadx_smp.dir/$threadx_smp -r build/$1 -f ../../../common_smp/src --xml-pretty --output coverage_report/$1.xml -gcovr --object-directory=build/$1/threadx_smp/CMakeFiles/threadx_smp.dir/$threadx_smp -r build/$1 -f ../../../common_smp/src --html --html-details --output coverage_report/$1/index.html + +# gcov reads a data format tied to the compiler that produced it, so gcov has to match +# the gcc that built the objects. Since cmake/linux.cmake began honouring CC, taking +# whatever gcov happens to be first on PATH is no longer safe: building with gcc-14 and +# reading with gcov-13 gives "version 'B42*', prefer 'B33*'" from gcov, and gcovr turns +# that into "GCOV returncode was 3" and exits 64. The tests pass and then the coverage +# step fails with a Python traceback, which reads like a coverage bug rather than a +# toolchain mismatch. +# +# So derive gcov from CC rather than asking the caller to remember both. GCOV still +# overrides, for a toolchain that does not follow the gcc/gcov naming. +: "${CC:=gcc}" +if [ -z "${GCOV:-}" ]; then + cc_base=$(basename "$CC") + case "$cc_base" in + gcc*) GCOV="gcov${cc_base#gcc}" ;; + *) GCOV="gcov" ;; + esac +fi + +if ! command -v "$GCOV" >/dev/null 2>&1; then + echo "coverage.sh: '$GCOV' not found, derived from CC='$CC'." >&2 + echo "Install it, or set GCOV to the gcov matching that compiler." >&2 + exit 1 +fi + +gcovr --gcov-executable "$GCOV" --object-directory=build/$1/threadx_smp/CMakeFiles/threadx_smp.dir/$threadx_smp -r build/$1 -f ../../../common_smp/src --xml-pretty --output coverage_report/$1.xml +gcovr --gcov-executable "$GCOV" --object-directory=build/$1/threadx_smp/CMakeFiles/threadx_smp.dir/$threadx_smp -r build/$1 -f ../../../common_smp/src --html --html-details --output coverage_report/$1/index.html diff --git a/test/tx/cmake/coverage.sh b/test/tx/cmake/coverage.sh index 6dda78b38..9b47339e8 100755 --- a/test/tx/cmake/coverage.sh +++ b/test/tx/cmake/coverage.sh @@ -15,5 +15,31 @@ set -e cd $(dirname $0) mkdir -p coverage_report/$1 -gcovr --object-directory=build/$1/threadx/CMakeFiles/threadx.dir/common/src -r build/$1 -f ../../../common/src --xml-pretty --output coverage_report/$1.xml -gcovr --object-directory=build/$1/threadx/CMakeFiles/threadx.dir/common/src -r build/$1 -f ../../../common/src --html --html-details --output coverage_report/$1/index.html + +# gcov reads a data format tied to the compiler that produced it, so gcov has to match +# the gcc that built the objects. Since cmake/linux.cmake began honouring CC, taking +# whatever gcov happens to be first on PATH is no longer safe: building with gcc-14 and +# reading with gcov-13 gives "version 'B42*', prefer 'B33*'" from gcov, and gcovr turns +# that into "GCOV returncode was 3" and exits 64. The tests pass and then the coverage +# step fails with a Python traceback, which reads like a coverage bug rather than a +# toolchain mismatch. +# +# So derive gcov from CC rather than asking the caller to remember both. GCOV still +# overrides, for a toolchain that does not follow the gcc/gcov naming. +: "${CC:=gcc}" +if [ -z "${GCOV:-}" ]; then + cc_base=$(basename "$CC") + case "$cc_base" in + gcc*) GCOV="gcov${cc_base#gcc}" ;; + *) GCOV="gcov" ;; + esac +fi + +if ! command -v "$GCOV" >/dev/null 2>&1; then + echo "coverage.sh: '$GCOV' not found, derived from CC='$CC'." >&2 + echo "Install it, or set GCOV to the gcov matching that compiler." >&2 + exit 1 +fi + +gcovr --gcov-executable "$GCOV" --object-directory=build/$1/threadx/CMakeFiles/threadx.dir/common/src -r build/$1 -f ../../../common/src --xml-pretty --output coverage_report/$1.xml +gcovr --gcov-executable "$GCOV" --object-directory=build/$1/threadx/CMakeFiles/threadx.dir/common/src -r build/$1 -f ../../../common/src --html --html-details --output coverage_report/$1/index.html