I have a working project with CMake and Boost.Test with a directory structure like this (pardon the ASCII art):
+-proj
|---CMakeLists.txt
|---build
|---test
It is possible to specify a RELATIVE
flag and a directory to a file( GLOB ... )
command. Although not mentioned directly in the documentation of file( GLOB ), this works for file( GLOB_RECURSE ... )
too. Note, I tested this on my windows setup. I don't known about *nix.
NAME_WE
and/or PATH
flags, it is now possible to reconstruct the name and
the relative path of the cpp-file with respect to the globbing dir.string( REGEX REPLACE ... )
;
replacing forward slashes by underscores.Check this and this question for more info on modifying the output directory.
file( GLOB_RECURSE TEST_CPP_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp )
foreach( test_case ${TEST_CPP_SOURCES} )
# Get the name without extension
get_filename_component( test_name ${test_case} NAME_WE )
# Get the path to the test-case, relative to the ${CMAKE_CURRENT_SOURCE_DIR}
# thanks to the RELATIVE flag in file( GLOB_RECURSE ... )
get_filename_component( test_path ${test_case} PATH )
message( STATUS " name = " ${test_name} )
message( STATUS " path = " ${test_path} )
# I would suggests constructing a 'unique' test-name
string( REPLACE "/" "_" full_testcase "${test_name}/${test_path}" )
# Add an executable using the 'unique' test-name
message( STATUS " added " ${full_testcase} " in " ${test_path} )
add_executable( ${full_testcase} ${test_case} )
# and modify its output paths.
set_target_properties( ${full_testcase} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${test_path} )
endforeach( test_case ${TEST_CPP_SOURCES} )
A possible solution to disambiguate names in a directory structure like the one you have using a FOREACH()
over ${test_cases}
may be:
# Set Cmake version and policy
CMAKE_MINIMUM_REQUIRED( VERSION 2.8.7 )
CMAKE_POLICY( VERSION 2.8.7 )
PROJECT( DUMMY CXX )
FILE( GLOB_RECURSE test_cases FOLLOW_SYMLINKS "test/*.[h,c]pp" )
FOREACH( case ${test_cases} )
## Get filename without extension
GET_FILENAME_COMPONENT(case_name_we ${case} NAME_WE)
## Get innermost directory name
GET_FILENAME_COMPONENT(case_directory ${case} PATH)
GET_FILENAME_COMPONENT(case_innermost ${case_directory} NAME_WE)
## Construct executable name
SET( exe_name "${case_innermost}_${case_name_we}")
## Construct test name
SET( test_name "${exe_name}_test")
## Add executable and test
ADD_EXECUTABLE( ${exe_name} ${case} )
ADD_TEST( ${test_name} ${exe_name} )
ENDFOREACH()
As you can see this CMakeLists.txt
creates 4 distinct test/executable couples.