Include googletest into CMake installation process - c++

I have a C++ project that I am able to compile into a static library using CMake. I am also testing this project using googletest but after sifting through previous answers on getting the utility working with CMake projects I am stuck.
The root dir of my project contains the necessary code to compile my project into a static lib in the standard paths. Here is an example of the CMakeLists.txt file in my tests/ directory :
# Download and install GoogleTest
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
)
FetchContent_MakeAvailable(googletest)
# TESTS
add_executable(
bin test.cpp
)
# enable testing
enable_testing()
target_link_libraries(
bin
lib
# GTest::gtest
GTest::gtest_main
pthread
)
include(GoogleTest)
gtest_discover_tests(bin)
This successfully build the googletest library and my tests but doesn't run them automatically. I had to run ctest manually after my process to see the result of my tests. I want my typical cmake.. , make, make install process to build my project upon successful tests. Is there a way to do this? I think it makes sense for tests to pass as the first step before installing the library itself. Is there also a way to check for an installation of googletest on the system before installing the package from source?

To my understanding - both gtest_discover_tests() and gtest_add_tests() are only for replacing CMake's add_test() i.e. they discover and add tests to the ctest executable .
It is also not standard that you run tests during cmake <...>, make <...>, make install. So a good thing to think about is, to make an option that allows the end-user to decide if he/she wants to run tests.
That being said the easiest way on how to get your tests to run let's say - post build. Is to add_custom_command(), e.g.:
if(RUN_MTPK_TESTS)
add_custom_command(TARGET test_openMTPK
POST_BUILD
COMMAND ctest --output-on-failure)
endif()
Then by running: cmake -S[source] -B[build] -DRUN_MTPK_TESTS=TRUE you will, after running make, execute your tests through ctest.
To answer your last question, is there a way on how to check if googletest is already installed? Yes there is and it requires some additional conditions in your CMakeLists.txt. Example:
find_package(GTest)
if(NOT GTest_FOUND)
#FetchContent, etc...
endif()
#rest of your cmakelists
EDIT: Check find_package() for more information regarding the use of find_package and what variables it sets and how can you customize the behavior of said command.

Related

Specifying Build Options for External CMake Dependency

I am in the process of writing my project's CMakeLists.txt file. My project relies on an external dependency, GLFW, luckily for me GLFW also uses CMake for its build system. I am using find_package() and git submodules to handle dependency management, currently this is how my CMakeLists.txt file looks like:
# CMake version
cmake_minimum_required(VERSION 3.0)
# project name
project(CHIP-8)
# dependency management
find_package(OpenGL REQUIRED)
find_package(glfw)
if(NOT glfw)
message("Unable to locate glfw.")
message("Cloning the repository.")
execute_process(
COMMAND
git submodule update --init -- libs
WORKING_DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR}
)
message("Building glfw.")
add_subdirectory(libs/glfw)
endif()
From my limited understanding of CMake the command add_subdirectory(libs/glfw) runs CMake on the recently cloned glfw sub-module. The problem is a lot of unnecessary features are part of the default build for GLFW such as examples, unit tests, and documentation.
The documentation for compiling GLFW lists the CMake options for disabling these features GLFW_BUILD_EXAMPLES, GLFW_BUILD_TESTS, and GLFW_BUILD_DOCS.
I have two questions, the first being how can I specify these options, and the second is the argument I pass for find_package accurate (I do have GLFW installed on my system yet every time I build it still attempts to clone and build the repository).
Found my answer in a similar question.
All I had to do was add:
option(GLFW_BUILD_EXAMPLES OFF)
option(GLFW_BUILD_TESTS OFF)
option(GLFW_BUILD_DOCS OFF)
right before add_subdirectory(libs/glfw).

kdevelop Unit-Tests with gtest

