c++cmake

Linker errors trying to add Google test to basic CMake project


My project directory looks like this:

build
CMakeLists.txt
header_1.h
main.cpp
test
    CMakeLists.txt
    main.cpp
    tests.cpp

I have this CMakeLists.txt to generate my executable (excluding test):

cmake_minimum_required (VERSION 3.1)

project (my_project)

set (CMAKE_CXX_STANDARD 23)
set (CXX_STANDARD_REQUIRED ON)
set (CMAKE_CXX_EXTENSIONS OFF)

add_executable(my_app main.cpp)

target_include_directories(my_app PUBLIC)

I am trying to add a sub-folder test to build unit tests with Google test, but I am struggling.

I know I need to add add_subdirectory(test) in my outer CMakeLists.txt

and then I need test/CMakeList.txt, which I currently have:

set(BINARY ${CMAKE_PROJECT_NAME}_test)

file(GLOB_RECURSE TEST_SOURCES LIST_DIRECTORIES false *.h *.cpp)

set(SOURCES ${TEST_SOURCES})

find_package(GTest REQUIRED)
include_directories(${GTEST_INCLUDE_DIRS})

add_executable(${BINARY} ${TEST_SOURCES}) 

add_test(NAME ${BINARY} COMMAND ${BINARY})

target_link_libraries(${BINARY} PUBLIC ${CMAKE_PROJECT_NAME} ${GTEST_LIBRARIES} pthread)

but I keep getting linker errors because the second CMake is looking for my application as a library, not an executable:

[100%] Linking CXX executable my_project_test
/usr/bin/ld: cannot find -lmy_project: No such file or directory

I Googled for help but I could not find a simple example. There is a Google page example but it only shows the second CMake, not the first.

Could somebody please help with this?


Solution

  • The problem stems from the fact that you can’t link one executable to another executable (in this case my_app to ${CMAKE_PROJECT_NAME}_test) using target_link_libraries.
    As the name implies, this command is meant for linking libraries, not executables. That’s exactly what the linker is telling you: it’s trying to find a library called my_project, but it doesn’t exist (Since you have only built an executable with that name)

    If you still want to test code that lives in your executable, a common solution is to move the actual application code into a separate library via add_library(...).

    That way both targets use the same code, without trying to link two executables together.