Giter Club home page Giter Club logo

cmake-modules's Introduction

Additional CMake Modules

Introduction

This is a collection of additional CMake modules. Most of them are from Ryan Pavlik (http://academic.cleardefinition.com).

How to Integrate

These modules are probably best placed wholesale into a "cmake" subdirectory of your project source.

If you use Git, try installing git-subtree, so you can easily use this repository for subtree merges, updating simply.

For the initial checkout:

cd projectdir

git subtree add --squash --prefix=cmake [email protected]:bilke/cmake-modules.git master

For updates:

cd projectdir

git subtree pull --squash --prefix=cmake [email protected]:bilke/cmake-modules.git master

For pushing to upstream:

cd projectdir

git subtree push --prefix=cmake [email protected]:bilke/cmake-modules.git master

How to Use

At the minimum, all you have to do is add a line like this near the top of your root CMakeLists.txt file (but not before your project() call):

list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")

Licenses

The modules that are written by Ryan Pavlik are all subject to this license:

Copyright Iowa State University 2009-2011

Distributed under the Boost Software License, Version 1.0.

(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

Modules based on those included with CMake as well as modules added by me (Lars Bilke) are under the OSI-approved BSD license, which is included in each of those modules. A few other modules are modified from other sources - when in doubt, look at the .cmake.

Important License Note!

If you find this file inside of another project, rather at the top-level directory, you're in a separate project that is making use of these modules. That separate project can (and probably does) have its own license specifics.

cmake-modules's People

Contributors

abak avatar aminiussi avatar apthorpe avatar bilke avatar chekov2k avatar displaylink-kstrzemp avatar emlai avatar endjunction avatar ferdnyc avatar franzbranntvino avatar fuchsto avatar globberwops avatar hamletg avatar horta avatar jeffk95 avatar joakimsoderberg avatar kinddragon avatar kurotych avatar mahal-tu avatar marcusmueller avatar mdadams avatar mrodalgaard avatar muellerseb avatar psalaberria002 avatar qgymib avatar robamu avatar snakethatlovesstaticlibs avatar tafryn avatar thelink2012 avatar truschival avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cmake-modules's Issues

Code comment for CodeCoverage.cmake is missleading

Hi,

For test coverage the parameter
"Param _testrunner The name of the target which runs the tests"
is misleading, it is not the target but a command with arguments, in which for cmake via make generator would be something like "make test".

Is there a reason for not being a cmake target and added as a dependency ?
flexibility ?

...
# Param _testrunner     The name of the target which runs the tests.
#						MUST return ZERO always, even on errors.
#						If not, no coverage report will be created!
...
FUNCTION(SETUP_TARGET_FOR_COVERAGE _targetname _testrunner _outputname)
...
	SEPARATE_ARGUMENTS(test_command UNIX_COMMAND "${_testrunner}")

	# Setup target
	ADD_CUSTOM_TARGET(${_targetname}

		# Cleanup lcov
		${LCOV_PATH} --directory . --zerocounters

		# Run tests
		COMMAND ${test_command} ${ARGV3}
...
	)

Thanks

Always Error ' make (e=5): Access is denied'

I have tried gcovr 3.2/4.8/5.1.
And I use this CMake to use gcovr in my project.
but when i execute 'make coverage' command. It always give below error back:
C:\Downloads\gcovr-3.2\gcovr -r C:/Test/src --object-dir= C:/Test/build -e test_*
process_begin: CreateProcess(NULL, C:\Downloads\gcovr-3.2\gcovr -r C:/Test/src --object-dir= C:/Test/build -e test_*, ...) failed.

### make (e=5): Access is denied.

Please help!!! As this problem really bother me for a long time!!!

Is there a way to specify environment variables when running LCOV_EXEC_TESTS_CMD?

In add_custom_target,

    add_custom_target(${Coverage_NAME}
        COMMAND ${LCOV_CLEAN_CMD}
        COMMAND ${LCOV_BASELINE_CMD} 
        COMMAND ${LCOV_EXEC_TESTS_CMD}
        COMMAND ${LCOV_CAPTURE_CMD}
        COMMAND ${LCOV_BASELINE_COUNT_CMD}
        COMMAND ${LCOV_FILTER_CMD} 
        COMMAND ${LCOV_GEN_HTML_CMD}

${LCOV_EXEC_TESTS_CMD} is resolved to the full path of the executable. However, when I changed the COMMAND to something like

COMMAND ${Coverage_ENV_VAR} ${LCOV_EXEC_TESTS_CMD}

Then ${LCOV_EXEC_TESTS_CMD} does not get resolved to the full path.

CodeCoverage: don't abort if gcov/lcov is not found

tldr: Allow the user to skip coverage target creation if gcov/lcov is not found.

Thank you for maintaining CodeCoverage.cmake, it has served me well over the last few years.

Now I'm facing an issue however: gcov is not found, and CodeCoverage.cmake aborts the whole CMake configuration process:

CMake Error at cmake-build-debug-visual-studio-clang/cmake-modules/CodeCoverage.cmake:83 (MESSAGE):
  gcov not found! Aborting...
Call Stack (most recent call first):
  CMakeLists.txt:129 (include)


-- Configuring incomplete, errors occurred!

This is the corresponding line:

if(NOT GCOV_PATH)
message(FATAL_ERROR "gcov not found! Aborting...")
endif() # NOT GCOV_PATH

My code looks like this:

include(CodeCoverage)
set(LCOV_REMOVE_EXTRA '*/v1/*')
if(LCOV_PATH)
    setup_target_for_coverage(coverage "cmake --build ${CMAKE_BINARY_DIR} --target check" coverage)
else()
    message(STATUS "lcov not found! Skipping 'coverage' target...")
endif()

As you can see, I want to skip the coverage target setup if lcov is not found. I don't think CMake allows recovering from FATAL_ERROR, so it would be nice if CodeCoverage.cmake supported this use case by allowing the user to handle the error instead of aborting.

Code coverage aggregation

Is there a way to aggregate the results of the coverage analysis? That is, it looks like CodeCoverage.cmake is a per-target (one per add_test()?) function. Say I have 10 subdirectories each with their own set of add_test() calls - how do I see the result as a coverage percentage for the whole project?

CodeCoverage, also check for gcc

i suggest changing line 86 from
elseif(NOT CMAKE_COMPILER_IS_GNUCXX)
to
elseif(NOT CMAKE_COMPILER_IS_GNUCXX AND NOT CMAKE_COMPILER_IS_GNUCC)

This enables using CodeCoverage.cmake in a gcc build environment (without a working g++)

CTest returns non-zero when any tests fail, causing coverage to not finish

As stated in the script:

# NOTE! This should always have a ZERO as exit code
# otherwise the coverage generation will not complete.

However, the recommended way of running coverage analysis on all files is to make an add_custom_target that runs ctest. If any tests fail, ctest returns non-zero which causes the coverage analysis to abort. It seems reasonable to still run coverage even if there are failing tests - is there any way to get around this?

CodeCoverage: gcovr does not find anything in out of tree builds

For some unknown reason a coverage of 0 was recorded, so I changed the gcovr invocation to include an --object-directory although according to gcovr manpage this should not be necessary.

        # Running gcovr
        COMMAND ${GCOVR_PATH} -x -r ${CMAKE_SOURCE_DIR} ${COBERTURA_EXCLUDES}
            -o ${Coverage_NAME}.xml --object-directory=${CMAKE_BINARY_DIR}

Now all .gc* files are found in my object directory.

CodeCoverage.cmake - difficulties using it to cover shared libraries rather than the main program

Using this version of CodeCoverage.cmake.

I wanted to use CodeCoverage.cmake to extract test coverage information in a context where I have a main test executable but want coverage for a shared library it links against.

The functions setup_target_for_coverage_gcovr_blah have an argument BASE_DIRECTORY but whether trying to use relative paths or absolute paths I just could not get it to work as expected. There is/was a bug such that only the main executable can end up in the code coverage report. Even with that fixed, base_directory appears to be relative the cmake build directory rather than the calling cmakelists.txt.

I've implemented something that works with BASE_DIRECTORY relative to the directory of the calling CMakeLists.txt file. The provisional changes are in this commit

I may submit a PR but I am not sure this is the intended behavior. Also it intersects with the pending pull request 51 related to issue #50 and will try to include these changes before a PR.

CodeCoverage.cmake: unknown argument: '-fprofile-abs-path'

Error

error: unknown argument: '-fprofile-abs-path' [clang-diagnostic-error]

Environment:

$ clang-11 --version
Debian clang version 11.0.1-2
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
$ g++ --version
g++ (GCC) 11.2.0
Copyright (C) 2021 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.
$ gcovr --version
gcovr 4.2
Copyright 2013-2018 the gcovr authors
Copyright 2013 Sandia Corporation
Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
the U.S. Government retains certain rights in this software.

CMake is configured by

/usr/bin/cmake --no-warn-unused-cli -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_C_COMPILER:FILEPATH=/usr/bin/c99-gcc -H/path/to/workspace -B/path/to/workspace/build/Debug -G "Unix Makefiles"

It seems that the flag profile-abs-path is available on gcc11, but why am I getting the error?

Support for INCLUDE arg as opposed to EXCLUDE ?

This is a tiny feature request :)
It would be real handy if there is support for an INCLUDE argument to setup_target_for_coverage_*. It becomes a bit annoying if I have a quite a bit of source files, but just want to see the coverage for a particular class.

Thank you.

CodeCoverage.cmake syntax seems to changed

I'm using cmake 3.5 (linux) and 3.7 (under CLion) with Catch. I wanted to use code coverage and stumble to your great integration, which I'll try to use to integrate in CLion.
When I used it with the description in beginning of the text I always had following error:

""" CMake Error at cmake-modules/CodeCoverage.cmake:179 (add_custom_command):
""" add_custom_command Wrong syntax. A TARGET or OUTPUT must be specified.

I read your CodeCoverage.cmake and had to learn how arguments are parsed ;-). I had to change my call in the CMakeLists.txt to:
setup_target_for_coverage(NAME ${PROJECT_TEST_NAME}_coverage
EXECUTABLE ${PROJECT_TEST_NAME}
DEPENDENCIES ${PROJECT_TEST_NAME})

Could you change the description in the beginning of the CodeCoverage.cmake.

Out of source cmake build : unable to find *.gcno files

Hi,

I am attempting to use the CodeCoverage.cmake macros for an out of source build of a C++ application using Boost unit_test_framework to drive the tests.

As I am running the test on OS X, I have to use clang (4.1) as gcc does not support gcov.

I am getting the following errors
[100%] Resetting code coverage counters to zero.
Processing code coverage counters and generating report.
/opt/lcov/v1.10/bin/lcov --directory . --zerocounters
Deleting all .da files in . and subdirectories
Done.
/Users/nicholas/temp/build_cpp/tests/unittest
Running 1 test case...

*** No errors detected
/opt/lcov/v1.10/bin/lcov --directory . --capture --output-file unittest_coverage_output.info
Capturing coverage data from .
Found gcov version: 4.2.1
Scanning . for .gcda files ...
Found 2 data files in .
Processing compute.dir/Compute.cpp.gcda
geninfo: ERROR: /Users/nicholas/temp/build_cpp/CMakeFiles/compute.dir/Compute.cpp.gcno: could not open file
make[3]: *** [tests/CMakeFiles/UnitTestCoverage] Error 2
make[2]: *** [tests/CMakeFiles/UnitTestCoverage.dir/all] Error 2
make[1]: *** [tests/CMakeFiles/UnitTestCoverage.dir/rule] Error 2
make: *** [UnitTestCoverage] Error 2

The following files location may shed some light

Tan-Meng-Yues-MacBook:build_cpp nicholas$ find . -name *.gcno
./src/CMakeFiles/compute.dir/Compute.cpp.gcno
./tests/CMakeFiles/unittest.dir/main.cpp.gcno
Tan-Meng-Yues-MacBook:build_cpp nicholas$ find . -name *.gcda
./CMakeFiles/compute.dir/Compute.cpp.gcda
./CMakeFiles/unittest.dir/main.cpp.gcda

Cheers

CodeCoverage: clang requires llvm-cov

When using gcov with a project built using Clang, gcov is unable to parse the .gcno files, giving the error: version '402*', prefer 'A92*'.

This seems to be because llvm-cov is required. I've hacked around this myself by doing the following before including CodeCoverage.cmake:

if("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang")
	find_program(LLVMCOV_PATH llvm-cov)
	if(LLVMCOV_PATH)
		set(GCOV_PATH "${CMAKE_CURRENT_SOURCE_DIR}/llvm-cov.sh")
	endif()
endif()
include(CodeCoverage.cmake)

where llvm-cov.sh is the following (marked with executable permissions):

#!/bin/bash
exec llvm-cov gcov "$@"

Could this be added in with a somewhat less hacky workaround?

No tests were found

Hi,
I'm trying to use CMakeCoverage.cmake together with Boost Unit test framework. I have several test modules and I'd like to aggregate the results, as described in #8.

So, I've written this code


include(CTest)
enable_testing()
include(CodeCoverage.cmake)
APPEND_COVERAGE_COMPILER_FLAGS()
set(COVERAGE_EXCLUDES 'external_dependencies/*')

add_subdirectory(${SRC_DIR} ${PROJECT_BINARY_DIR})

# Adding Unit-tests
add_test(NAME constant_neuron_test COMMAND constant_neuron_test)
add_test(NAME binary_neuron_test COMMAND binary_neuron_test)
add_test(NAME logistic_neuron_test COMMAND logistic_neuron_test)
add_test(NAME connectionFunctionGeneral_test COMMAND connectionFunctionGeneral_test)
add_test(NAME connection_Function_identity_test COMMAND connection_Function_identity_test)
add_test(NAME neural_network_test COMMAND neural_network_test)
add_test(NAME dataset_test COMMAND dataset_test)
add_test(NAME particle_swarm_test COMMAND particle_swarm_test)
add_test(NAME particle_test COMMAND particle_test)
add_test(NAME NeuralNetworkSum_test COMMAND NeuralNetworkSum_test)
add_test(NAME errorfunction_test COMMAND errorfunction_test)
add_test(NAME DESolver_test COMMAND DESolver_test)

SETUP_TARGET_FOR_COVERAGE_LCOV(
    NAME coverage
    EXECUTABLE ${CMAKE_CTEST_COMMAND})

The problem is, that something is wrong and I'm still getting the following error after running make coverage:

Test project /home/martin/4Neuro/build
No tests were found!!!
cd /home/martin/4Neuro/build && /usr/bin/lcov --gcov-tool /usr/bin/gcov --directory . --capture --output-file coverage.info
Capturing coverage data from .
Found gcov version: 7.3.0
Scanning . for .gcda files ...
geninfo: WARNING: no .gcda files found in . - skipping!
Finished .info-file creation
cd /home/martin/4Neuro/build && /usr/bin/lcov --gcov-tool /usr/bin/gcov -a coverage.base -a coverage.info --output-file coverage.total
Combining tracefiles.
Reading tracefile coverage.base
Reading tracefile coverage.info
lcov: ERROR: no valid records found in tracefile coverage.info
CMakeFiles/coverage.dir/build.make:60: recipe for target 'CMakeFiles/coverage' failed
make[3]: *** [CMakeFiles/coverage] Error 255
make[3]: Leaving directory '/home/martin/4Neuro'
CMakeFiles/Makefile2:70: recipe for target 'CMakeFiles/coverage.dir/all' failed
make[2]: *** [CMakeFiles/coverage.dir/all] Error 2
make[2]: Leaving directory '/home/martin/4Neuro'
CMakeFiles/Makefile2:77: recipe for target 'CMakeFiles/coverage.dir/rule' failed
make[1]: *** [CMakeFiles/coverage.dir/rule] Error 2
make[1]: Leaving directory '/home/martin/4Neuro'
Makefile:132: recipe for target 'coverage' failed
make: *** [coverage] Error 2

Do you know, what am I doing wrong?

If you'd like to see the whole project, its in [email protected]:bes0030/4Neuro.git , in the branch coverage.

Thank you very much,
Martin

if(${Coverage_BASE_DIRECTORY}) evaluates wrongly

Hello,

I have a problem defining the BASE_DIRECTORY in CodeCoverage.cmake:

if(${Coverage_BASE_DIRECTORY})

I think if(${Coverage_BASE_DIRECTORY}) evaluates wrongly, probably should be without the parenthesis.

Here I attache a small test:

project(Test)
cmake_minimum_required(VERSION 3.5)
function(f)
    set(options NO_DEMANGLE)
    set(oneValueArgs BASE_DIRECTORY NAME)
    set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES LCOV_ARGS GENHTML_ARGS)
    cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
    message("Coverage_BASE_DIRECTORY should be defined as ${Coverage_BASE_DIRECTORY}")
    if(${Coverage_BASE_DIRECTORY})
        message("but is defined as ${Coverage_BASE_DIRECTORY}")
    else()
        message("but is not defined")
    endif()
    if(Coverage_BASE_DIRECTORY)
        message("[with fix]: is defined as ${Coverage_BASE_DIRECTORY}")
    else()
        message("[with fix]: is not defined")
    endif()
