Cookbook
This section contains how-to guides on creating code coverage reports for various purposes. For an introduction on using gcovr, see the User Guide instead.
Recipes in the cookbook:
How to collect coverage for C extensions in Python
Collecting code coverage data on the C code that makes up a Python extension module is not quite as straightforward as with a regular C program.
As with a normal C project,
we have to compile our code with coverage instrumentation.
Here, we export CFLAGS="--coverage"
and then run python3 setup.py build_ext
.
Unfortunately, build_ext
can rebuild a source file
even if the current object file is up to date.
If multiple extension modules share the same source code file,
gcov will get confused by the different timestamps
and report inaccurate coverage.
It is nontrivial to adapt the build_ext
process to avoid this.
Instead, we can use the ccache
utility to make the compilation lazy
(works best on Unix systems).
Before we invoke the build_ext
step, we first export CC="ccache gcc"
.
Ccache works well but isn’t absolutely perfect,
see the ccache manual for caveats.
A shell session might look like this:
# Set required env vars
export CFLAGS="--coverage"
export CC="ccache gcc"
# clear out build files so we get a fresh compile
rm -rf build/temp.* # contains old .gcda, .gcno files
rm -rf build/lib.*
# rebuild extensions
python3 setup.py build_ext --inplace # possibly --force
# run test command i.e. pytest
# run gcovr
rm -rf coverage; mkdir coverage
gcovr --filter src/ --txt-summary --html-details coverage/index.html
Out-of-Source Builds with CMake
Tools such as cmake
encourage the use of out-of-source builds,
where the code is compiled in a directory other than the one which
contains the sources. This is an extra complication for gcov
.
In order to pass the correct compiler and linker flags, the following
commands need to be in CMakeLists.txt
:
# This flags are used if cmake is called with -DCMAKE_BUILD_TYPE=PROFILE
set(CMAKE_C_FLAGS_PROFILE --coverage)
set(CMAKE_CXX_FLAGS_PROFILE --coverage)
add_executable(program example.cpp)
The --coverage
compiler flag is an alternative to
-fprofile-arcs -ftest-coverage
for
recent version of gcc.
In versions 3.13 and later of cmake
, the
target_link_libraries
command can be removed and
add_link_options("--coverage")
added after
the add_compile_options
command.
We then follow a normal cmake
build process:
cd $BLD_DIR
cmake -DCMAKE_BUILD_TYPE=PROFILE $SRC_DIR
make VERBOSE=1
and run the program:
cd $BLD_DIR
./program
However, invocation of gcovr
itself has to change. The assorted
.gcno
and .gcda
files will appear under the CMakeFiles
directory in BLD_DIR
, rather than next to the sources. Since
gcovr
requires both, the command we need to run is:
cd $BLD_DIR
gcovr -r $SRC_DIR .
Support of Keil uVision format
As mentioned in comment of issue 697
the format of gcov
file generated by the Keil uVision compiler is not compatible with the
gcov
specification.
To support coverage data generated by this compiler you have to create the gcov files as documented
in Keil uVision documentation
and process them before running gcov
to get the correct format.
Save the following Sed script as fix-gcov.sed
:
# fix markers for uncovered code:
# match any of #=%$ repeated 6 times
s/^\([#=%$]\)\(\1\{5\}\)/\2/
# fix branch tags
/^branch/ {
s/executed 0/never executed/
s/executed .*/taken 1/
s/skipped .*/never executed/
}
Then, apply this Sed script to all gcov files before invoking gcovr:
find . -name '*.gcov' -exec sed -i -f fix-gcov.sed {} \;
gcovr --gcov-use-existing-files
Warning
Untested because we have no access to Keil uVision compiler
How to create a standalone application
To create a standalone application you need to install the test suite
(see Test suite). In this test suite you can build a standalone
executable with the command python3 -m nox --session bundle_app
.
The command creates the application build/gcovr
and calls the
executable whith each format to check if it’s working correct.