Unable to link classes in GTest with CMake - c++

I am trying to incorporate GTests in my project using CMake. I followed this instruction and I get following error:
Undefined symbols for architecture x86_64:
"SomeClass::someMethod()", referenced from:
someMethod_TrivialTest_Test::TestBody() in SomeClassTest.cpp.o
ld: symbol(s) not found for architecture x86_64
Here is my CMake file:
cmake_minimum_required(VERSION 3.11)
project (someProject)
set(CMAKE_CXX_STANDARD 17)
#Include headers
include_directories("../include")
#Add source files
file(GLOB SOURCES "src/*.cpp")
add_executable(someProject ${SOURCES})
################################
# GTest
################################
# Download and unpack googletest at configure time
configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download )
if(result)
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
endif()
execute_process(COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download )
if(result)
message(FATAL_ERROR "Build step for googletest failed: ${result}")
endif()
# Prevent overriding the parent project's compiler/linker
# settings on Windows
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
# Add googletest directly to our build. This defines
# the gtest and gtest_main targets.
add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src
${CMAKE_BINARY_DIR}/googletest-build
EXCLUDE_FROM_ALL)
# The gtest/gtest_main targets carry header search path
# dependencies automatically when using CMake 2.8.11 or
# later. Otherwise we have to add them here ourselves.
if (CMAKE_VERSION VERSION_LESS 2.8.11)
include_directories("${gtest_SOURCE_DIR}/include")
endif()
# Add test cpp file
add_executable( someTests ./test/SomeClassTest.cpp)
# Link test executable against gtest & gtest_main
target_link_libraries(someTests gtest gtest_main)
add_test( someTests someTests )
My project structure (CMakeLists.txt.in is used to download the GTest library, added from the instruction mentioned above):
.
├── CMakeLists.txt
├── CMakeLists.txt.in
├── include
│ └──SomeClass.hpp
├── src
│ ├── Main.cpp
│ └── SomeClass.cpp
└── tests
└── SomeClassTest.cpp
If I manually create and link objects, it works.
g++ -c ./src/SomeClass.cpp
g++ -c ./test/SomeClassTest.cpp
g++ SomeClassTest.o SomeClass.o ./build/googletest-build/googlemock/gtest/CMakeFiles/gtest.dir/src/gtest-all.cc.o -o myTests
The object of the test class seems to be there:
./build/CMakeFiles/someTests.dir/test/SomeClassTest.cpp.o
But the directory for the someProject object is empty:
./build/CMakeFiles/someProject.dir/src/
So I am missing something in the CMake file and it is not linking properly. All the answers I could find so far were related to specifying target_link_libraries but I am not sure if that is the problem here. I am new to CMake and linking issues. Would reeeally appreciate any advice!

All the answers I could find so far were related to specifying target_link_libraries but I am not sure if that is the problem here.
You were right on track with this assumption.
Currently, you're telling CMake that there is an executable to be built from some sources and a test to be built from some other sources and linked with gtest. CMake doesn't know that the executable and your test are in any way related, though!
I see two possible solutions:
add the sources of the executable (except the one with the main function) as sources to the test.
build all of the sources from the executable (except the one with the main function) as library and link both the executable and the test to that library.
I prefer the later one, which would - roughly - look like:
add_library(someProgram_lib ${SOURCES})
add_executable(someProgram src/main.cc)
target_link_libraries(someProgram someProgram_lib)
add_executable(someTests ./test/SomeClassTest.cpp)
target_link_libraries(someTests gtest gtest_main someProgram_lib)

Related

Why CTest can't find tests with googletest ? Also, can I run a single test function by mouse click in visual studio code like in visual studio? [duplicate]