endfunction()
f(BASE_DIRECTORY "TEST1")
f()

That on my machine (amd64, ubuntu 20.04, cmake 3.16) produces:

Coverage_BASE_DIRECTORY should be defined as TEST1
but is not defined
[with fix]: is defined as TEST1
Coverage_BASE_DIRECTORY should be defined as 
but is not defined
[with fix]: is not defined

I found this line because I'm using lcov, but probably same thing applies for gcov sections.

Cheers!

I am trying to use CodeCoverage and failing

CMakeLists.txt

I am having the following error...

make Unit_Tests_coverage
[ 90%] Built target Unit_Tests
[100%] Resetting code coverage counters to zero.
Processing code coverage counters and generating report.
Deleting all .da files in . and subdirectories
Done.
Not enough data for a trend yet.

Not enough data for a trend yet.

slope is 10
Improving weather on the way!

slope is 10
Improving weather on the way!

slope is 10
Improving weather on the way!

===============================================================================
All tests passed (2 assertions in 1 test case)

Capturing coverage data from .
Found gcov version: 6.3.1
Scanning . for .gcda files ...
geninfo: WARNING: no .gcda files found in . - skipping!
Finished .info-file creation
Reading tracefile /home/cfair/Tutorial/DesignPatterns/weatherStation/build/coverage.info
lcov: ERROR: no valid records found in tracefile /home/cfair/Tutorial/DesignPatterns/weatherStation/build/coverage.info
make[3]: *** [CMakeFiles/Unit_Tests_coverage.dir/build.make:62: CMakeFiles/Unit_Tests_coverage] Error 255
make[2]: *** [CMakeFiles/Makefile2:105: CMakeFiles/Unit_Tests_coverage.dir/all] Error 2
make[1]: *** [CMakeFiles/Makefile2:112: CMakeFiles/Unit_Tests_coverage.dir/rule] Error 2
make: *** [Makefile:142: Unit_Tests_coverage] Error 2

