Adding google-test to a subfolder in a CMake project - cmake

I have just added google-test source code to libs/gtest-1.6.4 directory in my project. There is a libs/gtest-1.6.4/CMakeLists.txt file. In the top-most CMakeLists.txt, I have added add_subdirectory('libs/gtest-1.6.4'). The structure of the project is
|- CMakeLists.txt
|- src
|- CMakeLists.txt
|- *.h and *.cc
|- libs
|- gtest-1.6.4
|- CMakeLists.txt
|- gtest source code etc.
|- other subdirectories
Now I add #include "gtest/gtest.h" in one of the header file. Compilation fails with
gtest/gtest.h: No such file or directory
compilation terminated.
Here is the snippet of my src/CMakeLists.txt file.
set( Boost_USE_STATIC_LIBS ON )
find_package( Boost COMPONENTS graph regex system filesystem thread REQUIRED)
.. Normal cmake stuff ...
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS} )
# This line is added for google-test
INCLUDE_DIRECTORIES(${GTEST_INCLUDE_DIRS} ${COMMON_INCLUDES})
add_executable(Partitioner
print_function.cc
methods.cc
partitioner.cc
main.cc
)
TARGET_LINK_LIBRARIES(Partitioner ${Boost_LIBRARIES})
TARGET_LINK_LIBRARIES(Partitioner ${GTEST_LIBRARIES})
What am I missing?

Looking at GTest's CMakeLists.txt, it looks like their include path is ${gtest_SOURCE_DIR}/include. They also define the library as a CMake target called gtest (this is wrapped in a macro cxx_library(gtest ...) currently on line 70).
So it looks like you need to do:
...
# This line is added for google-test
INCLUDE_DIRECTORIES(${GTEST_INCLUDE_DIRS} ${COMMON_INCLUDES})
INCLUDE_DIRECTORIES(${gtest_SOURCE_DIR}/include ${COMMON_INCLUDES})
...
TARGET_LINK_LIBRARIES(Partitioner ${Boost_LIBRARIES})
TARGET_LINK_LIBRARIES(Partitioner ${GTEST_LIBRARIES})
TARGET_LINK_LIBRARIES(Partitioner ${Boost_LIBRARIES} gtest)
You'd also have to ensure that in your root CMakeLists.txt, you've called add_subdirectory(libs/gtest-1.6.4) before add_subdirectory(src) so that the GTest variables are correctly set when they're being used in "src/CMakeLists.txt".

As mentioned in accepted answer,
I did put my GoogleTest stuff up before my add_subdirectory() lines and it worked.
# The ROOT CMakeLists.txt
enable_testing()
include(CTest)
# https://google.github.io/googletest/quickstart-cmake.html
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/....zip
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
include(GoogleTest)
add_subdirectory(some)
add_subdirectory(other)
add_subdirectory(another)
And in one of those sub directory, I see tests work.
# A CMakeLists.txt in a sub directory
#enable_testing() # NOT REQUIRED, hence, commented out
#include(CTest) # NOT REQUIRED, hence, commented out
#include(GoogleTest) # NOT REQUIRED, hence, commented out
add_executable(
mytest
test/mytest.cpp
)
target_link_libraries(
mytest
gtest_main
)
gtest_discover_tests(
mytest
)

Related

how to split 'header', 'src', 'test' dir in cmake?(and donot add cmakelist.txt in each dir)

when building a project stucture like following:
LinearAlgebra
|---HEADER
|-----|---Linear.h
|---SRC
|-----|---Linear.cpp
|---TEST
|-----|---hello_test.cc
here is my CMakeList.txt:
cmake_minimum_required(VERSION 3.10)
project(LinearAlgebra )
set(CMAKE_CXX_STANDARD 11)
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
add_library(LA_HEADER INTERFACE header/Linear.h)
add_library(LA_SRC INTERFACE src/Linear.cpp)
target_include_directories(LA_HEADER INTERFACE "${PROJECT_SOURCE_DIR}/header" "${PROJECT_SOURCE_DIR}/src")
enable_testing()
add_executable(
hello_test
test/hello_test.cc
)
target_link_libraries(
hello_test
gtest_main
LA_HEADER
LA_SRC
)
include(GoogleTest)
gtest_discover_tests(hello_test)
it works fine with cmake -S . -B build, but when it comes to cmake --build build following error occured:
Undefined symbols for architecture x86_64:
"Linear::Linear()", referenced from:
HelloTest_BasicAssertions_Test::TestBody() in hello_test.cc.o
it seems something wrong with my cmake file that didn't tell Linear.h where Linear.cpp located. So how to fix it ?? thanks for your help...
seems i misunderstand add_library, change three lines and it works out:
cmake_minimum_required(VERSION 3.10)
project(LinearAlgebra )
include_directories(header) # include_directories instead of add_library for .h files
add_library(LA_LIB src/Linear.cpp) # use add_library for .cpp files only!!!
set(CMAKE_CXX_STANDARD 11)
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
enable_testing()
add_executable(
hello_test
test/hello_test.cc
)
target_link_libraries(
hello_test
gtest_main
LA_LIB # link LA_LIB only..
)
include(GoogleTest)
gtest_discover_tests(hello_test)
leave it here for anyone have the same requirements.

