@@ -38,6 +38,7 @@ same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
3838 [OUTPUT_PREFIX prefix]
3939 [OUTPUT_SUFFIX suffix]
4040 [DISCOVERY_MODE <POST_BUILD|PRE_TEST>]
41+ [USE_RELATIVE_PATHS]
4142 [SKIP_IS_FAILURE]
4243 [ADD_TAGS_AS_LABELS]
4344 )
@@ -157,6 +158,12 @@ same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
157158 code-signs the test executable only after the post-build script that
158159 ``POST_BUILD`` mode uses to run it for test discovery. See Catch2 issue #2411.
159160
161+ ``USE_RELATIVE_PATHS``
162+ Makes the files generated for ``PRE_TEST`` discovery use paths relative to
163+ the generated CTest include file. This allows a build tree to be relocated
164+ with its test executable before test discovery runs. This option requires
165+ CMake 3.24 or newer.
166+
160167 ``SKIP_IS_FAILURE``
161168 Disables skipped test detection.
162169
@@ -170,7 +177,7 @@ function(catch_discover_tests TARGET)
170177
171178 cmake_parse_arguments (
172179 ""
173- "SKIP_IS_FAILURE;ADD_TAGS_AS_LABELS"
180+ "SKIP_IS_FAILURE;ADD_TAGS_AS_LABELS;USE_RELATIVE_PATHS "
174181 "TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST;REPORTER;OUTPUT_DIR;OUTPUT_PREFIX;OUTPUT_SUFFIX;DISCOVERY_MODE"
175182 "TEST_SPEC;EXTRA_ARGS;PROPERTIES;DL_PATHS;DL_FRAMEWORK_PATHS"
176183 ${ARGN}
@@ -201,6 +208,12 @@ function(catch_discover_tests TARGET)
201208 if (NOT _DISCOVERY_MODE MATCHES "^(POST_BUILD|PRE_TEST)$" )
202209 message (FATAL_ERROR "Unknown DISCOVERY_MODE: ${_DISCOVERY_MODE} " )
203210 endif ()
211+ if (_USE_RELATIVE_PATHS AND NOT _DISCOVERY_MODE STREQUAL "PRE_TEST" )
212+ message (FATAL_ERROR "USE_RELATIVE_PATHS requires DISCOVERY_MODE PRE_TEST" )
213+ endif ()
214+ if (_USE_RELATIVE_PATHS AND CMAKE_VERSION VERSION_LESS "3.24" )
215+ message (FATAL_ERROR "USE_RELATIVE_PATHS requires CMake 3.24 or newer" )
216+ endif ()
204217
205218 ## Generate a unique name based on the extra arguments
206219 string (SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS} ${_REPORTER} ${_OUTPUT_DIR} ${_OUTPUT_PREFIX} ${_OUTPUT_SUFFIX} " )
@@ -210,6 +223,7 @@ function(catch_discover_tests TARGET)
210223 set (ctest_file_base "${CMAKE_CURRENT_BINARY_DIR } /${TARGET} -${args_hash} " )
211224 set (ctest_include_file "${ctest_file_base} _include.cmake" )
212225 set (ctest_tests_file "${ctest_file_base} _tests.cmake" )
226+ set (ctest_include_file_for_property "${ctest_include_file} " )
213227
214228 get_property (crosscompiling_emulator
215229 TARGET ${TARGET}
@@ -264,16 +278,69 @@ function(catch_discover_tests TARGET)
264278 set (ctest_tests_file "${ctest_file_base} _tests-$<CONFIG >.cmake" )
265279 endif ()
266280
281+ set (test_executable_for_script "$<TARGET_FILE :${TARGET} >" )
282+ set (test_working_dir_for_script "${_WORKING_DIRECTORY} " )
283+ set (discover_tests_script_for_script "${_CATCH_DISCOVER_TESTS_SCRIPT} " )
284+ set (ctest_tests_file_for_script "${ctest_tests_file} " )
285+ set (test_executable_argument "[==[${test_executable_for_script} ]==]" )
286+ set (test_working_dir_argument "[==[${test_working_dir_for_script} ]==]" )
287+ set (ctest_file_argument "[==[${ctest_tests_file_for_script} ]==]" )
288+ set (ctest_path_setup)
289+ set (ctest_config_include_file
290+ "${ctest_file_base} _include-\$ {CTEST_CONFIGURATION_TYPE}.cmake"
291+ )
292+
293+ if (_USE_RELATIVE_PATHS)
294+ get_filename_component (ctest_file_base_name "${ctest_file_base} " NAME )
295+ get_filename_component (ctest_tests_file_name "${ctest_tests_file} " NAME )
296+ get_filename_component (ctest_include_file_name "${ctest_include_file} " NAME )
297+
298+ set (test_executable_relative
299+ "$<PATH :RELATIVE_PATH ,$<TARGET_FILE :${TARGET} >,${CMAKE_CURRENT_BINARY_DIR } >"
300+ )
301+ set (test_working_dir_relative
302+ "$<PATH :RELATIVE_PATH ,$<PATH :ABSOLUTE_PATH ,${_WORKING_DIRECTORY} ,${CMAKE_CURRENT_BINARY_DIR } >,${CMAKE_CURRENT_BINARY_DIR } >"
303+ )
304+ set (discover_tests_script_name
305+ "${ctest_file_base_name} _CatchAddTests.cmake"
306+ )
307+ configure_file (
308+ "${_CATCH_DISCOVER_TESTS_SCRIPT} "
309+ "${CMAKE_CURRENT_BINARY_DIR } /${discover_tests_script_name} "
310+ COPYONLY
311+ )
312+
313+ set (ctest_config_include_file
314+ "${ctest_file_base_name} _include-\$ {CTEST_CONFIGURATION_TYPE}.cmake"
315+ )
316+ string (CONCAT ctest_path_setup
317+ "get_filename_component(_catch_discover_tests_script \" ${discover_tests_script_name} \" REALPATH)" "\n "
318+ "get_filename_component(_catch_discovery_dir \"\$ {_catch_discover_tests_script}\" DIRECTORY)" "\n "
319+ "set(_catch_test_executable \"\$ {_catch_discovery_dir}/${test_executable_relative} \" )" "\n "
320+ "set(_catch_test_working_dir \"\$ {_catch_discovery_dir}/${test_working_dir_relative} \" )" "\n "
321+ "set(_catch_tests_file \"\$ {_catch_discovery_dir}/${ctest_tests_file_name} \" )" "\n "
322+ )
323+ set (test_executable_for_script "\$ {_catch_test_executable}" )
324+ set (test_working_dir_for_script "\$ {_catch_test_working_dir}" )
325+ set (discover_tests_script_for_script "\$ {_catch_discover_tests_script}" )
326+ set (ctest_tests_file_for_script "\$ {_catch_tests_file}" )
327+ set (test_executable_argument "\"\$ {_catch_test_executable}\" " )
328+ set (test_working_dir_argument "\"\$ {_catch_test_working_dir}\" " )
329+ set (ctest_file_argument "\"\$ {_catch_tests_file}\" " )
330+ set (ctest_include_file_for_property "${ctest_include_file_name} " )
331+ endif ()
332+
267333 string (CONCAT ctest_include_content
268- "if(EXISTS \" $<TARGET_FILE :${TARGET} >\" )" "\n "
269- " if(NOT EXISTS \" ${ctest_tests_file} \" OR" "\n "
270- " NOT \" ${ctest_tests_file} \" IS_NEWER_THAN \" $<TARGET_FILE :${TARGET} >\" OR\n "
271- " NOT \" ${ctest_tests_file} \" IS_NEWER_THAN \"\$ {CMAKE_CURRENT_LIST_FILE}\" )\n "
272- " include(\" ${_CATCH_DISCOVER_TESTS_SCRIPT} \" )" "\n "
334+ "${ctest_path_setup} "
335+ "if(EXISTS \" ${test_executable_for_script} \" )" "\n "
336+ " if(NOT EXISTS \" ${ctest_tests_file_for_script} \" OR" "\n "
337+ " NOT \" ${ctest_tests_file_for_script} \" IS_NEWER_THAN \" ${test_executable_for_script} \" OR\n "
338+ " NOT \" ${ctest_tests_file_for_script} \" IS_NEWER_THAN \"\$ {CMAKE_CURRENT_LIST_FILE}\" )\n "
339+ " include(\" ${discover_tests_script_for_script} \" )" "\n "
273340 " catch_discover_tests_impl(" "\n "
274- " TEST_EXECUTABLE" " [==[" "$< TARGET_FILE : ${TARGET} > " "]==]" "\n "
341+ " TEST_EXECUTABLE" " ${test_executable_argument} " "\n "
275342 " TEST_EXECUTOR" " [==[" "${crosscompiling_emulator} " "]==]" "\n "
276- " TEST_WORKING_DIR" " [==[" " ${_WORKING_DIRECTORY } " "]==]" "\n "
343+ " TEST_WORKING_DIR" " ${test_working_dir_argument } " "\n "
277344 " TEST_SPEC" " [==[" "${_TEST_SPEC} " "]==]" "\n "
278345 " TEST_EXTRA_ARGS" " [==[" "${_EXTRA_ARGS} " "]==]" "\n "
279346 " TEST_PROPERTIES" " [==[" "${_PROPERTIES} " "]==]" "\n "
@@ -284,13 +351,13 @@ function(catch_discover_tests TARGET)
284351 " TEST_OUTPUT_DIR" " [==[" "${_OUTPUT_DIR} " "]==]" "\n "
285352 " TEST_OUTPUT_PREFIX" " [==[" "${_OUTPUT_PREFIX} " "]==]" "\n "
286353 " TEST_OUTPUT_SUFFIX" " [==[" "${_OUTPUT_SUFFIX} " "]==]" "\n "
287- " CTEST_FILE" " [==[" " ${ctest_tests_file } " "]==]" "\n "
354+ " CTEST_FILE" " ${ctest_file_argument } " "\n "
288355 " TEST_DL_PATHS" " [==[" "${_DL_PATHS} " "]==]" "\n "
289356 " TEST_DL_FRAMEWORK_PATHS" " [==[" "${_DL_FRAMEWORK_PATHS} " "]==]" "\n "
290357 " ADD_TAGS_AS_LABELS" " [==[" "${_ADD_TAGS_AS_LABELS} " "]==]" "\n "
291358 " )" "\n "
292359 " endif()" "\n "
293- " include(\" ${ctest_tests_file } \" )" "\n "
360+ " include(\" ${ctest_tests_file_for_script } \" )" "\n "
294361 "else()" "\n "
295362 " add_test(${TARGET} _NOT_BUILT ${TARGET} _NOT_BUILT)" "\n "
296363 "endif()" "\n "
@@ -304,7 +371,7 @@ function(catch_discover_tests TARGET)
304371 "if(NOT CTEST_CONFIGURATION_TYPE)" "\n "
305372 " message(\" No configuration for testing specified, use '-C <cfg>'.\" )" "\n "
306373 "else()" "\n "
307- " include(\" ${ctest_file_base} _include- \$ {CTEST_CONFIGURATION_TYPE}.cmake \ " )" "\n "
374+ " include(\" ${ctest_config_include_file} \ " )" "\n "
308375 "endif()" "\n "
309376 )
310377 file (GENERATE OUTPUT "${ctest_include_file} " CONTENT "${ctest_include_multi_content} " )
@@ -316,7 +383,7 @@ function(catch_discover_tests TARGET)
316383
317384 # Add discovered tests to directory TEST_INCLUDE_FILES
318385 set_property (DIRECTORY
319- APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file } "
386+ APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file_for_property } "
320387 )
321388
322389endfunction ()
0 commit comments