I have a project with a structure
├── CMakeLists.txt
├── mzl.c
├── mzl.h
└── tests
├── CMakeLists.txt
├── mzl-communication-test.c
├── mzl-setup-test.c
├── mzl-test-errors.c
└── mzl-test-errors.h
Where the top directory CMakeLists.txt file is
project(mzl)
cmake_minimum_required(VERSION 2.8)
add_subdirectory(tests)
# Enable testing for the project
enable_testing()
# Find zmq
find_library(ZMQ_LIB zmq REQUIRED)
message(STATUS "ZMQ Library: ${ZMQ_LIB}")
# Find threading library
set(CMAKE_THREAD_PREFER_PTHREAD ON)
find_package(Threads REQUIRED)
message(STATUS "Threading Library: ${CMAKE_THREAD_LIBS_INIT}")
# Set include directories for headers
set (
MZL_INCLUDE_DIRS
${CMAKE_SOURCE_DIR}
CACHE STRING "MZL Include Directories"
)
include_directories(${MZL_INCLUDE_DIRS})
# Set source files
set (
MZL_SRC_FILES
mzl.c
)
# Add library
add_library(${PROJECT_NAME} STATIC ${MZL_SRC_FILES})
# Link to zmq
target_link_libraries(${PROJECT_NAME} ${ZMQ_LIB} ${CMAKE_THREAD_LIBS_INIT})
and tests/CMakeLists.txt is
# Use MZL Source Directories (mzl headers are in top directory)
include_directories(${CMAKE_SOURCE_DIR})
# Variable from here is empty
message(STATUS "MZL Include Directories: ${MZL_INCLUDE_DIRS}")
# Files common to all tests
set ( TEST_COMMON_SOURCES
mzl-test-errors.c
)
# Library setup/shutdown testing
set(SETUP_TEST_NAME mzl-setup-test)
add_executable(${SETUP_TEST_NAME} ${TEST_COMMON_SOURCES} ${SETUP_TEST_NAME}.c)
target_link_libraries(${SETUP_TEST_NAME} ${PROJECT_NAME} ${ZMQ_LIB})
add_test(${SETUP_TEST_NAME} ${SETUP_TEST_NAME})
# Communcations test
set(COMMUNICATION_TEST_NAME mzl-communication-test)
add_executable(${COMMUNICATION_TEST_NAME} ${TEST_COMMON_SOURCES}
${COMMUNICATION_TEST_NAME}.c)
target_link_libraries(${COMMUNICATION_TEST_NAME} ${PROJECT_NAME}
${CMAKE_THREAD_LIBS_INIT} ${ZMQ_LIB})
add_test(${COMMUNICATION_TEST_NAME} ${COMMUNICATION_TEST_NAME})
Everything worked fine before I added the second test mzl-communication-test. After adding it and the lines in the tests/CMakeLists.txt after # Communications test, running ctest did nothing extra -- it still only ran the first test.
After deleting the build directory and running cmake again, I get no errors for the initial CMake run, but running make runs CMake again, resulting in an error with CMake:
CMake Error: Parse error in cache file build/CMakeCache.txt. Offending entry: include
followed by a Make error:
Makefile:203: recipe for target 'cmake_check_build_system' failed
make: *** [cmake_check_build_system] Error 1
Running make again results in everything being built, including the tests; however, running ctest results in
Test project build
No tests were found!!!
The issue seems to be with something that I am doing with CMake, but can't figure out what to do from here as I can't see anything that I'm doing differently than when it was originally working. Even my last commit to git, which was working when I committed it, is no longer working.
You need to move the enable_testing() call to be before you do add_subdirectory(tests)
# Enable testing for the project
enable_testing()
add_subdirectory(tests)

Error running google test on default in CLion