I have a gtest cmake project that can be compiled and debugged with kdevelop. Since version 4.5 kdevelop can handle unit tests. I do not find a way to integrate the tests to kdevelop "Unit-Tests". Does anybody know how to do it?
For test binaries to show up in the Unit-Tests tab in Kdevelop (tested on 5.3) you need to make your testcases be recognized by CTest.
If you have a dedicated CMakeLists.txt for your test-executable a minimal configuration could look like this:
set (SOURCES
testsource.cpp
)
add_executable(testexecutable ${SOURCES})
target_link_libraries(testexecutable
gtest
)
add_test(
NAME test
COMMAND testexecutable )
Additionally for it to be working with a standard CMake configuration run you need to add
enable_testing()
somewhere in your CMake project, eg. your main CMake file.
I found further documentation here:
https://cmake.org/cmake/help/latest/command/add_test.html
https://gitlab.kitware.com/cmake/community/wikis/doc/ctest/Testing-With-CTest
Be aware that this only adds basic execution of the testcase binaries to the KDevelop GUI. There is no customisation or/filtering in the GUI that I know of.
You may also have a look at the gtest specific defintions for cmake/ctest. I didn't try any of these as I'm stuck on a CMake version which does not support these yet.
https://blog.kitware.com/dynamic-google-test-discovery-in-cmake-3-10/

Catch lib (unit testing) and CTest (CMake) integration

I'm looking for successful example of Catch CatchLib integration with CMake test (Ctest) . as I understand this is additional cmake script which has to parse application ouput?
Did someone already written this? probably shared this?
==================================================
update (solution has been found) :
I've committed cmake script to CatchLib , for the integration Catch with CTest. this is a simplified version of Fraser99's cmake script here
Integrating Catch with CMake is rather simple, as it's a header-only library.
Here's a quick rundown of what you have to do:
You can either assume that the Catch sources are already installed on the build machine or use ExternalProject for fetching them as part of the build process.
In either case, you will end up with the Catch header files in some known directory on your build machine. I would recommend creating an interface target for making this information known to your test executables:
add_library(Catch INTERFACE)
target_include_directories(Catch INTERFACE ${YOUR_CATCH_INCLUDE_DIR})
That way, you can simply specify Catch as a dependency to target_link_libraries:
add_executable(my_test ${MY_TEST_SOURCES})
target_link_libraries(my_test PUBLIC Catch)
As usual with CMake, add_test takes care of introducing the tests to CTest:
enable_testing()
add_test(NAME MyAwesomeTest COMMAND my_test)
And that's it already. Run make test on the built project to run your tests.
I have a project on Github that does this if you need to see a complete working example.
Update for newer versions of Catch: If you've already upgraded to Catch2, that one comes with its own package config file so you can just integrate it calling find_package. This provides a smoother CMake integration overall and you don't have to start defining your own interface target. While the approach above will still work even with Catch2, I would recommend using find_package if your Catch version supports it already.
Install catch with:
$ git clone https://github.com/catchorg/Catch2 <catch_src_dir>
$ mkdir <catch_bin_dir>
$ cd <catch_bin_dir>
$ cmake -DBUILD_TESTING:BOOL=FALSE <catch_src_dir>
$ make
$ make install
Then do add the following to the CMakeLists.txt:
find_package(Catch2 REQUIRED)
target_link_libraries(tests Catch2::Catch2)
See here.

Depending on the INSTALL target of a CMake External Project