I can tell the gcda files are not being created....but they have SOMETIMES been created but mostly I get this error. Is this a bug? Or a screw up on my part? Have mercy on my poor CMakeTest file I am just now learning cmake.

lcov branches: no data found

Hi,

First, thanks so much for sharing this.

Running ubuntu 22.04.3 LTS with the following tools:
lcov: LCOV version 1.14
gcov (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
gcovr 5.0

I ran into an issue where my lcov report would show "branches: no data found".

I found some others who ran into the same issue and adding "--rc lcov_branch_coverage=1" to the targets LCOV_CAPTURE_CMD, LCOV_BASELINE_COUNT_CMD, LCOV_FILTER_CMD and LCOV_GEN_HTML_CMD fixed my issue.

Hope this can help,
Best regards,
JC

CodeCoverage.cmake does not show the comments of the cutom_command

Hi,

first of all thanks a lot for your work. It spares me a lot of time!

I'm using the CodeCoverage.cmake script and it works very well but the message associated with custom targets are not printed.
I'm working with CMake version 3.22.1.

I solved this by replacing the comment with:

      COMMAND ${CMAKE_COMMAND} -E echo "Lcov code coverage info report saved in ${Coverage_NAME}.info."

Do you want a PR for this?

CodeCoverage and Ninja

I am trying to use CodeCoverage.cmake with Ninja. On build I always get this error:
ninja: warning: phony target 'do_coverage' names itself as an input; ignoring [-w phonycycle=warn]
ninja: error: build.ninja:176: multiple rules generate do_coverage [-w dupbuild=err]

Here is the snip it I have from my cmake file

    # Code Coverage
    #
    if(ENABLE_COVERAGE)
        include(CodeCoverage)
        append_coverage_compiler_flags()

        setup_target_for_coverage_lcov(
            NAME do_coverage                          # New target name
            EXECUTABLE ctest                          # Executable in PROJECT_BINARY_DIR
            EXCLUDE ("/usr/include/*" "UnitTests/*")  # Ignore UnitTests and system libraries
        )

GCOVR HTML target cannot create directory if base directory is given as an argument

In line 541,

The directory path was defined over PROJECT_BINARY_DIR variable but it must be calculated over BASEDIR variable because all base directory paths are assigned to this variable eventually.

Wrong approach:

# Create folder
    set(GCOVR_HTML_FOLDER_CMD
        ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME}
    )

