.. _compiling:

Compiling for Coverage
======================

In order to collect coverage data,
your software must be “instrumented” by the compiler.
That means, you must re-compile your software with special compiler options.

The general workflow is:

1. compile your software to enable coverage profiling
2. execute your software to collect coverage profiles
3. run ``gcovr`` to create reports from the collected coverage profiling data

This document explains how you can use GCC or Clang
to compile with coverage instrumentation.

If you cannot compile your software with coverage flags,
you cannot use gcovr.
However, other tools like kcov_ might help.

.. _kcov: https://github.com/SimonKagstrom/kcov


Example Code
------------

The following ``example.cpp`` program
is used to illustrate the compilation process:

.. include:: ../../examples/example.cpp
    :code: cpp
    :number-lines: 1

This code executes several subroutines in this program,
but some lines in the program are not executed.


Compiler Options
----------------

We compile ``example.cpp`` with the GCC compiler as follows:

.. include:: ../../examples/example.sh
    :code: bash
    :start-after: #BEGIN compile
    :end-before: #END compile

What do these compiler flags mean?

* We compile without optimization (``-O0``),
  because optimizations may merge lines of code
  or otherwise change the flow of execution in the program.
  This can change the measured coverage.

  On the other hand, enabling basic optimizations with ``-O1``
  can sometimes produce “better” coverage reports, especially for C++.
  This is a matter of personal preference,
  just make sure to avoid comparing coverage metrics across optimization levels.

  If you are having problems with lots of uncovered branches,
  see: :ref:`exception branches`

* Either ``--coverage`` or  ``-fprofile-arcs -ftest-coverage`` are needed
  so that the compiler produces the information necessary to gather coverage data.

  With these options, the compiler adds logic to the output program
  that counts how often which part of the code was executed.
  The compiler will also create a ``example.gcno`` file with metadata.
  The name of the gcno file matches the compilation unit (see below).

Optional compiler flags:

* You can use other flags like ``-g`` or ``-fPIC`` as required by your tests.
  These don't affect the coverage results.

* Using ``-fprofile-abs-path`` (available since GCC 8)
  can avoid some problems with interpreting the coverage data correctly.
  By default, the additional coverage files generated by GCC
  contain relative paths from the working directory to the source files.
  If there are multiple potential working directories
  from which you might have run the compiler,
  gcovr can get confused.
  Adding this option is more robust.

This examples uses the ``g++`` compiler for C++ code,
but any GCC or Clang-based compiler should work.

If you are using CMake, see :ref:`oos cmake`
for information on configuring that build system
to compile your software with coverage enabled.


Running the Program
-------------------

The above compiler invocation generated a ``program`` executable.
Now, we have to execute this command:

.. include:: ../../examples/example.sh
    :code: bash
    :start-after: #BEGIN run
    :end-before: #END run

This will run whatever you designed this program to do.
Often, such a program would contain unit tests to exercise your code.

As a side effect, this will create an ``example.gcda`` file
with the coverage data for our compilation unit.
This is a binary file so it needs to be processed first.
Together, the ``.gcda`` and ``.gcno`` files can be used
to create coverage reports.


Processing Coverage
-------------------

Your compiler ships with tools to analyze the coverage data files.
For GCC, this is ``gcov``.
For Clang, this is ``llvm-cov``.
You don't have to call these programs yourself – gcovr will do that for you.

So let's invoke gcovr:

.. include:: ../../examples/example.sh
    :code: bash
    :start-after: #BEGIN gcovr
    :end-before: #END gcovr

This will search for all your ``.gcno`` and ``.gcda`` files,
run the compiler's gcov tool,
and summarize the code coverage statistics into a report.
By default, we get a text summary on the command line
that shows aggregate statistics for each line:

.. include:: ../../examples/example.txt
    :literal:

Gcovr supports many different :ref:`output_formats`
that you can generate instead.


Choosing the Right Gcov Executable
----------------------------------

If you have multiple compilers installed or if you are using Clang,
you will likely need to tell gcovr which gcov executable to use.
By default, gcovr just uses the program named ``gcov``.
This is fine for the default GCC compiler,
e.g. ``gcc`` or ``g++``.
Otherwise, you must use the :option:`--gcov-executable <gcovr --gcov-executable>`
to tell gcovr what to use.

If you have used a specific GCC version (e.g. ``gcc-8`` or ``g++-8``),
then you must name the gcov tool with the corresponding version.
For example::

    gcovr --gcov-executable gcov-8

If you have used Clang, then you can use its gcov emulation mode.
For example::

    gcovr --gcov-executable "llvm-cov gcov"

Again, the ``llvm-cov`` name may have to include your compiler version.


Working with Multiple Object Files
----------------------------------

Code coverage instrumentation works on a per object file basis,
which means you have to re-compile your entire project to collect coverage data.

The C/C++ model has a concept of “compilation units”.
A large project is typically not compiled in one go,
but in separate steps.
The result of compiling a compilation unit is a ``.o`` object file
with the machine code.
The object code from multiple compilation units is later linked
into the final executable or library.
The previous example only had a single compilation unit,
so no explicit linking step was necessary.

Because each compilation unit is compiled independently,
every one has to be instrumented with coverage counters separately.
A common mistake is to add the compiler flags for coverage
(e.g. in the CFLAGS or CXXFLAGS variables)
but then forgetting to force a re-compile.
Depending on the build system,
it may be necessary to clear out the old object files
that weren't compiled with coverage,
e.g. with a  ``make clean`` command.
Other build systems use a separate build directory when compiling with coverage
so that incremental compilation works as expected.

Each object file will have an associated ``.gcno`` and ``.gcda`` file
in the same directory as the ``.o`` object file.
For example, consider the following compilation process:

.. code:: bash

   # (1) compile to object code
   g++ --coverage -c -o a.o a.cpp
   g++ --coverage -c -o b.o b.cpp

   # (2) link the object files in the program
   g++ --coverage -o the-program a.o b.o

   # (3) run the program
   ./the-program

1. Compiling the object code creates the ``a.o`` and ``b.o`` object files,
   but also corresponding ``a.gcno`` and ``b.gcno`` notes files,
   one for each compilation unit.
   The ``-c`` option is used to only compile but to not link the code.

2. Linking the object code produces the final program.
   This has no effect on coverage processing,
   except that the ``--coverage`` flag makes sure
   that a compiler-internal gcov support library is linked.

3. Running the program will increment the in-memory coverage counters
   for all executed lines.
   At the end, the counters are written into gcov data files,
   one for each compilation unit.
   Here, we would get ``a.gcda`` and ``b.gcda`` files.

If you only want coverage data for certain source files,
it is sufficient to only compile those compilation units with coverage enabled
that contain these source files.
But this can be tricky to do correctly.
For example, header files are often part of multiple compilation units.
