J. D.
J. D.

Reputation: 279

CMake unit structure with many tests

I would like to set up cmake to run on a project with unit testing. The project structure is as follows:

|---CMakeLists.txt
|---build
|---source
|   |---CMakeLists.txt
|   |---many .cpp and .h files
|---tests
|   |---CMakeLists.txt
|   |---many .cpp files

The source files in tests use Boost unit_test.h library.

My outer CMakeLists.txt is as follows:

cmake_minimum_required(VERSION 2.8.11)

set(CMAKE_CXX_FLAGS "-std=c++11")

project(MyProject CXX)
add_subdirectory(source)
add_subdirectory(tests)
enable_testing()

The CMakeLists.txt in the source folder is:

file( GLOB LIB_SOURCES *.cpp )
file( GLOB LIB_HEADERS *.h )
add_library( MyProject_lib ${LIB_SOURCES} ${LIB_HEADERS} )

And the CMakeLists.txt in the tests folder is:

# require old policy to allow for source files containing the name "test"
cmake_policy(SET CMP0037 OLD)
# Locate Boost libraries: unit_test_framework, date_time and regex
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
find_package(Boost 1.59 REQUIRED COMPONENTS unit_test_framework date_time regex)

include_directories("${CMAKE_SOURCE_DIR}/source" ${Boost_INCLUDE_DIRS})

file(GLOB APP_SOURCES *.cpp)
foreach(testsourcefile ${APP_SOURCES})
    string(REPLACE ".cpp" "" testname ${testsourcefile})
    add_executable(${testname} ${testsourcefile})
    target_link_libraries(${testname} LINK_PUBLIC ${Boost_LIBRARIES} MyProject_lib)
    add_custom_target(targetname)
    add_custom_command(TARGET targetname POST_BUILD COMMAND ${testname})
endforeach(testsourcefile ${APP_SOURCES})

If I comment the lines with add_custom_target and add_custom_command, the result of this configuration is that the library is correctly built and linked, but none of the tests is compiled.

If I do not comment the two lines with add_custom_target and add_custom_command, The error I get by running cmake is:

CMake Error at tests/CMakeLists.txt:25 (add_custom_target):
add_custom_target cannot create target "targetname" because another target
with the same name already exists.  The existing target is a custom target
created in source directory "/tests".  See
documentation for policy CMP0002 for more details.

Since I have a large number of tests, listing them one by one is not practical. I would like to have cmake to find all the .cpp files, as done for the library in the source folder, compile and run them.

Upvotes: 1

Views: 1965

Answers (1)

Rene
Rene

Reputation: 2466

This is the solution I use in my library:

FILE( GLOB log_testprograms *.cpp )

FOREACH( testsource ${log_testprograms} )
   GET_FILENAME_COMPONENT( filename ${testsource} NAME_WE )
   celma_add_celma_boost_testprogram( ${filename} )
ENDFOREACH()

celma_add_celma_boost_testprogram is a macro like this:

macro( celma_add_celma_boost_testprogram  filename )
   add_executable(        ${filename}  ${filename}.cpp )
   target_link_libraries( ${filename}  celma ${Boost_Test_Link_Libs} )
   add_test(              ${filename}  ${CMAKE_CURRENT_BINARY_DIR}/${filename} )
endmacro( celma_add_celma_boost_testprogram )

Celma is the name of my library, the variable Boost_Test_Link_Libs contains the list of Boost libraries to link against, including the Boost.Test library.

Upvotes: 1

Related Questions