bilke / cmake-modules Goto Github PK
View Code? Open in Web Editor NEWAdditional CMake functionality. Most of the modules are from Ryan Pavlik (https://github.com/rpavlik/cmake-modules)
License: Boost Software License 1.0
Additional CMake functionality. Most of the modules are from Ryan Pavlik (https://github.com/rpavlik/cmake-modules)
License: Boost Software License 1.0
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
`
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!
Hi,
I want to monitor the code coverage of my Cmake-based project. Also, I was looking for files to monitor the built targets. Which files are suitable? Do I need to modify this file for my project?
Thanks
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.
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:
CodeCoverage.cmake
L717):
target_compile_options(${name} PRIVATE ${COVERAGE_COMPILER_FLAGS})
separate_arguments(_flag_list NATIVE_COMMAND "${COVERAGE_COMPILER_FLAGS}")
target_compile_options(${name} PRIVATE ${_flag_list})
-g
which resulted in:
error: unrecognized debug output level ' -fprofile-arcs -ftest-coverage'
gcov
. So I could solve this by replacing:
append_coverage_compiler_flags_to_target(${LIB_NAME})
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
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
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.
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)
I was trying to follow the usage instructions in CodeCoverage.cmake ; but when I loaded the module, I got a notice about the compiler not being GCC and "Aborting...". Yet, I was using GCC. This was on a Devuan GNU/Linux 3 with GCC 8.4.0 and CMake 3.13.
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.
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!!!
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
error: unknown argument: '-fprofile-abs-path' [clang-diagnostic-error]
$ 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?
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.
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
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?
cmake-modules/CodeCoverage.cmake
Line 194 in d6d1a77
You could check if GENERATOR_IS_MULTI_CONFIG e.g.
get_property(MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT MULTI_CONFIG)
...
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?
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?
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}
)
Hello,
I have a problem defining the BASE_DIRECTORY in CodeCoverage.cmake:
cmake-modules/CodeCoverage.cmake
Line 212 in 0503702
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!
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:
cmake-modules/CodeCoverage.cmake
Lines 123 to 125 in 3e03403
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.
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
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
)
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.
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:
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)
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()
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?
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.
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
codecov.io fails with gcc's gcov files and works fine with coverage.info from lcov. However on line 151all coverage info files are removed, which is unfortunate. See here:
https://github.com/bilke/cmake-modules/blob/master/CodeCoverage.cmake#L151
My request is to keep the essential info file and not remove it. That way codecov.io can point to this very useful cmake file and work pretty easy with default instructions.
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
Hi,
I am attempting to use the function for test coverage report generation on CentOS
I noticed that when I ran the Cobertura coverage reporting, it uses up 100% CPU, I had to kill it
Simply changing it to the non-Cobertura reporting, it ran fine and I get the directory with the index.html and associated files.
I am using gcovr from https://github.com/gcovr/gcovr, which is at version 3.1
Cheers
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.
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.
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>
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.
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
.
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++)
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.
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?
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.
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
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
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?
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.
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.
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 ๐ฅณ
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.