Code Coverage with SonarQube#

This guide explains how to build the project with gcov instrumentation, run the unit tests, and feed the resulting coverage data into SonarQube.


Prerequisites#

  • GCC toolchain with gcov (installed alongside g++)

  • CMake 3.20+

  • CUDA 12.x+ and TensorRT 10.x+

  • gcovr (required, generates SonarQube coverage reports) — install with pip install gcovr

  • sonar-scanner (for uploading results to SonarQube)


Quick Start#

A convenience script handles the full workflow — configure, build, test, and report — in a single command:

./scripts/run_coverage.sh --trt-package-dir /path/to/TensorRT

The TRT_PACKAGE_DIR can also be supplied as an environment variable:

export TRT_PACKAGE_DIR=/usr/local/TensorRT-10.x.x
./scripts/run_coverage.sh

After the script completes, coverage data is available in build_coverage/ and SonarQube can be run immediately with sonar-scanner.

Script Options#

Flag

Description

Default

--trt-package-dir <path>

Path to TensorRT installation (required unless TRT_PACKAGE_DIR is set)

--cuda-version <ver>

CUDA version to use

12.8

--build-dir <dir>

Build output directory

build_coverage

--gtest-filter <filter>

Google Test filter expression

* (all tests)

--jobs, -j <N>

Parallel build jobs

$(nproc)


Manual Workflow#

If you need finer control you can run each step individually.

1. Configure#

mkdir -p build_coverage
cmake -S . -B build_coverage \
    -DCMAKE_BUILD_TYPE=Debug \
    -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
    -DBUILD_UNIT_TESTS=ON \
    -DENABLE_COVERAGE=ON \
    -DTRT_PACKAGE_DIR=/path/to/TensorRT

The key CMake options for coverage are:

Option

Description

Default

ENABLE_COVERAGE

Enable gcov instrumentation (--coverage flags)

OFF

BUILD_UNIT_TESTS

Build the Google Test unit test binary

OFF

CMAKE_BUILD_TYPE

Must be Debug for accurate coverage

CMAKE_EXPORT_COMPILE_COMMANDS

Generate compile_commands.json (required by SonarQube)

OFF

Note: ENABLE_COVERAGE warns at configure time if CMAKE_BUILD_TYPE is not Debug, because compiler optimizations can cause misleading coverage results.

2. Build#

Build only the unit test target to keep compile times short:

cmake --build build_coverage --target unitTests -j$(nproc)

The build produces .gcno files alongside every object file. These contain the control-flow graph that gcov needs to map execution counts back to source lines.

3. Clear Stale Data#

If you are re-running tests after a previous coverage run, delete old .gcda files so results are not accumulated:

find build_coverage -name '*.gcda' -delete

4. Run Tests#

ctest --test-dir build_coverage --output-on-failure --parallel $(nproc) \
    --output-junit build_coverage/test_results.xml

Running the instrumented binaries produces .gcda files that record how many times each basic block was executed. Every group writes into the same .gcda set, so the report is the union of all of them.

To narrow the run, either invoke one group directly or set GTEST_FILTER, which ctest passes through to each executable:

./build_coverage/unittests/unitTestCommon --gtest_filter="LoggerTest.*"
GTEST_FILTER="LoggerTest.*" ctest --test-dir build_coverage

5. Generate Reports#

Use gcovr to convert the raw gcov data into reports. The SonarQube generic coverage XML (--sonarqube) is required for coverage import:

GCOVR_COMMON="--root . \
    --filter cpp/ \
    --filter unittests/ \
    --exclude 3rdParty/ \
    --exclude '.*\.cu$' \
    --gcov-ignore-errors=no_working_dir_found \
    --gcov-ignore-parse-errors=all"

# SonarQube generic coverage format (required for sonar.coverageReportPaths)
gcovr $GCOVR_COMMON \
    --sonarqube build_coverage/sonarqube-coverage.xml

# Cobertura XML (optional, for other CI integrations)
gcovr $GCOVR_COMMON \
    --xml-pretty \
    --output build_coverage/coverage.xml

# HTML with per-file detail (optional, for local viewing)
gcovr $GCOVR_COMMON \
    --html-details build_coverage/coverage.html

Open build_coverage/coverage.html in a browser for a quick local overview.


SonarQube Integration#

The project’s sonar-project.properties is pre-configured for coverage:

sonar.cfamily.compile-commands=build_coverage/compile_commands.json
sonar.coverageReportPaths=build_coverage/sonarqube-coverage.xml
  • sonar.coverageReportPaths points to the SonarQube generic coverage XML generated by gcovr --sonarqube. This is the format SonarQube uses to import line coverage data.

  • sonar.cfamily.compile-commands points to the compilation database so SonarQube can accurately parse the C++ source files.

  • build_coverage/** is not listed in sonar.sources to prevent SonarQube from scanning build artifacts (object files, HTML reports, etc.) as source code.

After a coverage build and test run, upload results with:

sonar-scanner

Tip: If your build directory is not build_coverage, override the properties on the command line:

sonar-scanner \
    -Dsonar.coverageReportPaths=my_build/sonarqube-coverage.xml \
    -Dsonar.cfamily.compile-commands=my_build/compile_commands.json

What Gets Instrumented#

  • C++ source files (.cpp) — fully instrumented with line and branch coverage.

  • CUDA files (.cu) — not instrumented. nvcc generates temporary stub files in /tmp/ during compilation that are deleted after the build. The resulting .gcno files contain unresolvable source references, which causes gcov and gcovr to fail. Coverage is therefore limited to .cpp files.

  • Third-party code (3rdParty/) — excluded from coverage reports via sonar.exclusions and gcovr --exclude filters.


CI Integration Example#

Below is a minimal CI job that produces coverage for SonarQube:

coverage:
  stage: test
  script:
    - pip install gcovr
    - ./scripts/run_coverage.sh --trt-package-dir $TRT_PACKAGE_DIR
    - sonar-scanner
  artifacts:
    paths:
      - build_coverage/sonarqube-coverage.xml
      - build_coverage/coverage.xml
      - build_coverage/coverage.html
      - build_coverage/test_results.xml
    reports:
      junit: build_coverage/test_results.xml

Troubleshooting#

gcov not found during CMake configure

gcov is part of the GCC toolchain. Install it with:

sudo apt install gcc

No .gcda files after running tests

  • Verify the binary was built with ENABLE_COVERAGE=ON (--coverage should appear in the compile commands).

  • Ensure the test binary runs to completion (or at least exits normally). Coverage data is flushed on exit().

Coverage percentages seem too low

  • Use CMAKE_BUILD_TYPE=Debug to prevent the compiler from optimizing away branches.

  • Make sure you cleared old .gcda files before the test run so you are not mixing stale data.

SonarQube shows 0% coverage

  • Confirm sonar.coverageReportPaths points to the sonarqube-coverage.xml file generated by gcovr --sonarqube.

  • Confirm sonar.cfamily.compile-commands points to a valid compile_commands.json generated by the same build.

  • Run sonar-scanner from the repository root so relative paths in sonar-project.properties resolve correctly.

  • Verify the source file paths inside sonarqube-coverage.xml match the files that SonarQube is analyzing (paths must be relative to the project root or absolute).