Catch lib (unit testing) and CTest (CMake) integration - c++

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.

Related

Include googletest into CMake installation process

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.

how can i make some install command run before compile process?

I will use install command in my CMakeLists like this:
install(DIRECTORY lib-mmm/src/infra/ DESTINATION /home/nick/infra FILES_MATCHING PATTERN "*.h")
this is command to install some directory to some place.
I want this run before other compile process.
but i found when i define it as install, it will be called only when make install, which is after make process.
how can i make install directory command run before real compile process?
Afaik there is no way to do this by using the same project. The install target depends on the targets being build and any dependency of building on the install target would result in a circular dependency.
There are alternatives though:
Use file(COPY)
Use execute_process to set up, build & install another cmake project during configuration. It can be problematic though to get cmake to use the same options for that build. This could also be refined by getting add_custom_command involved...
In your case though simply adding the correct include directory using target_include_directories will probably work better though.

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/

How can I use CMake to both build wxwidgets on-demand and link with it

I have the following situation:
I'm working on an application that depends on a number of third party libs, among them wxwidgets
I build the application for multiple target configurations (x86, arm, Linux, Windows) using Linux as my build host system
Due to the above mentioned multiple target configurations, I have chosen to build those third-party libs from source, using CMake's ExternalProject_Add function.
The third-party libs are built 'on-demand' at a location separate from my application's CMAKE_BINARY_DIR so that I can wipe the build tree for my application without having to rebuild the third-party libs (takes a looooong time).
The location of the third-party libs is different depending on what target configuration I build them for (obviously).
I'm quite new to CMake and the problem I currently face is this:
The source files in my application can't find the wx include files and I need to set the correct linker flags to be able to link my application against wxwidgets.
This seems to be handled by a utility 'wx-config' that provides exactly that info as output when run with either the --cppflags or --libs flag. I can not however, figure out how to catch that output and append it to the include dirs and linked libraries I setup from my CMakeLists.txt files.
So basically what I want is.
Build wxwidgets (if it doesn't exist) for the current target configuration
Run wx-config --cppflags and --libs to find out the correct include dirs and linker flags for the current target configuration
Use the info from step 2 when building targets that are my own application
So far I've tried something like this:
# Set a target-configuration-specific location
set(wxwidgetsTop ${MYPROJECT_EXTERNAL_DIR}/wxwidgets/wxwidgets_${MYPROJECT_CURRENT_TARGET_CFG})
# Build the project
ExternalProject_Add( wxWidgetsExternal
PREFIX ${wxwidgetsTop}
URL ${MYPROJECT_EXTERNAL_DIR}/tarballs/wxWidgets-3.0.2.tar.bz2
SOURCE_DIR ${wxwidgetsTop}/src/wxwidgets
CONFIGURE_COMMAND ${configure_cmdline}
BUILD_COMMAND make -j${MYPROJECT_NCPU}
INSTALL_COMMAND make install
)
# Create a wxwidgets target to be used as a dependency from other code
add_library(wxWidgets IMPORTED STATIC GLOBAL)
add_dependencies(wxWidgets wxWidgetsExternal)
# (non-working) attempt to get the correct include dirs and linker
# flags for wxwidgets
add_custom_command(TARGET wxWidgetsExternal
POST_BUILD
COMMAND ${INSTALL_DIR}/bin/wx-config ARGS --cppflags
COMMENT "Running wx-config"
)
but the above does not provide a way to actually use the result from the custom command to append the cppflags and linker options when building the targets that make up my application.
What is a good way to achieve what I want?
I see three different ways of doing this:
Method 1: use find_package
Use wxWidgets as a standalone requirement for your project, and expect the devs to install it before building your project. In your CMakeLists.txt you will need to call find_package(wxWidgets), like this:
find_package(wxWidgets COMPONENTS net gl core base)
if(wxWidgets_FOUND)
include(${wxWidgets_USE_FILE})
# and for each of your dependent executable/library targets:
target_link_libraries(<YourTarget> ${wxWidgets_LIBRARIES})
endif()
This has the advantage of not rebuilding the lib if you rebuild your project, however it requires some work for your user (they need to handle the installation of wxWidgets by hand) and for you (you need to setup include paths / compile definitions / ... by hand).
Method 2: embed wxWidgets
The second option is to bundle wxWidgets in your repo (svn external or git submodule) and usually (re)write the CMakeLists.txt of this lib to be target-oriented. Then, in your top-most CMakeLists.txt, you can do the following:
# for example, if you just need core and net:
target_link_librairies(my_app PUBLIC wxWidgetsCore wxWidgetsNet)
# No need to manually setup include dirs, etc...
To make a CMakeLists.txt target-oriented, you define include directories and other compilation properties for a target, not a directory. Example:
# When defining wxWidgetsCore, for example
add_library(wxWidgetsCore ...)
target_include_directories(wxWidgetsCore PUBLIC someDir)
target_compile_definitions(wxWidgetsCore PUBLIC -pedantic)
target_link_libraries(wxWidgetsCore PUBLIC someLib)
The drawback of this approach is that rebuilding your project will trigger a rebuild of wxWidgets. However, it is possible to trick this by not using "rebuild" but "clean just my app, then build". Here is some insight on how to achieve this.
Method 3: some sort of hybrid
The big drawback of method 2 leads to the third approach: don't put wxWidgets in your project, but create a CMakeLists.txt that will "import" the lib. The idea: you ask your user for the directory where wxWidgets is installed, then this script will setup everything for your project. First, put the CMakeLists.txt here:
/your-project-root
/thirdparty
/wxWidgets
CMakeLists.txt
/dir-where-wxwidgets-is-installed
...
Now, you define an imported target:
# When defining wxWidgetsCore, for example
set(WX_INCLUDE_DIR ${USER_SPECIFIED_WX_ROOT}/include)
add_library(wxWidgetsCore IMPORTED GLOBAL)
set_property(TARGET wxWidgetsCore APPEND PROPERTY
INTERFACE_INCLUDE_DIRECTORIES ${WX_INCLUDE_DIR})
See INTERFACE_INCLUDE_DIRECTORIES and INTERFACE_LINK_LIBRARIES. You need your user to have build wxWidgets somewhere in his system, but from your point of view you just do target_link_libraries(your_app PUBLIC wxWidgets...), as in method 2. The advantage is that this approach is interchangeable with method 2 transparently, and you don't put the whole dependency in your project.
Setting cppflags and linker flags has to be done at CMake time, but you are trying to run wx-config at build time and you are not capturing its output anyway, so your add_custom_command() isn't doing anything useful other than printing things to the build tool's output.
Ideally, you would use the FindwxWidgets module CMake already provides. It requires wxWidgets to already be built (but see further below). Have a look at the CMake documentation for it and see if that at least sounds like what you are trying to achieve manually by using wx-config. If you can get FindwxWidgets to do the job for you, that would be a much cleaner approach.
Getting something to build at configure time so you can use it later on in your CMakeLists.txt file is a bit more tricky. ExternalProject_Add() downloads and builds things at build time, but you need wxWidgets to be built earlier at configure time. I wrote an article recently for how to do at least the downloading part at configure time and you should be able to adapt it to do the whole build at configure time instead. The article uses Google Test as its example and can be found here:
https://crascit.com/2015/07/25/cmake-gtest/
It would be trivial to make it put the wxWidgets build wherever you like, not just in the CMAKE_BINARY_DIR area. That would allow you to have different wxWidgets builds for each build configuration and to be able to wipe out your application's build tree independently of the wxWidgets builds.
Hope that points you in the right direction.
The solution I use checks for wxWidgets installation in the system using find_package, if it's not found, then the script downloads wxWidgets from github and links the program against downloaded library. The lib is installed in the build directory, so only the first build is slow - subsequent builds do not even check wxWidgets sources timestamps, so the process is as fast as building using preinstalled wxWidgets library.
Here's how my script does it:
It quietly checks for wxWidgets installation using find_package(wxWidgets QUIET),
If it's found, the script adds a dummy library wxWidgets_external,
If it's not, then it creates an ExternalProject named wxWidgets_external which downloads, builds and installs the library in the build dir, setting wxWidgets_ROOT_DIR to point to the wxWidgets installation dir,
Then we add another ExternalProject pointing to a folder with the main program's source files and CMakeLists.txt build script. This external projects depends on wxWidgets_external which is either a dummy library in case wxWidgets is preinstalled in the system, or an external project set up to download the library from github,
In the aforementioned CMakeLists.txt we again call find_package, this time with REQUIRED parameter and use the library the standard way (https://docs.wxwidgets.org/trunk/overview_cmake.html). Because we set up the dependencies and variables correctly, this call will use either preinstalled wxWidgets (if it's available) or the one downloaded from github.
There are more quirks to it, but that's the gist of it. The full sample code (tested on Linux, Windows and Mac) is available on github (https://github.com/lszl84/wx_cmake_template).
Also see full blog post which explains this in more detail: https://justdevtutorials.medium.com/wxwidgets-cmake-multiplatform-superbuild-4ea86c4e6eda

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} )