Correct approach:

# Create folder
    set(GCOVR_HTML_FOLDER_CMD
        ${CMAKE_COMMAND} -E make_directory ${BASEDIR}/${Coverage_NAME}
    )

Compiler is not GNU or Flang! Aborting...

I am getting the above error when trying to add coverage flags to my project. It seems to be related to checking the compilers for each of the available languages.

Relevant CMake code:

# Debug info to help with this issue
get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
message("ALL LANGUAGES: ${LANGUAGES}")
foreach(LANG ${LANGUAGES})
    message("${LANG} compiler is \"${CMAKE_${LANG}_COMPILER_ID}\"")
endforeach()

# Error hit by this line
include(CodeCoverage)

Relevant output of CMake:

ALL LANGUAGES: ASM;C;CXX;NONE
ASM compiler is ""
C compiler is "Clang"
CXX compiler is "Clang"
NONE compiler is ""
CMake Error at lib/cmake-modules/CodeCoverage.cmake:159 (message):
  Compiler is not GNU or Flang! Aborting...
Call Stack (most recent call first):
  CMakeLists.txt:132 (include)

Please let me know if there's any more information I can provide

Extract specified files for large projects

I've been using CodeCoverage.cmake and lcov for a while. I noticed that patterns to excluded were handled well, whereas patterns to extracted are not supported yet. I believe the lcov option --extract is useful when you are testing a large project with a lot of modules grouped by directories.

