CMake: how to add Boost.Test examples with relative directories?

I have a working project with CMake and Boost.Test with this directory structure (pardon the ASCII art):

+-proj |---CMakeLists.txt |---build |---test |\----dir1 | \----foo.cpp // contains one BOOST_AUTO_TEST_SUITE and several BOOST_AUTO_TEST_CASE | |---bar.cpp // contains one BOOST_AUTO_TEST_SUITE and several BOOST_AUTO_TEST_CASE \----dir2 \----foo.cpp // contains one BOOST_AUTO_TEST_SUITE and several BOOST_AUTO_TEST_CASE |---bar.cpp // contains one BOOST_AUTO_TEST_SUITE and several BOOST_AUTO_TEST_CASE 

I am currently compiling all of the source files into one large executable, which I can run using CTest. My CMakeLists.txt looks like this:

 file(GLOB_RECURSE test_cases FOLLOW_SYMLINKS "test/*.[h,c]pp") add_executable(test_suite ${test_cases}) include_directories(${PROJECT_SOURCE_DIR} ${Boost_INCLUDE_DIRS}) target_link_libraries(test_suite ${Boost_LIBRARIES}) include(CTest) add_test(test_runner test_suite) 

I would like to compile each .cpp file into a separate executable file and add it separately as a test, so that I can use CTest regex hardware (especially the test exception, which Boost.Test does not seem to have) to selectively run certain tests. However, I get a name conflict when CMake generates build targets for foo / bar from dir1 / dir2.

My question is : how can I mirror the entire directory tree in test to a similar tree under build so that there are more name conflicts between different executables and so CTest can run them all?

Note : renaming them in the source tree is not an option. I would like to do foreach() on the variable ${test_cases} (as explained in this answer ), but I find it difficult to extract the relative directory and file name and port them to the build/ directory for each file.

UPDATE . At the end, I compiled this script:

 # get the test sources file(GLOB_RECURSE test_sources RELATIVE ${PROJECT_SOURCE_DIR} *.cpp) # except any CMake generated sources under build/ string(REGEX REPLACE "build/[^;]+;?" "" test_sources "${test_sources}") # get the test headers file(GLOB_RECURSE test_headers RELATIVE ${PROJECT_SOURCE_DIR} *.hpp) # except any CMake generated headers under build/ string(REGEX REPLACE "build/[^;]+;?" "" test_headers "${test_headers}") # compile against the test headers, the parent project, and the Boost libraries include_directories(${PROJECT_SOURCE_DIR} ${ParentProject_include_dirs} ${Boost_INCLUDE_DIRS}) # calls enable_testing() include(CTest) foreach(t ${test_sources} ) # get the relative path in the source tree get_filename_component(test_path ${t} PATH) # get the source name without extension get_filename_component(test_name ${t} NAME_WE) # concatenate the relative path and name in an underscore separated identifier string(REPLACE "/" "_" test_concat "${test_path}/${test_name}") # strip the leading "test_" part from the test ID string(REGEX REPLACE "^test_" "" test_id ${test_concat}) # depend on the current source file, all the test headers, and the parent project headers add_executable(${test_id} ${t} ${test_headers} ${ParentProject_headers}) # link against the Boost libraries target_link_libraries(${test_id} ${Boost_LIBRARIES}) # match the relative path in the build tree with the corresponding one in the source tree set_target_properties(${test_id} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${test_path}) # add a test with executable in the relative path of the build tree add_test(${test_id} ${test_path}/${test_id}) endforeach() 
+5
c ++ boost cmake ctest boost-test
May 31 '13 at 12:39
source share
2 answers

You can specify the RELATIVE flag and the directory for the file( GLOB ... ) command file( GLOB ... ) . Although this is not mentioned directly in the file documentation (GLOB) , it works for file( GLOB_RECURSE ... ) . Notice, I tested this when setting up my windows. I do not know about * nix.

  • Along with some get_filename_component calls using NAME_WE and / or PATH , you can now restore the name and relative path of the cpp file to the nail dir.
  • Retrieving the path and name (without extension) is basically similar to Massimiliano's answer . In addition, I used his suggestion to create a unique name test with string( REGEX REPLACE ... ) ; replacing slashes with underscores.
  • With a unique test name, an executable file can be generated, and then its output directory can be changed using set_target_properties .

Check this and this question for more information on changing 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} ) 
+3
Jun 03 '13 at 8:05
source share

A possible solution to disambiguating names in a directory structure similar to the one you use with FOREACH() over ${test_cases} might 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 different test / executable pairs.

+4
Jun 03 '13 at 6:13
source share



All Articles