Selectively building gtest tests with cmake and showing gtest output - c++

I've got cmake working with a test file similar to " How to start working with GTest and CMake " but the problem is that gtest and the test binary gets built each time I make rather than just when I run make test. And when running make test, only the ctest summary output is shown, not the actual gtest output.
How can I change this behaviour so that the tests and gtest library is only built when I run make test, and running make test actually shows the proper output?

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.

Automate CMake build using C++ script

I would like to automate the build of CMake using an MSVC C++ script instead of using CMake-gui to generate the build or CMake terminal or using the CMake integrated on MSVC 2017 by right click on the CMakeLists.txt to build it manually. Assume we have a project (name it: initialize) that includes the CMakeLists.txt and initialize.cpp, so my question is how I can convert these commands into a C++ code, assume build_initialize.cpp:
mkdir build
cd build/
cmake ..
So, the requirement of this tiny C++ code is to
Set the path to this project
Create build folder
Run CMake
At the end if I execute build_initialize.exe, the job is just to build the initialize.cpp using CMake. The goal is to test if the build is success or not as a test case within another project that has several test cases.
You may ask, why I didnot include it to the top CMakelists.txt, and then build it from the beginning using CMake. If I am going to do that, I will get an executable file. As a result, by running the ctest of CMake, the initialize.exe will require a pace of hardware. This is not the goal. My goal is just to build it. If I run build_initialize.exe, just repeat the build using CMake without initialize.exe execution.
Sorry, it could be very simple, but I lack the good experience either in C++ or CMake. Two days have been lost without success.
Thanks to all of you for the comments. The answer has been given by #Fred. To run cmake from C++ script, simply the system() can be used such as: System(cmake -S path_to_src -B path_to_bld).
Useful link: https://faq.cprogramming.com/cgi-bin/smartfaq.cgi?id=1043284392&answer=1044654269

CMake: target "test" doesn't build tests, target "all" does

I created a command-line portable script-based industrialized agnostic build system useful to quickly build several dependent projects while not having to rely on a particular IDE or a build factory. It's agnostic, because it's not based on a single build engine. I founded the first version using cmake, because my projects are mostly C++, but that'll evolve (to include gradle for example or whatever). That's to say, I'm not centered on CMake, it's merely a tool to a goal, easy portable C++ project building. I had BJam in mind formerly and would have kept it if there had been more documentation.
As a result though, I'm very dependent on CMake to perform the build and unit tests. As of today, I realized that tests are built under the 'all' target and run under the 'test' target.
With CMake 2- (and -here for example- a Unix Makefiles generator):
make all # Build project AND tests
make test # Run tests
With CMake 3+ and any generator:
cmake --build . --target all # Build project AND tests
cmake --build . --target test # Run tests
I'd like to know if someone would know a way to split the 'build project' phase apart from the 'build tests' phase (also because it feels more natural in my build system to join test building and running tests than the other way around).
Important precision: I don't want to bootstrap the project with one vision or another (by flipping BUILD_TESTING). The idea would be to have 3 stages like:
cmake --build . --target <project> # 1. Build project only
cmake --build . --target <build_tests> # 2. Build tests
cmake --build . --target <run_tests> # 3. Run tests
If I choose not to run tests, I could go straight from phase 1 above to installing, but running phase 3 would trigger the previous dependent phases.
Any clue? (If not, I suspect I'll have to ask CMake developers directly...)
Thanks in advance. Regards.
Assuming you choose build_tests target for build test's executables and run_tests target for run them:
Defining targets:
add_custom_target(build_tests)
# 'run_tests' triggers 'ctest'.
add_custom_target(run_tests COMMAND ${CMAKE_CTEST_COMMAND})
# 'run_tests' implies 'build_tests'
add_dependencies(run_tests build_tests)
Creating test's executables, so they won't be built by default but with build_tests target.
# Do not build 'test1' by default
add_executable(test1 EXCLUDE_FROM_ALL ...)
# 'build_tests' implies (among other things) building 'test1'
add_dependencies(build_tests test1)

CMake test does not find library on MacOS

I have a simple library with unit tests. That library can be built as static linked library or dynamic library. The library builds for Windows, Linux and MacOS.
The library is using CMake (with Qt) and has ctest unit tests.
This is how the library gets build and unit tests are called:
cmake -DCMAKE_BUILD_TYPE=Debug path/to/sources
cmake --build . --target all
cmake --build . --target test
This is all working fine, except for MacOS. When building the library is a dynamic linked library, the unit tests do not find the library.
Start 110: UnitTest
110/119 Test #110: UnitTest.................***Exception: Child aborted 0.01 sec
dyld: Library not loaded: library.dylib
Referenced from: /tmp/build/bin/UnitTest
Reason: image not found
Calling ctest directly or calling the executable directly works fine. Only when calling the test target from cmake, the unit test executable does not find the library.
Setting DYLD_LIBRARY_PATH to the location of the library does not help.
I used install_name_tool to change the path to the library to an absolute path, which fixes the problem.
However, this is only a indicator of the problem, not a solution.
I suspect cmake changes the DYLD_LIBRARY_PATH when calling the test target. Is this true? How should this work?
I suspect cmake changes the DYLD_LIBRARY_PATH when calling the test target. Is this true?
In fact, ctest is used to execute your tests previously described in your CMakeLists.txt and neither cmake or ctest update DYLD_LIBRARY_PATH environment variable.
That said, if you would like to associate a specific test with some environment variable, you could do so by setting the ENVIRONMENT test property. For example:
set_property(TEST ${name} PROPERTY ENVIRONMENT "DYLD_LIBRARY_PATH=/path/to/foo")
To better address your problem, I suggest you do the following:
indicate the version of CMake binaries used
if possible possible, provide a small example allow to reproduce the problem
share the output of these two commands:
(1) ldd /tmp/build/bin/UnitTest
(2) otool -l /tmp/build/bin/UnitTest | grep -A 3 LC_RPATH | grep path
As a side note, consider specifying the type of parameter passed to cmake, prefer -DCMAKE_BUILD_TYPE:STRING=Debug instead of -DCMAKE_BUILD_TYPE=Debug.

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/