Matched gcov to the compiler that produced the coverage data (#658)

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 <noreply@anthropic.com>
This commit is contained in:
Frédéric Desbiens
2026-08-24 15:55:18 -04:00
committed by GitHub
parent a4397e133a
commit eabdb86409
2 changed files with 56 additions and 4 deletions
+28 -2
View File
@@ -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
+28 -2
View File
@@ -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