CodeCoverage is not running for my .c file under test, generating a coverage for test files.

Hi

I used the CodeCoverage.cmake, my project folder structure is something like this
src/
application1/
app1.c
app1.h
application2/
app2.c
app2.h
test/
application1/
app1_test.cpp
build/
cmakeList.txt

I used CodeCoverage module as it is and it works, but the problem is it generates the coverage for app1_test.cpp, not for the actual file under test which is app1.c

so i modified your CMake module and added the one more parameter which takes my c and replaced ${PROJECT_SOURCE_DIR} to my new parameter and that works for me. does this module is not intended for such type of folder structure?

Appending to wrong variable

In the definition of the function APPEND_COVERAGE_COMPILER_FLAGS, you append the COVERAGE_COMPILER_FLAGS twice to CMAKE_CXX_FLAGS where the first one should be on CMAKE_C_FLAGS.

function(APPEND_COVERAGE_COMPILER_FLAGS)
-    set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
    message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}")
endfunction() # APPEND_COVERAGE_COMPILER_FLAGS

Tutorial: CodeCoverage aggregation using ctest

Tutorial

This was written against commit 1fcf7f4 in June 2024. The latest at the time of writing.

I am putting this here as a tutorial only. In my example, I use doctest bootstrapped by ctest but you can use Catch2 or something else instead. ctest will still be required though.

My project contains multiple shared libraries with separate tests. I want to be able to run lcov over the entire project and aggregate the results rather than deal with separate reports.

Some attempts were made previously by people in #8 with ctest and catkin. I have adapted and summarised some of this below.

Structure

My general project structure is as follows:

project_root/
    |- my_first_lib/
    |   |- include/
    |   |   |- ...
    |   |- src/
    |   |   |- ...
    |   |- test/
    |   |   |- ...
    |   |- CMakeLists.txt
    |- my_second_lib/
    |   |- include/
    |   |   |- ...
    |   |- src/
    |   |   |- ...
    |   |- test/
    |   |   |- ...
    |   |- CMakeLists.txt
    |- test/
    |   |- CMakeLists.txt
    |   |- main.cpp
    |- CMakeLists.txt

Whether or not you separate your include/ or src/ folders is irrelevant. What is relevant, is that you have an overarching test/ folder in the project root and separate test/ folders for each of your libraries/executables.

Code

project_root/CMakeLists.txt:

cmake_minimum_required(VERSION 3.27)

project(my_project LANGUAGES C CXX)
# bla bla bla, regular project root setup

# important parts below
enable_testing()

add_subdirectory(my_first_lib)
add_subdirectory(my_second_lib)

add_subdirectory(test)

project_root/my_first_lib/CMakeLists.txt:

# just your regular library setup below
add_library(my_first_lib SHARED)

target_sources(
    my_first_lib PRIVATE
    # include all of your library source files as you normally would
    src/library.cpp
)

target_include_directories(
    my_first_lib PUBLIC
    "${CMAKE_CURRENT_SOURCE_DIR}/include"
)

target_include_directories(
    my_first_lib PRIVATE
    "${CMAKE_CURRENT_SOURCE_DIR}/src"
)

# important part for testing
add_executable(my_first_lib_test)

target_sources(
    my_first_lib_test PRIVATE
    # I use an identical main() file for all tests, you can customise as required
    "${CMAKE_SOURCE_DIR}/test/main.cpp"
    # now put each of the test sources below
    test/my_first_lib_test_foobar.cpp
    test/my_first_lib_test_simple.cpp
    test/my_first_lib_test_very_hard.cpp
)


target_link_libraries(
    my_first_lib_test PRIVATE
    # I use doctest for testing, you may use something else
    doctest::doctest
    # the test executable links to the library
    my_first_lib
)

target_include_directories(
    my_first_lib_test PRIVATE
    "${CMAKE_SOURCE_DIR}/test"
)

add_test(NAME my_first_lib_ctest COMMAND my_first_lib_test)

append_coverage_compiler_flags_to_target(my_first_lib)
append_coverage_compiler_flags_to_target(my_first_lib_test)

project_root/my_second_lib/CMakeLists.txt:

Exactly the same as project_root/my_first_lib/CMakeLists.txt except everything targets my_second_lib_xxx rather than my_first_lib_xxx.

project_root/test/CMakeLists.txt:

setup_target_for_coverage_lcov(
    NAME "my_coverage"
    EXECUTABLE "${CMAKE_CTEST_COMMAND}" "--verbose"
    DEPENDENCIES
    # place all add_test targets below
    "my_first_lib_test"
    "my_second_lib_test"
    # exclusions must contain "test" to avoid including the main.cpp file
    # (your mileage may vary if you write your main() functions differently)
    EXCLUDE "/usr/*" "*/_deps/*" "test"
)

project_root/test/main.cpp:

#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include <doctest/doctest.h>

Result

This results in a target my_coverage which will execute ctest which will execute all of your separate test executables.

I am using doctest and my tests will call into library code. In the same vein, you can adapt this to run an executable instead of a library by using a custom main() that calls all doctest test-cases if CMake is building in non-release mode.

Once lcov runs and generates the final report, all aggregated results will be listed from both libraries.

Further adaptation

If you don't use doctest or you don't care for a shared main() function, then you can simplify this by removing the project_root/test/ folder entirely and moving the setup_target_for_coverage_lcov call straight into project_root/CMakeLists.txt.

Is there any way to exclude STL headers from the code coverage?

After struggling with the code coverage module for a while, I have a problem with the output for the coverage. Right now, I get something like this:

screen shot 2018-04-15 at 9 56 47 pm

As you can see, the bottom three folders are not part of my code (They contain system includes). Is there any way to exclude them? (I tried doing --no-external, but then I get no coverage as this is an out-of-source build using CMake)

EXCLUDEs additional directories which starts with the same name

Hello,

# Folder structure
.
|-- src/
|-- test/
|-- testmodules/
|-- CMakeLists.txt
setup_target_for_coverage_gcovr_html(
        NAME ${PROJECT_NAME}_coverage_html
        EXECUTABLE ${PROJECT_NAME} --gtest_output=xml:report.xml
        BASE_DIRECTORY ${CMAKE_SOURCE_DIR}
        EXCLUDE "test/*")

In the above example, the testmodules also get excluded even if it was just the test folder that I wanted to exclude.

Any help is appreciated. Thank you.

geninfo: WARNING: no .gcno files found in . - skipping!

I was using a previous version of this code coverage and wanted to update to this one as I see it is better maintained. I am running into an issue though. When I try to make my_coverage_target I am getting:
Capturing coverage data from .
Found gcov version: 9.3.1
Using intermediate gcov format
Scanning . for .gcno files ...
geninfo: WARNING: no .gcno files found in . - skipping!
Finished .info-file creation

It seems there is no .gcno file being created when I am running this coverage. Does anyone have any ideas on a solution to this issue? Do I need to run this as a Debug to make it work?

Thanks!

setup_target_for_coverage_gcovr_html fails when running with clang

Using the CodeCoverage.cmake module works just fine when I am compiling my project with GCC, but it does not work when running with clang. Is gcovr gcc only, or is there also a way to compile it with clang?

The code I am using is:

