c++ - rutas - CMake: ¿cómo agregar casos de Boost.Test con directorios relativos?
rutas relativas php (2)
Tengo un proyecto en funcionamiento con CMake y Boost.Test con una estructura de directorios como esta (perdón por el arte ASCII):
+-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
Actualmente compilo todos los archivos fuente en un gran ejecutable que puedo ejecutar con CTest. Mi CMakeLists.txt se ve así:
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)
Me gustaría compilar cada archivo .cpp en un archivo ejecutable independiente, y agregarlo por separado como una prueba para que pueda usar la maquinaria de expresión regular CTest (especialmente la exclusión de prueba que Boost.Test no parece tener) para ejecutar selectivamente ciertas pruebas Sin embargo, aparece un conflicto de nombre cuando CMake genera objetivos de compilación para foo / bar desde dir1 / dir2.
Mi pregunta es : ¿cómo puedo reflejar todo el árbol de directorios bajo test
en un árbol similar bajo build
para que no haya más conflictos de nombres entre los diversos ejecutables y para que CTest pueda ejecutarlos todos?
Nota : Renombrarlos en el árbol fuente no es una opción. Me gustaría hacer un foreach()
sobre la variable ${test_cases}
(como se explica en esta respuesta ), pero estoy teniendo problemas para extraer el directorio relativo y el nombre del archivo, y llevarlos a la build/
directorio en un archivo por archivo.
ACTUALIZACIÓN : al final, reconstruí este guión:
# 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()
Una posible solución para FOREACH()
nombres en una estructura de directorios como la que tiene utilizando un FOREACH()
sobre ${test_cases}
puede ser:
# 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()
Como puede ver, este CMakeLists.txt
crea 4 parejas distintas de prueba / ejecutable.
Es posible especificar un indicador RELATIVE
y un directorio para un comando de file( GLOB ... )
. Aunque no se menciona directamente en la documentación del archivo (GLOB) , esto también funciona para el file( GLOB_RECURSE ... )
. Tenga en cuenta que probé esto en mi configuración de Windows. No sé sobre * nix.
- Junto con algunas llamadas get_filename_component con
NAME_WE
y / o banderasPATH
, ahora es posible reconstruir el nombre y la ruta relativa del archivo cpp con respecto al directorio globbing. - La extracción de un camino y un nombre (sin extensión) es en su mayoría similar a la respuesta de Massimiliano . Además, he usado su sugerencia para generar un nombre de prueba único con una
string( REGEX REPLACE ... )
; reemplazando barras diagonales por guiones bajos. - Con un nombre de prueba único, el ejecutable se puede generar y luego su directorio de salida se puede modificar con set_target_properties .
Verifique esto y esta pregunta para obtener más información sobre cómo modificar el directorio de salida.
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} )