Is there a way to identify dependencies of the installation-step of a target in cmake? Here's my situation:
My goal is to be able to download the source code of this project and build it without first installing the dependencies. In other words, I'd like the dependencies to be recognized and installed prior to trying to build the main target. For example, I'm working on including Leptonica as an external project:
set(leptonica_build "${CMAKE_CURRENT_BINARY_DIR}/leptonica")
ExternalProject_Add(
leptonica
DOWNLOAD_DIR ${download_dir}
BINARY_DIR ${leptonica_build}
GIT_REPOSITORY ${OpenCV_git_repository}
GIT_TAG ${OpenCV_git_tag}
TLS_VERIFY true
CONFIGURE_COMMAND <SOURCE_DIR>/configure --prefix=${DOC_READER_INSTALL_PREFIX}
)
Running the target leptonica correctly builds and installs the library into a temporary directory, making itself available to other targets to consume:
add_dependencies(myProgram leptonica)
find_library(LEPT_LIB lept)
target_link_libraries(myProgram ${LEPT_LIB})
The problem is that, when /tmp is cleared and cmake is first executed with the target of myProgram, liblept.so isn't found because it hasn't yet been installed, and consequently an upstream dependency of myProgram hasn't been met until after make install has been run.
In other words, I'd like the build script to first download and install then dependencies, then try to lookup the location of the libraries needed by downstream build steps. Is this possible to do with cmake or should I be accomplishing this goal some other way?
Build and install leptonica from a separate CMakeLists.txt. Alternatively, you can use the same CMakeLists and selectively enable either the ExternalProject-section or the main section of your CMakeLists with a control variable (-DMYPROJECT_INSTALL_DEPS=1)
You can trigger the configure/build steps of leptonica from shell script, or call cmake from the main CMakeLists with execute_process:
execute_process(
COMMAND ${CMAKE_COMMAND} -H... -B...
COMMAND ${CMAKE_COMMAND} --build ... --target install ...
)
That way the entire configuration/build/install steps will get executed in the configuration step of your main project.

How to properly setup googleTest on OS X aside from XCode

How do I setup gTest, so that I can link aganist the library? I will code in vim, so I just want to install the libraries, unlike the XCode setup. Goal is to be able to link a project against the library by setting -lgtest as linker flag and optionally, if I did not write my own test mainroutine, the explicit -lgtest_main flag.
Before you start make sure your have read and understood
this note from Google! This tutorial makes using gtest easy, but may introduce nasty bugs.
1. Get the googletest framework
$ wget https://github.com/google/googletest/archive/release-1.8.0.zip
Or get it by hand. I guess I won't manitain this little How-to, so if you stumbled upon it and the links are outdated, feel free to edit it.
2. Unzip and build google test
$ unzip gtest-1.8.0.zip
$ cd gtest-1.8.0
$ ./configure
$ make
3. "Install" the headers and libs on your system.
$ sudo cp -a include/gtest /usr/include
$ sudo cp -a lib/.libs/* /usr/lib/
gTestframework is now ready to use. Just don't forget to link your project against the library by setting -lgtest as linker flag and optionally, if you did not write your own test mainroutine, the explicit -lgtest_main flag.
From here on you might want to go to Googles documentation about the framework to learn how it works. Happy coding!
It's adviced that you link statically. There's no secret. Being a bit offtopic, I use CMake in my projects, which I recommend, and here (https://github.com/oblitum/operations) I have setup a very basic skeleton project that links to gmock and gtest (it's also adviced by google that you use the same gtest from gmock, when you use gmock). In the external folder reside the external CMake files that actually import gtest and gmock through ExternalProject_Add. In the sample, I'm setting the URL as a file path in my system where gmock and gtest are downloaded, but, if you check CMake ExternalProject_Add docs you can see that download urls, online repository urls are also available, which can allow your build to download gtest and gmock, and cache it, automatically.
I think cmake is an easy way to setup and use gtest on OSX. It works without manually copying files. Unzip gooletest-release-1.8.0, then
cd googletest-release-1.8.0
# create a build directory
mkdir build
cd build
# build configuration
cmake .. -DBUILD_GTEST=ON -DBUILD_SHARED_LIBS=ON
# build it
make
# installation
sudo make install
Afterwards, you can easily incorporate gtest in your project with the cmake commands
# sets GTEST_INCLUDE_DIRS and GTEST_LIBRARIES
find_package( GTest REQUIRED )
# adds the gtest include directory
include_directories( ${GTEST_INCLUDE_DIRS} )
# links gtest
target_link_libraries( yourTestApp ${GTEST_LIBRARIES} )