C++ Code Coverage with CMake and GCOVR

Bensuperpc August 07, 2025 [Software] #Features #Code coverage #Testing #GCOVR

Code Coverage in C/C++ with CMake and GCOVR

Introduction

This tutorial shows how to set up a C/C++ project with CMake and GCOVR to generate code coverage reports. This allows you to precisely verify which parts of the source code and which conditional branches (if, switch, etc.) are actually covered by the tests.

We’ll use a small sample project based on Google Test, but the method is also compatible with other frameworks such as Catch2, Boost.Test, or Doctest.

Minimum Requirements

A distribution like Ubuntu 22.04, Debian 12 or higher is recommended for this tutorial, but you can use any Linux distribution with the required versions of the tools.

Installing Dependencies

To install the necessary dependencies, you can use the following commands:

For Ubuntu/Debian :

sudo apt-get install cmake build-essential g++ gcovr ninja-build libgtest-dev

For Fedora :

sudo dnf install cmake gcc-c++ gcovr ninja-build gtest-devel

For Arch Linux :

sudo pacman -S cmake gcc gcovr ninja gtest

What is GCOVR?

GCOVR is an open-source tool that generates C/C++ code coverage reports from the data produced during test execution.

Sample Project

The sample project is a simple application and two C++ libraries, one for mathematics and one for physics.

Here is the project structure:

.
├── CMakeLists.txt
├── main.cpp
├── math
   ├── CMakeLists.txt
   ├── math.cpp
   └── math.hpp
├── physics
   ├── CMakeLists.txt
   ├── physics.cpp
   └── physics.hpp
└── tests
    ├── CMakeLists.txt
    └── test.cpp

4 directories, 10 files

You can download the sample project: tuto_coverage.7z

Compilation with Coverage

To enable code coverage, the project must be compiled with the options: -O0 -g --coverage and --coverage for linking.

cmake -S . -B build -G Ninja -DCMAKE_CXX_FLAGS="-O0 -g --coverage" -DCMAKE_EXE_LINKER_FLAGS="--coverage" && cmake --build build

The --coverage option is equivalent to -fprofile-arcs -ftest-coverage for GCC/Clang, in a classic project, it is preferable to use CMake presets rather than specifying the options manually.

Running Tests

Once the project is compiled, you can run the tests, this will generate files on which GCOVR relies to generate coverage reports:

ctest --test-dir build --output-on-failure --no-tests=error --repeat until-fail:1 --schedule-random --parallel 1
OptionDescription
--test-dir buildSpecify the directory containing the tests
--output-on-failureShow the output of failed tests
--no-tests=errorGenerates an error if no tests are found
--repeat until-fail:1Repeats the tests until a failure occurs, here 1 time
--schedule-randomRuns the tests in random order
--parallel 1Runs the tests in parallel, here 1 test at a time

You will get output similar to:

Test project /home/bensuperpc/tuto_coverage/build
    Start 3: MathTests.Mul
1/7 Test #3: MathTests.Mul .....................   Passed    0.00 sec
    Start 7: PhysicsTests.GravitationalForce
2/7 Test #7: PhysicsTests.GravitationalForce ...   Passed    0.00 sec
    Start 5: PhysicsTests.Speed
3/7 Test #5: PhysicsTests.Speed ................   Passed    0.00 sec
    Start 2: MathTests.Sub
4/7 Test #2: MathTests.Sub .....................   Passed    0.00 sec
    Start 1: MathTests.Add
5/7 Test #1: MathTests.Add .....................   Passed    0.00 sec
    Start 6: PhysicsTests.KineticEnergy
6/7 Test #6: PhysicsTests.KineticEnergy ........   Passed    0.00 sec
    Start 4: MathTests.Div
7/7 Test #4: MathTests.Div .....................   Passed    0.00 sec

100% tests passed, 0 tests failed out of 7

Total Test time (real) =   0.02 sec

HTML Report with GCOVR

After running the tests, you can generate a coverage report with GCOVR, here we generate an HTML report to visualize the code coverage, but you can also generate reports in plain text, XML or JSON.

gcovr --root "." --decisions --calls --html-theme "green" --exclude "tests/*" --exclude "build/*" --exclude "main.cpp" --html --html-details --output "build/coverage.html"
OptionDescription
--root "."Sets the root directory for coverage
--decisionsIncludes coverage decisions in the report
--callsIncludes function calls in the report
--html-theme "green"Sets the HTML report theme to green
--exclude "tests/*"Excludes test files from the report
--exclude "build/*"Excludes build files from the report
--exclude "main.cpp"Excludes the main.cpp file from the report
--htmlGenerates an HTML report
--html-detailsIncludes details in the HTML report
--output "build/coverage.html"Specifies the output file name for the HTML report

Once the HTML report is generated, you can open it in your browser to visualize the code coverage, it should be generated in the file build/coverage.html.

Here is the rendering of the report in the browser:

Main Page
Main Page
Secondary Page
Secondary Page

XML or JSON Report

You can also generate a report in XML or JSON for integration with other tools:

gcovr --root "." --decisions --calls --exclude "tests/*" --exclude "build/*" --exclude "main.cpp" --xml-pretty --output "build/coverage.xml"

Ou en JSON :

gcovr --root "." --decisions --calls --exclude "tests/*" --exclude "build/*" --exclude "main.cpp" --json-pretty --output "build/coverage.json"

Sources