Fundamentals 11 min read

Measuring Code Coverage for C/C++ Projects with Gcov and LCOV

This article explains how to measure code coverage for C/C++ projects using GCC's built‑in Gcov tool and the LCOV utility, covering prerequisite setup, compilation with profiling flags, running tests, generating .gcno/.gcda files, producing .gcov reports, creating HTML visualizations, and cautions against over‑relying on coverage percentages.

DevOps Engineer
DevOps Engineer
DevOps Engineer
Measuring Code Coverage for C/C++ Projects with Gcov and LCOV

This article demonstrates how to use Gcov and LCOV to measure code coverage for C/C++ projects, providing a practical guide from environment setup to report generation and discussing the limitations of coverage metrics.

Problem

Many legacy C/C++ projects lack unit tests and rely on regression testing, making it difficult to know which code paths are exercised and where test coverage can be improved.

Current Situation

Commercial tools such as Squish Coco and Bullseye insert instrumentation during compilation to record execution, but they can be costly and introduce build complications. GCC already includes a built‑in coverage tool called Gcov .

Prerequisites

To follow the tutorial you need GCC and LCOV installed. The example source code is available at https://github.com/shenxianpeng/gcov-example . The repository’s master branch contains the source, while the coverage branch’s out directory holds the generated reports.

# 这是我的测试环境上的 GCC 和 lcov 的版本
sh-4.2$ gcc --version
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

sh-4.2$ lcov -v
lcov: LCOV version 1.14

How Gcov Works

The workflow consists of three main steps:

Compile with special flags ( -fprofile-arcs and -ftest-coverage ) to generate .gcno files.

Run the resulting executable to produce .gcda data files.

Use gcov to convert .gcno and .gcda into .gcov reports, then feed them to LCOV for HTML visualization.

1. Compilation

The required compile options are defined in the makefile . Running make builds the program and creates the profiling files.

make
sh-4.2$ make
gcc -fPIC -fprofile-arcs -ftest-coverage -c -Wall -Werror main.c
gcc -fPIC -fprofile-arcs -ftest-coverage -c -Wall -Werror foo.c
gcc -fPIC -fprofile-arcs -ftest-coverage -o main main.o foo.o

The compilation produces .gcno files alongside the object files.

2. Running the Executable

Execute the program to generate .gcda files.

./main
sh-4.2$ ./main
Start calling foo() ...
when num is equal to 1...
when num is equal to 2...

Each source file now has a corresponding .gcda file containing execution counts.

3. Generating the Report

Run make report to invoke gcov and then LCOV.

make report
sh-4.2$ make report
gcov main.c foo.c
File 'main.c'
Lines executed:100.00% of 5
Creating 'main.c.gcov'

File 'foo.c'
Lines executed:85.71% of 7
Creating 'foo.c.gcov'

Lines executed:91.67% of 12
lcov --capture --directory . --output-file coverage.info
... (output omitted for brevity) ...
Overall coverage rate:
  lines......: 91.7% (11 of 12 lines)
  functions..: 100.0% (2 of 2 functions)

The command performs two actions: (1) runs gcov on the source files to produce .gcov files, and (2) uses LCOV to aggregate the data and generate an HTML report.

# 1. Generate coverage.info data file
lcov --capture --directory . --output-file coverage.info
# 2. Generate HTML report
genhtml coverage.info --output-directory out

Cleaning Up

All generated files can be removed with make clean :

sh-4.2$ make clean
rm -rf main *.o *.so *.gcno *.gcda *.gcov coverage.info out

Code Coverage Report

The HTML report shows covered lines in blue and uncovered lines in red, supporting line, function, and branch coverage.

Don’t Overestimate Coverage Metrics

High coverage percentages do not guarantee effective testing; they only indicate which code was executed. Striving for 100% coverage can lead to meaningless tests that add little value. As Martin Fowler notes, coverage is useful for locating untested code but is a poor indicator of test quality.

Further Reading

Using Gcov in the Linux kernel – example

Setting environment variables for cross‑profiling – documentation

References

Squish Coco – https://shenxianpeng.github.io/2019/05/squishcoco/

Gcov – https://gcc.gnu.org/onlinedocs/gcc/Gcov.html

GCC – https://gcc.gnu.org/install/index.html

LCOV – http://ltp.sourceforge.net/coverage/lcov.php

gcovr – https://github.com/gcovr/gcovr

Martin Fowler on Test Coverage – https://www.martinfowler.com/bliki/TestCoverage.html

code coverageTestingC++gcovgcclcov
DevOps Engineer
Written by

DevOps Engineer

DevOps engineer, Pythonista and FOSS contributor. Created cpp-linter, commit-check, etc.; contributed to PyPA.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.