# Generate code coverage
if (ENABLE_COVERAGE) 
    include(CodeCoverage)
    append_coverage_compiler_flags_to_target(application)
    setup_target_for_coverage_gcovr_html(
              NAME application_coverage
              EXECUTABLE application_unit_tests
              BASE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
              EXCLUDE ${PROJECT_BINARY_DIR}/* ${PROJECT_SOURCE_DIR}/libs/*)
endif()

The error I am getting is:

(ERROR) Trouble processing '/home/creapermann/Programming/Etovex/Librum/build-Debug/src/adapters/CMakeFiles/adapters.dir/controllers/user_controller.cpp.gcda' with working directory '/home/creapermann/Programming/Etovex/Librum/build-Debug/src/adapters/CMakeFiles/adapters.dir/controllers/.'.
Stdout of gcov was >>None<< End of stdout
Stderr of gcov was >>None<< End of stderr
Current processed gcov file was None.
Use option --verbose to get extended informations.
Traceback (most recent call last):
File "/usr/lib/python3.10/site-packages/gcovr/workers.py", line 80, in worker
work(*args, **kwargs)
File "/usr/lib/python3.10/site-packages/gcovr/gcov.py", line 323, in process_datafile
done = run_gcov_and_process_files(
File "/usr/lib/python3.10/site-packages/gcovr/gcov.py", line 536, in run_gcov_and_process_files
out, err = gcov_cmd.run_with_args(
File "/usr/lib/python3.10/site-packages/gcovr/gcov.py", line 519, in run_with_args
raise RuntimeError(f"GCOV returncode was {gcov_process.returncode}.")
RuntimeError: GCOV returncode was 3.
Traceback (most recent call last):
File "/usr/lib/python3.10/site-packages/gcovr/workers.py", line 80, in worker
work(*args, **kwargs)
File "/usr/lib/python3.10/site-packages/gcovr/gcov.py", line 323, in process_datafile
done = run_gcov_and_process_files(
File "/usr/lib/python3.10/site-packages/gcovr/gcov.py", line 536, in run_gcov_and_process_files
out, err = gcov_cmd.run_with_args(
File "/usr/lib/python3.10/site-packages/gcovr/gcov.py", line 519, in run_with_args
raise RuntimeError(f"GCOV returncode was {gcov_process.returncode}.")
RuntimeError: GCOV returncode was 3.
(ERROR) Uncaught EXCEPTION
Traceback (most recent call last):
File "/usr/bin/gcovr", line 33, in <module>
sys.exit(load_entry_point('gcovr==6.0', 'console_scripts', 'gcovr')())
File "/usr/lib/python3.10/site-packages/gcovr/__main__.py", line 328, in main
covdata = collect_coverage_from_gcov(options)
File "/usr/lib/python3.10/site-packages/gcovr/__main__.py", line 380, in collect_coverage_from_gcov
with Workers(
File "/usr/lib/python3.10/site-packages/gcovr/workers.py", line 173, in __exit__
self.wait()
File "/usr/lib/python3.10/site-packages/gcovr/workers.py", line 164, in wait
raise self.exceptions[0][1]
File "/usr/lib/python3.10/site-packages/gcovr/__main__.py", line 387, in collect_coverage_from_gcov
contexts = pool.wait()
File "/usr/lib/python3.10/site-packages/gcovr/workers.py", line 164, in wait
raise self.exceptions[0][1]
File "/usr/lib/python3.10/site-packages/gcovr/workers.py", line 80, in worker
work(*args, **kwargs)
File "/usr/lib/python3.10/site-packages/gcovr/gcov.py", line 323, in process_datafile
done = run_gcov_and_process_files(
File "/usr/lib/python3.10/site-packages/gcovr/gcov.py", line 536, in run_gcov_and_process_files
out, err = gcov_cmd.run_with_args(
File "/usr/lib/python3.10/site-packages/gcovr/gcov.py", line 519, in run_with_args
raise RuntimeError(f"GCOV returncode was {gcov_process.returncode}.")
RuntimeError: GCOV returncode was 3.
make[3]: *** [src/adapters/CMakeFiles/coverage.dir/build.make:73: src/adapters/CMakeFiles/coverage] Error 1
make[2]: *** [CMakeFiles/Makefile2:2437: src/adapters/CMakeFiles/coverage.dir/all] Error 2
make[1]: *** [CMakeFiles/Makefile2:2444: src/adapters/CMakeFiles/coverage.dir/rule] Error 2
make: *** [Makefile:1053: coverage] Error 2

More flexible way to specify excludes when using 'setup_target_for_coverage_lcov'

Hello,

thank you for providing great cmake modules!

I had the problem when using setup_target_for_coverage_lcov such that the excludes where always based on the base path. I was getting coverage results from v1 c++ libs as well. I modified the function a little, that it could just forward the excludes as is to the lcov tool, since the tool already is capable to handle pattern based excludes.

set(LCOV_EXCLUDES "")
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_LCOV_EXCLUDES})
list(APPEND LCOV_EXCLUDES "${EXCLUDE}")
endforeach()
list(REMOVE_DUPLICATES LCOV_EXCLUDES)

I just removed the part where the path gets calculated.

For me that way the problem is solved. Maybe you have a better idea how to do it. I wanted to just mention the issue.

Thank you and best regards.
Alessandro

Issue with append_coverage_compiler_flags_to_target (but with solution)

Hi there and thanks for this amazing repo!

I was trying to cleanup my coverage workflow and tried to replace append_coverage_compiler_flags with append_coverage_compiler_flags_to_target.

Two problems came across:

  1. I needed to replace (CodeCoverage.cmake L717):
     target_compile_options(${name} PRIVATE ${COVERAGE_COMPILER_FLAGS})
    with:
     separate_arguments(_flag_list NATIVE_COMMAND "${COVERAGE_COMPILER_FLAGS}")
     target_compile_options(${name} PRIVATE ${_flag_list})
    Since the white spaces were not recognized to split the flags everything was append to -g which resulted in:
     error: unrecognized debug output level ' -fprofile-arcs -ftest-coverage'
  2. Doing the above, I got another error, because the lib was not linked against gcov. So I could solve this by replacing:
    append_coverage_compiler_flags_to_target(${LIB_NAME})
    with:
    target_compile_options(${LIB_NAME} PRIVATE -g --coverage)
    target_link_libraries(${LIB_NAME} PRIVATE gcov)

Note, that --coverage is equivalent to -fprofile-arcs -ftest-coverage (when compiling) and -lgcov (when linking). link

Maybe it could be a good idea to replace:

function(append_coverage_compiler_flags_to_target name)
    target_compile_options(${name}
        PRIVATE ${COVERAGE_COMPILER_FLAGS})
endfunction()

with

function(append_coverage_compiler_flags_to_target name)
    separate_arguments(_flag_list NATIVE_COMMAND "${COVERAGE_COMPILER_FLAGS}")
    target_compile_options(${name} PRIVATE ${_flag_list})
    target_link_libraries(${name} PRIVATE gcov)
endfunction()

And maybe we could also replace -fprofile-arcs -ftest-coverage with --coverage.

Cheers,
Sebastian

Add support for sonar?

I manually modified CodeCoverage.cmake to include:

`function(setup_target_for_coverage_gcovr_sonar)

set(options NONE)
set(oneValueArgs BASE_DIRECTORY NAME)
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

if(NOT GCOVR_PATH)
    message(FATAL_ERROR "gcovr not found! Aborting...")
endif() # NOT GCOVR_PATH

# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
if(DEFINED Coverage_BASE_DIRECTORY)
    get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
else()
    set(BASEDIR ${PROJECT_SOURCE_DIR})
endif()

# Collect excludes (CMake 3.4+: Also compute absolute paths)
set(GCOVR_EXCLUDES "")
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES})
    if(CMAKE_VERSION VERSION_GREATER 3.4)
        get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
    endif()
    list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
endforeach()
list(REMOVE_DUPLICATES GCOVR_EXCLUDES)

# Combine excludes to several -e arguments
set(GCOVR_EXCLUDE_ARGS "")
foreach(EXCLUDE ${GCOVR_EXCLUDES})
    list(APPEND GCOVR_EXCLUDE_ARGS "-e")
    list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}")
endforeach()

# Set up commands which will be run to generate coverage data
# Run tests
set(GCOVR_XML_EXEC_TESTS_CMD
    ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
)
# Running gcovr
set(GCOVR_XML_CMD
    ${GCOVR_PATH} -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS} ${GCOVR_EXCLUDE_ARGS} 
    --object-directory=${PROJECT_BINARY_DIR} --sonar ${Coverage_NAME}.xml
)

if(CODE_COVERAGE_VERBOSE)
    message(STATUS "Executed command report")

    message(STATUS "Command to run tests: ")
    string(REPLACE ";" " " GCOVR_XML_EXEC_TESTS_CMD_SPACED "${GCOVR_XML_EXEC_TESTS_CMD}")
    message(STATUS "${GCOVR_XML_EXEC_TESTS_CMD_SPACED}")

    message(STATUS "Command to generate gcovr XML coverage data: ")
    string(REPLACE ";" " " GCOVR_XML_CMD_SPACED "${GCOVR_XML_CMD}")
    message(STATUS "${GCOVR_XML_CMD_SPACED}")
endif()

add_custom_target(${Coverage_NAME}
    COMMAND ${GCOVR_XML_EXEC_TESTS_CMD}
    COMMAND ${GCOVR_XML_CMD}
    
    BYPRODUCTS ${Coverage_NAME}.xml
    WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
    DEPENDS ${Coverage_DEPENDENCIES}
    VERBATIM # Protect arguments to commands
    COMMENT "Running gcovr to produce Sonar code coverage report."
)

# Show info where to find the report
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
    COMMAND ;
    COMMENT "Sonar code coverage report saved in ${Coverage_NAME}.xml."
)

endfunction() # setup_target_for_coverage_sonar_xml
`

CodeCoverage: exclude stdlib / boost headers from coverage report?

It seems to me like there is currently no practical way to exclude e.g. all boost headers from the final coverage report, COVERAGE_EXCLUDES can only exclude files, not whole directories. This really clutters up the coverage report, making it essentially useless. Is there a workaround for this?

EDIT: one method that works but kind of seems like a hack is the following:

file(GLOB_RECURSE excludes "/usr/include/c++/*")                               
set(COVERAGE_EXCLUDES "${excludes}")   

I'm not sure how to do this in a platform-independant way though.

CodeCoverage: causes a cmake warning when used with googletest.

My project builds fine but when I include CodeCoverage.cmake I get warnings issued from googletest.

set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
include(CodeCoverage)

Causes the warning to be issued:

CMake Warning (dev) in third_party/googletest/googletest/CMakeLists.txt:
  Policy CMP0022 is not set: INTERFACE_LINK_LIBRARIES defines the link
  interface.  Run "cmake --help-policy CMP0022" for policy details.  Use the
  cmake_policy command to set the policy and suppress this warning.

  Target "gtest" has an INTERFACE_LINK_LIBRARIES property which differs from
  its LINK_INTERFACE_LIBRARIES properties.

  INTERFACE_LINK_LIBRARIES:

    gcov;Threads::Threads

  LINK_INTERFACE_LIBRARIES:

    Threads::Threads

Any idea how to resolve this without setting a CMake policy? Thanks.

Better use CMAKE_COMPILER_IS_GNU than CMAKE_COMPILER_IS_GNUCXX

When compiling a C project, one may use gcc which is a GNU compiler but not a GNUCXX compiler. Therefore, the test below which is using the variable CMAKE_COMPILER_IS_GNUCXX should be turned into CMAKE_COMPILER_IS_GNU.

-  if(CMAKE_COMPILER_IS_GNUCXX)
+  if(CMAKE_COMPILER_IS_GNU)
       link_libraries(gcov)
  else()
      set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
  endif()

CodeCoverage with Xcode (Clang): Undefined symbols for architecture x86_64

During the linking phase of my GitHub action, I encounter the following errors while using Xcode 14.2 (Clang) (not on Linux/Ubuntu):

[100%] Linking CXX executable [NAME]
Undefined symbols for architecture x86_[64]
  "_llvm_gcda_emit_arcs", referenced from:
      ___llvm_gcov_writeout in [FILE.o]
      ...
  "_llvm_gcda_emit_function", referenced from:
      ___llvm_gcov_writeout in test.[FILE.o]
      ...
  "_llvm_gcda_end_file", referenced from:
      ___llvm_gcov_writeout in in test.[FILE.o]
      ...
  "_llvm_gcda_start_file", referenced from:
      ___llvm_gcov_writeout in in test.[FILE.o]
      ...
  "_llvm_gcda_summary_info", referenced from:
      ___llvm_gcov_writeout in in test.[FILE.o]
      ...
  "_llvm_gcov_init", referenced from:
      ___llvm_gcov_init in in test.[FILE.o]
      ...
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

It looks like that something is missing during the linking phase (maybe a flag ?).
Any thoughts?
Thanks ๐Ÿฅณ

CodeCoverage: Could not find a package configuration file provided by "Python"

Last commit 9d5f5fa looks like regress for ubuntu 16.04 CMake 3.10.0 ( tested in docker )
I got this warning. Maybe you are know how fix it?
After revert last commit. No have warning

CMake Warning at cmake-modules/CodeCoverage.cmake:78 (find_package):
  By not providing "FindPython.cmake" in CMAKE_MODULE_PATH this project has
  asked CMake to find a package configuration file provided by "Python", but
  CMake did not find one.

  Could not find a package configuration file provided by "Python" with any
  of the following names:

    PythonConfig.cmake
    python-config.cmake

  Add the installation prefix of "Python" to CMAKE_PREFIX_PATH or set
  "Python_DIR" to a directory containing one of the above files.  If "Python"
  provides a separate development package or SDK, be sure it has been
  installed.
Call Stack (most recent call first):
  tests/CMakeLists.txt:12 (include)

Command Line Arguments

Hello.

When I called "make someCoverageTarget 127.0.0.1 1918", the command line parameters could not be passed to the application.
Even if i use the variable $ {EXECUTABLE_ARGS}, the effect is the same.
What could I do?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.