Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use gcov with Cmake

Tags:

c++

cmake

gcov

I'm having difficulties following this guide (that I've seen recommended on another post) on the matter https://github.com/bilke/cmake-modules/blob/master/CodeCoverage.cmake

First:

Copy this file into your cmake modules path.

How do I know what my cmake module path is?

Use the function SETUP_TARGET_FOR_COVERAGE to create a custom make target

What does it mean exactly? How do I do that? Especifically, what do I have to type and where?

I am forced to compile the application with cmake, otherwise I would do it with gcc.

like image 719
fedest Avatar asked Jun 22 '16 02:06

fedest


2 Answers

You set the cmake module path by calling set(CMAKE_MODULE_PATH <path>)

The cmake module path setting tells cmake where to look for cmake modules like those that are included by the include macro.

For example, the steps I took to use CodeCoverage.cmake are:

  1. Copy CodeCoverage.cmake into my source folder at 'scripts/cmake'.
  2. Add the following to my CMakeLists.txt:

    set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/scripts/cmake)
    
    if (CMAKE_BUILD_TYPE STREQUAL "Coverage")
        include(CodeCoverage)
        setup_target_for_coverage(${PROJECT_NAME}_coverage ${TEST_TARGET} coverage)
    
        SET(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
        SET(CMAKE_C_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
    endif() #CMAKE_BUILD_TYPE STREQUAL "Coverage"
    
  3. Run cmake with -DCMAKE_BUILD_TYPE=Coverage

  4. Run make

  5. Run make <coverage_target>

Note that:

  • ${TEST_TARGET} is a variable I set with the name of my unit testing target that I create earlier in the script.
  • <coverage_target> is whatever string that is generated by ${PROJECT_NAME}_coverage.
  • You don't have to wrap the coverage creation with the if like I did.
  • Since I'm using AppleClang, I had to fix the CodeCoverage.cmake script to allow it. The way it is written now allows gcc and clang 3.0.0 or newer only.
like image 126
galsh83 Avatar answered Oct 10 '22 01:10

galsh83


gcov with zero lines of CMake

As an alternative to using a CMake module for gcov integration, it is possible to use do it without modifying the build system at all. You only need about 5 lines of shell. This is a nice approach for projects that are not too large or complicated.

By the book, one must feed a list of source file names (excluding headers) to gcov. This is based on various naming and directory conventions: gcov assumes that the source files have a name like foo.c or foo.cpp and that the corresponding object file is called foo.o and is in the same directory as the source file. But CMake, by default, names them like foo.cpp.o. gcov strips the extension of the given source file name, and then adds the .gcno and .gcda suffixes. We can exploit these facts by feeding gcov, instead of source files, the .gcda files. As it turns out, gcov will look for everything in the right places in that case.

How-to

  1. Turn on coverage data in the compiler and linker flags by adding the --coverage flag to CMAKE_C_FLAGS and/or CMAKE_CXX_FLAGS. This makes the compiler generate .gcno files at build time, and it makes executables dump .gcda files on exit.

  2. Make a script for the [run test / generate report / clean coverage data] loop. Here's a barebones Bash example:

    # Ensure we are in the build directory and that coverage was enabled in the compiler
    grep -q -- --coverage CMakeCache.txt || exit 1
    
    # Clean up old runtime data
    find . -name '*.gcda' -exec rm {} \;
    
    # Run test command (specified as script arguments)
    # This can be anything that runs program(s) built by the project 
    "${@}"
    
    # Generate reports (.gcov files). All .gcda files in the build directory are passed as gcov args.
    find . -name '*.gcda' | xargs gcov
    

Pros of this approach

  • Same script can be reused, without having to perform CMake integration on each project of interest
  • No complicated CMake code
  • Flexibility to easily change the test command. A CMake-integrated clean/run/report loop likely has a hard-coded command to run all tests, which is often less useful (and slower) than running a single test.

Cons

  • Full path information is lost. The name of each .gcov file includes only the basename (foo.gcov), whereas normally it would encode the full path like src#foo#foo.gcov. This could result in name collisions in report files.
  • Lack of integration of dependency information into the build system means you may accidentally use old .gcno files upon forgetting to rebuild (if --coverage was turned on and later turned off).
like image 1
Sessile Computing Avatar answered Oct 10 '22 01:10

Sessile Computing