So, unfortunatly I am unsure how to properly describe the error message.
Essentially I am trying to get used to google test, - I want to use it to test my C++ project in CLion. I create a new library project, with the following classes:
#include "gtest/gtest.h"
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
and also:
#include "gtest/gtest.h"
TEST(MyTestCategory, Vec2DAdditionTest){
EXPECT_EQ(1, 1);
}
Of course these tests are not useful at all - but its just to see if everything works the way it should.
Now when I tried to run them, I am prompted the following error:
6:46 PM Error running 'MyTestCategory.Vec2DAdditionTest': Cannot run 'MyTestCategory.Vec2DAdditionTest' on '<default>'
6:47 PM Error running 'All in main.cpp': Cannot run 'All in main.cpp' on '<default>'
What am I missing? I can't get the tests to run, - neither individually, nor directly over the main function?
Also after this, the build/run button gets greyed out in CLion and I have to right click on the main.cpp to force it to run/compile..
Essential I have a project structure like so:
src/
a.cpp
b.cpp
CMakeLists.txt
test/
main.cpp
atests.cpp
CmakeLists.txt
CMakeLists.txt
My run configuration for the test project looks like so:
Here is an example on how you can add GTests in your CLion project:
Consider a project structure very similar to what you have presented, however, with an additional file CMakeLists.txt.in in the test folder.:
src/
a.cpp
b.cpp
CMakeLists.txt
test/
main.cpp
atests.cpp
CMakeLists.txt
CMakeLists.txt.in
CMakeLists.txt
The CMakeLists.txt.in helps to download and add the GTest libraries to your project while building your project.
The content of CMakeLists.txt.in looks as below:
cmake_minimum_required(VERSION 2.8.2)
project(googletest-download NONE)
include(ExternalProject)
ExternalProject_Add(googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG master
SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src"
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
)
The test/CMakeLists.txt file looks as below:
cmake_minimum_required(VERSION 3.10)
### START OF CONFIGURING GTEST
configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download )
execute_process(COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download )
# Add googletest directly to our build. This defines
# the gtest and gtest_main targets.
add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src
${CMAKE_CURRENT_BINARY_DIR}/googletest-build
EXCLUDE_FROM_ALL)
### END OF CONFIGURING GTEST
# Now simply link against gtest or gtest_main as needed. Eg
add_executable(test_${PROJECT_NAME} main.cpp atest.cpp)
target_link_libraries(test_${PROJECT_NAME} ${PROJECT_NAME} gtest gtest_main)
add_test(NAME test_PROJECT_NAME COMMAND test_${PROJECT_NAME})
CMakeLists.txt in the root folder has the following content:
cmake_minimum_required(VERSION 3.10)
project(gtestTest)
set(CMAKE_CXX_STANDARD 14)
add_subdirectory(src)
add_subdirectory(test)
Now reload the CMake configuration and try running the test_gtestTest target to run the unit tests.
You can also create custom run configurations using gtest template of CLion to get user friendly test reports.
For more information on GTests with CLion, please refer to:
Google Test Support in Clion
Building Google Tests with CMake

add_custom_target not executing with multiple executable in a CMakeLists file