How to add include directories from ExternalProject_Add into project?

I have tried following this solution this individual has from this question. I am trying to do this with boost with the following cmake file in a separate directory from my Source:
#---------------------------------------------------------------------------
# Get and build boost
SET_PROPERTY(DIRECTORY PROPERTY "EP_BASE" ${ep_base})
SET(boost_GIT_TAG "origin/master")
set( Boost_Bootstrap_Command )
if( UNIX )
set( Boost_Bootstrap_Command ./bootstrap.sh )
set( Boost_b2_Command ./b2 )
else()
if( WIN32 )
set( Boost_Bootstrap_Command bootstrap.bat )
set( Boost_b2_Command b2.exe )
endif()
endif()
ExternalProject_Add(Boost_external_Download
GIT_REPOSITORY "https://github.com/boostorg/boost.git"
GIT_TAG ${boost_GIT_TAG}
BUILD_IN_SOURCE 1
UPDATE_COMMAND ""
PATCH_COMMAND ""
CONFIGURE_COMMAND ${Boost_Bootstrap_Command}
BUILD_COMMAND ${Boost_b2_Command} install
--without-python
--without-mpi
--disable-icu
--prefix=${CMAKE_BINARY_DIR}/Boost
--threading=single,multi
--link=shared
--variant=release
-j8
INSTALL_COMMAND ""
INSTALL_DIR ""
)
if( NOT WIN32 )
set(Boost_LIBRARY_DIR ${CMAKE_BINARY_DIR}/Boost/lib/ )
set(Boost_INCLUDE_DIR ${CMAKE_BINARY_DIR}/Boost/include/boost/ )
else()
set(Boost_LIBRARY_DIR ${CMAKE_BINARY_DIR}/Boost/lib/ )
set(Boost_INCLUDE_DIR ${CMAKE_BINARY_DIR}/Boost/include/boost/ )
endif()
ExternalProject_Get_Property(Boost_external_Download BINARY_DIR)
SET(Boost_DIR ${BINARY_DIR} CACHE PATH "")
add_library(Boost_external SHARED IMPORTED)
The only thing that is different between one of the solutions and mine is that I don't have the set_target_properties right after I add the library. Since boost has a lot of libraries in there and I am not exactly sure what needs to be added.
In my Source Folder, my CMakeLists.txt does the following:
include_directories(${Boost_INCLUDE_DIR})
add_executable(Main main.cpp)
target_link_libraries(Main Boost_external)
add_dependencies(Main Boost_external_Download)
However, in main.cpp when I use #include <boost/process.hpp> just to see if it links, I get the error that #include <boost/process.hpp> no such file or directory. When I try to make the project. I am not really sure where I am going wrong with this so any helpful advice would be appreciated.
Edit: structure
Root Folder
|
- CmakeLists.txt
- Externals Directory
|
| - Externals.cmake
| - boostExternal.cmake
| - other external cmake files
- Source Directory
|
| - CmakeLists.txt
| - main.cpp
The Root Cmake calls the Externals.cmake file. Which then includes all the other Cmake files within that directory. Once those are finished, the root Cmake file add the directory Source, and that Cmake file has the call to include_directories(${Boost_INCLUDE_DIR}).

CTest not detecting tests

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)

CPack create packages with executables from different source tree

