xo-umbrella2/xo-cmake/bin/xo-cmake-lcov-harness.in
Roland Conybeare 269b7b6cf4 build: coverage build working in umbrella builds (!)
1. more recent lcov is persnickety, need to ignore some errors.
2. need more careful assembly of subdirs with .gcda/.gcno info.
   lcov doesn't like duplication here.
2026-04-09 20:50:32 -04:00

139 lines
3.8 KiB
Bash
Executable file

#!/usr/bin/env bash
srcdir=$1
builddir=$2
outputstem=$3 # optional
lcov=$4 # optional
genhtml=$5 # optional
if [[ -z "${srcdir}" ]]; then
echo "xo-cmake-lcov-harness: expected non-empty srcdir"
exit 1
fi
if [[ -z "${builddir}" ]]; then
echo "xo-cmake-lcov-harness: expected non-empty builddir"
exit 1
fi
if [[ -z ${outputstem} ]]; then
outputstem=$builddir/ccov/out
fi
if [[ -z ${lcov} ]]; then
lcov=@LCOV_EXECUTABLE@
if [[ $lcov == "LCOV_EXECUTABLE-NOTFOUND" ]]; then
echo "xo-cmake-lcov-harness: lcov executable not found during xo-cmake build/install"
exit 1
fi
fi
if [[ -z ${genhtml} ]]; then
genhtml=@GENHTML_EXECUTABLE@
if [[ $genhtml == "GENHTML_EXECUTABLE-NOTFOUND" ]]; then
echo "xo-cmake-lcov-harness: genhtml executable not found during xo-cmake build/install"
exit 1
fi
fi
mkdir -p $builddir/ccov
# directory stems for location of {.gcda, gcno} coverage information,
#
# if we have source tree:
#
# ${srcdir}
# +- foo
# | \- foo.cpp
# \- bar
# \- quux
# +- quux.cpp
# \- quux_main.cpp
#
# then we expect build tree:
#
# ${builddir}
# +- foo
# | \- CMakeFiles
# | \- foo_target.dir
# | +- foo.cpp.gcda
# | \- foo.cpp.gcno
# +- bar
# \- quux
# \- CMakeFiles
# \- target4quux.dir
# +- quux.cpp.gcda
# +- quux.cpp.gcno
# +- quux_main.cpp.gcda
# \- quux_main.cpp.gcno
#
# in which case will have cmd_body:
#
# ${primarydirs}
# ./foo/CMakeFiles/foo_target.dir
# ./bar/quux/CMakeFiles/target4quux.dir
#
# here foo_target, quux_target are whatever build is using for corresponding cmake target names.
#
# We want to invoke lcov like:
#
# lcov --capture \
# --output ${builddir}/ccov \
# --exclude /utest/ \
# --base-directory ${srcdir}/foo --directory ${builddir}/foo/CMakeFiles/foo_target.dir \
# --base-directory ${srcdir}/bar/quux --directory ${builddir}/bar/quux/CMakeFiles/target4quux.dir
#
# collect unique directories containing .gcno files,
# then remove any that are subdirectories of another in the list.
# lcov scans recursively, so passing both parent/ and parent/facet/
# causes "duplicate file" errors.
_alldirs=$(cd ${builddir} && find -name '*.gcno' \
| xargs --replace=xx dirname xx \
| sort -u \
| sed -e 's:^\./::')
primarydirs=""
for d in ${_alldirs}; do
# check if any existing entry is a prefix of d
is_nested=false
for p in ${primarydirs}; do
case "${d}" in
"${p}"/*) is_nested=true; break ;;
esac
done
if ! ${is_nested}; then
primarydirs="${primarydirs} ${d}"
fi
done
#echo "primarydirs=${primarydirs}"
cmd="${lcov} --output ${outputstem}.info --capture --ignore-errors source --ignore-errors empty --ignore-errors inconsistent,inconsistent"
for bdir in ${primarydirs}; do
sdir=$(dirname $(dirname ${bdir}))
cmd="${cmd} --base-directory ${srcdir}/${sdir} --directory ${builddir}/${bdir}"
done
#echo cmd=${cmd}
set -x
# capture
${cmd}
# keep only files with paths under source tree
# (don't want coverage for external libraries such as libstdc++ etc)
${lcov} --extract ${outputstem}.info "${srcdir}/*" --output ${outputstem}2.info --ignore-errors inconsistent,inconsistent
# remove unit test dirs
# (we're interested in coverage of our installed code, not of the unit tests that exercise it)
${lcov} --remove ${outputstem}2.info '*/utest/*' --output ${outputstem}3.info --ignore-errors inconsistent,inconsistent
# generate .html tree
mkdir -p ${builddir}/ccov/html
${genhtml} --ignore-errors source --show-details --prefix ${srcdir} --output-directory ${builddir}/ccov/html ${outputstem}3.info
# also send report to stdout
${lcov} --list ${outputstem}3.info