I got a situation where another Makefile is executed from a CMakeLists.txt file.
Here is my root directory structure.
.
├── client.cpp
├── CMakeLists.txt
├── proto_lib
│   ├── Makefile
│   └── math.proto
└── server.cpp
This is a simple grpc test code where I am trying to compile a proto files using a Makefile create a static library. And then link that library to the final targets in the CMakefile. Makefile is working fine. CMakefile is also working fine with one executable.
Here is the CMakefile:
cmake_minimum_required(VERSION 3.5)
project(client-server)
message(STATUS "Compiling Network Function : ${PROJECT_NAME}")
set(CMAKE_CXX_STANDARD 11)
message(STATUS "Project Directory: ${PROJECT_SOURCE_DIR}")
set(CMAKE_BINARY_DIR ${CMAKE_SOURCE_DIR}/build)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)
set(LIB_FILE ${CMAKE_CURRENT_SOURCE_DIR}/proto_lib/libmylib.a)
add_custom_target(libmylib.a ALL
COMMAND make
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/proto_lib
COMMENT "grpc headers and libraries are generating..."
)
add_executable(server server.cpp)
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -g")
set(BASIC_LIBRARIES "-lpthread")
set(CMAKE_LINK_WHAT_YOU_USE ON)
set(LIBDIR "/usr/local/lib")
find_library(proto_location NAMES protobuf PATHS ${LIBDIR})
find_library(grpc_location NAMES grpc++ PATHS ${LIBDIR})
find_library(grpc_reflection_location NAMES grpc++_reflection PATHS ${LIBDIR})
find_library(dl_location NAMES dl PATHS ${LIBDIR})
find_library(grpc_location2 NAMES grpc PATHS ${LIBDIR})
if(proto_location)
message(STATUS "protobuf library found at " ${proto_location})
endif()
if(grpc_location)
message(STATUS "grpc++ found at " ${grpc_location})
endif()
if(grpc_reflection_location)
message(STATUS "grpc_reflection found at " ${grpc_reflection_location})
endif()
if(dl_location)
message(STATUS "dl found at " ${dl_location})
endif()
if(grpc_location2)
message(STATUS "grpc found at " ${grpc_location2})
endif()
target_link_libraries(server ${proto_location}
${LIB_FILE}
${grpc_location}
${grpc_reflection_location}
${dl_location}
${grpc_location2}
${BASIC_LIBRARIES}
)
When I enter the command make after CMake . in the root directory.
it starts with following output...
Scanning dependencies of target libmylib.a
[ 33%] grpc headers and libraries are generating...
[ 33%] Built target libmylib.a
etc.. etc..
and it succeeds.(The internal Makefile creates header files and static objects using proto and grpc libraries. After that server.cpp can include the headers from inside the proto_lib/ folder and CMake build succeeds)
But when I add one more executable at the end of CMakeLists.txt,
add_executable(client client.cpp)
target_link_libraries(client ${proto_location}
${LIB_FILE}
${grpc_location}
${grpc_reflection_location}
${dl_location}
${grpc_location2}
${BASIC_LIBRARIES}
)
and then cmake . && make
does not start with internal Makefile build. Instead, it starts with client build.
Scanning dependencies of target client
[ 20%] Building CXX object CMakeFiles/client.dir/client.cpp.o
/home/deka/Academic/gemini/learning/client_server_async/advanced1/client.cpp:10:10: fatal error: proto_lib/math.grpc.pb.h: No such file or directory
#include "proto_lib/math.grpc.pb.h"
Because proto_lib/Makefile is not executed first in this case therefore math.grpc.pb.h is not generated and that is what the above error is showing.
My question is: Why adding one more executable does not trigger the internal Makefile build at the start?
Thanks!

Why would google tests compile but not be able to see my project sources?