The problem is as follows:
Project structure:
ProjectDir
- CMakeLists.txt
- src
-- CMakeLists.txt
-- FirstApp
--- CMakeLists.txt
--- ... sources ...
-- SecondApp
--- CMakeLists.txt
--- ... sources ...
- tools
-- CMakeLists.txt
-- SomeTool
--- CMakeLists.txt
--- ... sources ...
-- SomeOtherTool
--- CMakeLists.txt
--- ... sources ...
What I want to achieve is:
package (let it be rpm or deb) with SomeTool binaries;
package with FirstApp, SecondApp AND SomeOtherTool binaries;
As far as I know:
CPack is putting into packages content the stuff that is defined in install command;
CPack cannot be called ( include(CPack) ) twice in the same tree (for example it cannot be called in CMakeLists.txt at src level AND SecondApp level);
What do I have
In ProjectDir/tools/SomeTool/CMakeLists.txt I've (it's pseado code):
PROJECT( SomeTool )
SET(TARGET SomeTool)
SET(CPACK_GENERATOR "RPM")
SET(CPACK_PACKAGE_NAME "SomeTool")
# ...
# all the other CPACK_* stuff
# ...
include(CPack)
add_custom_target(${TARGET}-package
COMMAND cpack --config "${CMAKE_CURRENT_BINARY_DIR}/CPack${PROJECT_NAME}Config.cmake")
SET(SOURCES ...)
SET(HEADERS ...)
add_executable(${TARGET} ${SOURCES} ${HEADERS})
install(TARGETS ${TARGET}
RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/usr/bin)
This way I can call make SomeTool-package and it'll create package (SomeTool.rpm) with content /usr/bin/SomeTool. Great!
I can have very similar CMakeLists.txt in ProjectDir/src/ dir:
# src/CMakeLists.txt
PROJECT( MainProject )
SET(CPACK_GENERATOR "RPM")
SET(CPACK_PACKAGE_NAME "MainProject")
# ...
# all the other CPACK_* stuff
# ...
include(CPack)
add_custom_target(MainProject-package
COMMAND cpack --config "${CMAKE_CURRENT_BINARY_DIR}/CPack${PROJECT_NAME}Config.cmake")
add_subdirectory(FirstApp)
add_subdirectory(SecondApp)
# src/FirstApp/CMakeLists.txt
SET(TARGET FirstApp)
SET(SOURCES ...)
SET(HEADERS ...)
add_executable(${TARGET} ${SOURCES} ${HEADERS})
install(TARGETS ${TARGET}
RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/usr/bin)
# src/SecondApp/CMakeLists.txt
SET(TARGET SecondApp)
SET(SOURCES ...)
SET(HEADERS ...)
add_executable(${TARGET} ${SOURCES} ${HEADERS})
install(TARGETS ${TARGET}
RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/usr/bin)
This way I can call make MainProject-package and it'll create package (MainProject.rpm) with content /usr/bin/FirstApp and /usr/bin/SecondApp. Great!
SomeOtherTool also have a CMakeLists.txt which looks the same as FirstApp and SecondApp CMakeLists.txt and I can call make SomeOtherTool and it'll produce SomeOtherTool binaries.
The Question
As CPack is puting into packages stuff connected to install command, how can I connect SomeOtherTool with my MainProject-package ?
My solution would (is) be to put another install clause at the end of src/CMakeLists.txt that'd look like:
add_dependency(MainProject SomeOtherTool)
install(FILES ${CMAKE_BINARY_DIR}/SomeOtherTool DESTINATION ${CMAKE_INSTALL_PREFIX}/usr/bin )
Is there any other way? This solution doesn't look clean.. If I change the SomeOtherTool executable name I'll have to change it in here also. The same goes with install path.

Compile sources in `src` directory to binaries in `bin` directory with CMake

My project directory contains a CMakeLists.txt file and src and include directories at its root. src also contains its own CMakeLists.txt, which is linked by the one at the root. Is there a way I can specify to CMake to set a default global build directory so that the syntax in src/CMakeLists.txt is close to the following?
include_directories(include)
add_executable(first main.cpp foo.cpp)
add_executable(second bar.cpp)
I would like this directory tree to be built:
CMakeLists.txt
src/
CMakeLists.txt
main.cpp
foo.cpp
bar.cpp
include/
...
bin/ (or build/)
first
second
You could set CMAKE_RUNTIME_OUTPUT_DIRECTORY:
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
However, this won't create subdirectories inside bin/ for each different target.
If you want that, you could create a helper function to wrap add_subdirectories:
function(my_add_executable TargetName)
set(Files ${ARGV})
list(REMOVE_AT Files 0)
add_executable(${TargetName} ${Files})
set_target_properties(${TargetName} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY
"${CMAKE_SOURCE_DIR}/bin/${TargetName}")
endfunction()
then simply change your calls to:
my_add_executable(first main.cpp foo.cpp)
my_add_executable(second bar.cpp)
For further details, run
cmake --help-variable "CMAKE_RUNTIME_OUTPUT_DIRECTORY"
cmake --help-property "RUNTIME_OUTPUT_DIRECTORY"
cmake --help-property "RUNTIME_OUTPUT_DIRECTORY_<CONFIG>"