CMake files to build main and tests separately

Viewed 246

I have the following directory structure:

main.cpp
CMakeLists.txt
src/
    some_function.h
    some_function.cpp
    some_class.h
    some_class.cpp
    CMakeLists.txt
test/
    catch.hpp
    tests.cpp 
    CMakeLists.txt

CmakeLists.txt in the project root:

cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 11) # C++11

project(main)

add_subdirectory (src)

add_executable(main main.cpp)

target_link_libraries (main some_class)

CmakeLists.txt in the src/:

add_library (some_class some_class.h some_class.cpp some_function.h some_function.cpp)

The above works to build and run the main target.

Now I want to build and run tests. The file tests.cpp includes some_function.h and some_class.h. However, I am not sure how to add the src/ directory here.

This is what I have so far in test/ (results in a linking error for the function in some_function.h):

cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 11) # C++11

project(tests)

set(CATCH_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
add_library(Catch INTERFACE)
target_include_directories(Catch INTERFACE ${CATCH_INCLUDE_DIR})

add_executable(tests tests.cpp)
target_link_libraries(tests Catch)
2 Answers

Just link the some_class library target to the tests target, like you did with the main executable target.

CmakeLists.txt in the project root:

cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 11) # C++11

project(main)

add_subdirectory (src)
# Add the test sub-directory also.
add_subdirectory(test)

add_executable(main main.cpp)

target_link_libraries (main some_class)

CmakeLists.txt in the test directory:

project(tests)

set(CATCH_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
add_library(Catch INTERFACE)
target_include_directories(Catch INTERFACE ${CATCH_INCLUDE_DIR})

add_executable(tests tests.cpp)
# Link 'some_class' here also!
target_link_libraries(tests PRIVATE some_class Catch)

Normal targets created by add_library() or add_executable() have the scope of the project not the directory that's why their name must be unique within the project. So you can "target_link" some_class to your target tests even if target tests is not in a subdirectory of src/...

The <name> corresponds to the logical target name and must be globally unique within a project.

ref: https://cmake.org/cmake/help/latest/command/add_library.html#normal-libraries

This is not the case for imported targets.

The [imported] target name has scope in the directory in which it is created and below, but the GLOBAL option extends visibility. It may be referenced like any target built within the project.

ref: https://cmake.org/cmake/help/latest/command/add_library.html#imported-libraries

Related