This is a quick recipe for setting up CMake to use googletest in your projects.
First, make a tests
folder in the root of your project. Then, add
add_subdirectory(tests)
to your CMakeLists.txt
, after you’ve finished adding
the libraries in your project. Note that the way I’ve written this probably
requires CMake 3.4+.
The CMakeLists.txt
file in tests
should look like this:
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
This adds the Threads::Threads
target that we can link to, to enable the
threading support that GTest requires. On some systems, it is important to use
the -pthread
flag, so this does that if necessary.
include(ExternalProject)
ExternalProject_Add(
gtest
URL http://googletest.googlecode.com/files/gtest-1.7.0.zip
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/gtest
URL_MD5 2d6ec8ccdf5c46b05ba54a9fd1d130d7
INSTALL_COMMAND ""
)
ExternalProject_Get_Property(gtest source_dir binary_dir)
We have to add an external property, to get CMake to download and build GTest for us. We also need to get the source directory and binary directory for use in linking.
add_library(libgtest INTERFACE)
add_dependencies(libgtest gtest)
target_link_libraries(libgtest
INTERFACE Threads::Threads
"${binary_dir}/libgtest_main.a"
"${binary_dir}/libgtest.a")
target_include_directories(libgtest INTERFACE "${source_dir}/include")
Hopefully these lines are familiar to you; they are setting up a special target
that we aren’t “building”, but are using. The target libgtest
is simply an
interface (no building), and is dependent on gtest
(That has to be built
first). The link and include commands set up the dependencies so that future
target_link_libraries commands only need this target, and will inherit
everything else!
enable_testing()
This prepares CTest to handle the tests. You can either run the binaries, or use “make test” to run the tests through CTest’s runner program.
file(GLOB test_cases *.cpp)
Or however you want to collect your test cases.
foreach(case_file ${test_cases})
get_filename_component( case_name ${case_file} NAME_WE )
set (case_name test_${case_name})
add_executable(${case_name} ${case_file})
target_link_libraries(${case_name} libgtest MyLibrary)
add_test(NAME ${case_name}
COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${case_name}
WORKING_DIRECTORY
${PROJECT_BINARY_DIR}
)
endforeach()
Here, we make the tests, doing two things. Setting up the CTest integration is
the bulk of the commands above; the main command is the target_link_libraries,
which should have your library target (MyLibrary
in this example) and the
libgtest
target. That gets all the includes and links (and defs, if you have
those) set on the test targets. That’s it!
Using an IDE
I’ve found this has some issues with IDE’s that support multiple build
configurations. I’m looking into a better solution, but for now, these lines
injected after the Get_Property
call will allow you to build directly in the
IDE again:
if(CMAKE_GENERATOR STREQUAL Xcode)
set(binary_dir "${binary_dir}/Debug")
endif()