Why would google tests compile but not be able to see my project sources?
Here's the error that I'm getting:
$ cmake . && make && make test
-- Configuring done
-- Generating done
-- Build files have been written to: mars_rover
Scanning dependencies of target mars_rover
[ 8%] Building CXX object CMakeFiles/mars_rover.dir/src/rover.cpp.o
Linking CXX executable build/bin/mars_rover
[ 33%] Built target mars_rover
[ 41%] Built target gtest
[ 50%] Built target gtest_main
Scanning dependencies of target mars_rover_TEST
[ 58%] Building CXX object CMakeFiles/mars_rover_TEST.dir/test/test_mars_rover.cpp.o
mars_rover/test/test_mars_rover.cpp:2:10: fatal error: 'src/directions.h' file not found
#include "src/directions.h"
^
1 error generated.
make[2]: *** [CMakeFiles/mars_rover_TEST.dir/test/test_mars_rover.cpp.o] Error 1
make[1]: *** [CMakeFiles/mars_rover_TEST.dir/all] Error 2
make: *** [all] Error 2
Here's how I've got my project laid out:
$ tree {src,test,lib} -L 1
src
├── directions.cpp
├── directions.h
├── main.cpp
├── plateau.cpp
├── plateau.h
├── point.h
├── rover.cpp
└── rover.h
test
├── input1
├── output1
├── test_main.cpp
└── test_mars_rover.cpp
lib
├── CMakeLists.txt
└── gtest-1.7.0
And here's my CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
# Options. Turn on with 'cmake -Dtest=ON'.
option(test "Build all tests." ON)
set(PROJECT_NAME mars_rover CXX)
project(${PROJECT_NAME})
set(CMAKE_CXX_FLAGS "-g -Wall -Werror")
file(GLOB_RECURSE PROJECT_SOURCES ${CMAKE_SOURCE_DIR}/src/*.cpp)
add_executable(${PROJECT_NAME} ${PROJECT_SOURCES})
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/build/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/build/lib)
if (test)
add_subdirectory(lib/gtest-1.7.0)
enable_testing()
include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
# finding test sources
file(GLOB_RECURSE TEST_SOURCES ${CMAKE_SOURCE_DIR}/test/*.cpp ${CMAKE_SOURCE_DIR}/src/*.cpp)
add_executable(${PROJECT_NAME}_TEST ${TEST_SOURCES})
# link to gtest
target_link_libraries(${PROJECT_NAME}_TEST gtest gtest_main)
add_test(CardinalDirectionTests ${EXECUTABLE_OUTPUT_PATH}/${PROJECT_NAME}_TEST --gtest_filter=MarsRoverTest.CardinalDirectionTests)
add_test(RelativeDirectionTests ${EXECUTABLE_OUTPUT_PATH}/${PROJECT_NAME}_TEST --gtest_filter=MarsRoverTest.RelativeDirectionTests)
endif()
Your test executable can't find 'src/directions.h' since its parent (${CMAKE_SOURCE_DIR}) hasn't been added to the include_directories call. Just adding it should work.
However, I can see a few other minor points in your setup. Running through your CMakeLists.txt, here are the changes I'd make:
cmake_minimum_required(VERSION 2.8.12)
If you can specify 2.8.12 as the minimum, you have access to the more useful target_include_directories command. Where include_directories is a bit of a blunderbuss approach, target_include_directories allows you to specify search paths just for that specific target. If you specify these as PUBLIC or INTERFACE, then subsequent targets which link to this one will automatically inherit these search paths too.
In a similar vein, you could look at using target_compile_definitions and target_compile_options.
set(PROJECT_NAME mars_rover CXX)
project(${PROJECT_NAME})
project(mars_rover)
The project command sets the variable PROJECT_NAME, so your set command has little use here. And CMake will detect that this is a C++ project by virtue of the source file suffixes.
By including all your sources in two separate targets (the main exe and the test exe), these will all be compiled twice. To avoid this inefficiency, I'd make a library of all your sources in "/src" except "main.cpp" and then have an exe which only has main.cpp and links to this library.
Also, using file(GLOB ...) or file(GLOB_RECURSE ...) is discouraged as a means of gathering source lists.
set(CMAKE_CXX_FLAGS "-g -Wall -Werror")
file(GLOB_RECURSE PROJECT_SOURCES ${CMAKE_SOURCE_DIR}/src/*.cpp)
add_executable(${PROJECT_NAME} ${PROJECT_SOURCES})
# No need to include .h files, but they show up in IDEs like Xcode if you do.
set(libSources
src/directions.cpp src/directions.h
src/plateau.cpp src/plateau.h
src/point.h
src/rover.cpp src/rover.h
)
add_library(${PROJECT_NAME}_LIB ${libSources})
# Anything linking to this will automatically have ${PROJECT_SOURCE_DIR}
# added to the compiler's search paths since it is PUBLIC. Prefer
# ${PROJECT_SOURCE_DIR} to ${CMAKE_SOURCE_DIR} in case this project is not
# the top-level one.
target_include_directories(${PROJECT_NAME}_LIB PUBLIC ${PROJECT_SOURCE_DIR})
# Use generator expressions to conditionally apply the flags to Unix and Debug
# builds. Anything linking to this will automatically have these flags also
# applied since they are PUBLIC.
target_compile_options(${PROJECT_NAME}_LIB PUBLIC
$<$<BOOL:${UNIX}>:-Werror -Wall $<$<CONFIG:Debug>:-g>>)
add_executable(${PROJECT_NAME} src/main.cpp)
target_link_libraries(${PROJECT_NAME} ${PROJECT_NAME}_LIB)
For the test, it looks like you have 2 or maybe 3 main functions - that's going to be a problem :-) gtest_main is a small helper which provides a main function which calls the required gtest functions to invoke the tests. I'm guessing you've also got main in "test/test_main.cpp" and since you're currently including all your "src/" files, I suppose you've also got a main in "src/main.cpp".
By splitting the mars_rover target into a lib and exe, you can just link to the lib and avoid explicitly excluding "src/main.cpp" from the test. I can't tell whether you want to use your own "test_main.cpp" or use gtest's helper - I've assumed the latter:
include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
file(GLOB_RECURSE TEST_SOURCES ...)
add_executable(${PROJECT_NAME}_TEST ${TEST_SOURCES})
target_link_libraries(${PROJECT_NAME}_TEST gtest gtest_main)
add_executable(${PROJECT_NAME}_TEST test/test_mars_rover.cpp)
# Only bring gtest's include path into scope - its src dir is not designed to
# be public
target_include_directories(${PROJECT_NAME}_TEST PRIVATE
${gtest_SOURCE_DIR}/include)
target_link_libraries(${PROJECT_NAME}_TEST ${PROJECT_NAME}_LIB gtest gtest_main)
Finally, there's no need to specify the full path to the test exe if you use the following syntax:
add_test(NAME CardinalDirectionTests
COMMAND ${PROJECT_NAME}_TEST
--gtest_filter=MarsRoverTest.CardinalDirectionTests)
add_test(NAME RelativeDirectionTests
COMMAND ${PROJECT_NAME}_TEST
--gtest_filter=MarsRoverTest.RelativeDirectionTests)

Detailed guide on using gcov with CMake/CDash?

I'm using CMake with my project and set up a cdash server for continuous/nightly building. Everything works well and by setting up a crontab, we have hourly/nightly build/test results uploaded to our cdash server automatically.
My next step is to add test coverage report to the build. I find the document here https://gitlab.kitware.com/cmake/community/-/wikis/doc/ctest/Coverage but frankly it's a bit far from a practical guide.
Currently I've added the required flag (instead of -fprofile-arcs -ftest-coverage, I find --coverage better), the compilation process generates .gcno files. But then I'm stuck. The command
make NightlyCoverage
doesn't seem to do anything. Could anybody tell me what is the next to do? The result that I want, is by doing make NightlyCoverage, coverage reports are generated and uploaded to cdash server.
I've been using https://github.com/bilke/cmake-modules/blob/master/CodeCoverage.cmake successfully.
Just followed the guidelines: added the files to my CMAKE_MODULE_PATH directory, added
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMakeModules)
if(CMAKE_COMPILER_IS_GNUCXX)
include(CodeCoverage)
setup_target_for_coverage(${PROJECT_NAME}_coverage ${PROJECT_TEST_NAME} coverage)
endif()
in my CMakeLists.txt. I also added manually gcov as a dependency for my target:
if(CMAKE_COMPILER_IS_GNUCXX)
target_link_libraries(${PROJECT_TEST_NAME} gcov)
endif()
With this, I just type
make my_project_coverage
and I get the html report in the coverage directory of my build tree.
I use gcovr to make a GCC Code Coverage Report without the CodeCoverage.cmake :
$ cd /path/to/your/project
$ mkdir build && cd build && cmake ..
$ make && make test
$ gcovr -r ../ .
I set up my project 'foo' in the following way. Copied the cmake file from the https://github.com/bilke/cmake-modules/blob/master/CodeCoverage.cmake to a subdirectory 'cmake_modules'. In the CMakeLists.txt file after the add_executable(foo ...) I added the following:
if(CMAKE_COMPILER_IS_GNUCXX)
LIST(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake_modules")
include(CodeCoverage)
APPEND_COVERAGE_COMPILER_FLAGS()
set(COVERAGE_LCOV_EXCLUDES 'dir1/*' 'dir2/*') // this is optional if you want to exclude some directory from the report
SETUP_TARGET_FOR_COVERAGE_LCOV(NAME foo_coverage
EXECUTABLE foo
DEPENDENCIES foo)
endif()
After cmake, build the target
make
make foo_coverage
And open the report with index.html file in the foo_coverage folder in the build folder
This answer is the same as #rcomblen's answer but its a bit outdated so I'll share my solution. Here's what I did:
created a toy project
(base) ciaran#DESKTOP-K0APGUV:/mnt/d/CoverageTest$ tree -L 2
.
├── CMakeLists.txt
├── cmake
│   └── CodeCoverage.cmake
├── src
│   ├── domath.cpp
│   ├── domath.h
│   └── testdomath.cpp
└── third_party
└── googletest
Where
// src/domath.h
#ifndef COVERAGETEST_DOMATH_H
#define COVERAGETEST_DOMATH_H
class domath {
public:
int add(int a, int b);
};
#endif //COVERAGETEST_DOMATH_H
and
// src/domath.cpp
#include "domath.h"
int domath::add(int a, int b) {
return a + b;
}
and
// src/testdomath.cpp
#include "gtest/gtest.h"
#include "domath.h"
TEST(DoMathTests, testAdd){
domath m;
int actual = m.add(4, 6);
ASSERT_EQ(10, actual);
}
download googletest and put it under third party directory
copy the gist so kindly shared by the other answers on this thread into cmake/CodeCoverage.cmake
install gcovr. This step is vital, because the other answers on this thread no longer work with the version of gcovr that I already had:
(base) ciaran#DESKTOP-K0APGUV:/mnt/d/CoverageTest$ pip install gcovr
(base) ciaran#DESKTOP-K0APGUV:/mnt/d/CoverageTest$ gcovr --version
gcovr 4.2
(base) ciaran#DESKTOP-K0APGUV:/mnt/d/CoverageTest$ which gcovr
/home/ciaran/miniconda3/bin/gcovr
Note, we need the output of which gcovr for the cmake script.
4) Write a cmake script that create a library, a test executable and use the CodeCoverage.cmake module:
cmake_minimum_required(VERSION 3.15)
project(CoverageTest)
set(CMAKE_CXX_STANDARD 14)
# setup googletest
add_subdirectory(third_party/googletest)
# create our library
add_library(DoMath STATIC src/domath.h src/domath.cpp)
add_dependencies(DoMath gtest gtest_main)
# create the test executable
add_executable(TestDoMath src/testdomath.cpp)
target_include_directories(TestDoMath PRIVATE third_party/googletest/googletest)
target_link_libraries(TestDoMath PRIVATE
DoMath gtest gtest_main)
add_dependencies(TestDoMath DoMath gtest gtest_main)
# now for coverage bits
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
if (CMAKE_COMPILER_IS_GNUCXX)
include(CodeCoverage)
append_coverage_compiler_flags()
# we need to turn off optimization for non-skewed coverage reports
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0")
# optional excludes - None needed here
# set(COVERAGE_EXCLUDES)
# importantly, set the path to the gcovr executable that you downladed
set(GCOVR_PATH "/home/ciaran/miniconda3/bin/gcovr")
# Works
setup_target_for_coverage_gcovr_xml(
NAME TestDoMathCoverageXml
EXECUTABLE TestDoMath
DEPENDENCIES TestDoMath DoMath
)
# Works
setup_target_for_coverage_gcovr_html(
NAME TestDoMathCoverageHtml
EXECUTABLE TestDoMath
DEPENDENCIES TestDoMath DoMath
)
# This one did not work for me:
setup_target_for_coverage_lcov(
NAME TestDoMathCoverageLcov
EXECUTABLE TestDoMath
DEPENDENCIES TestDoMath DoMath
)
endif ()
And thats it. Now just build the new targets.
Good luck.