How to assign a list of values to a variable in ctest's --build-options from within an add_test() command

Sample project with what I’ve tried

cmake_minimum_required(VERSION 3.14)
project(ctest_multiple_prefixes CXX)

file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/subdir/lib.cpp" "void func(){}")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/subdir/CMakeLists.txt" "
cmake_minimum_required(VERSION 3.14)
project(subdir)
add_library(lib lib.cpp)
")

enable_testing()

set(prefixes "${CMAKE_CURRENT_BINARY_DIR};${CMAKE_CURRENT_BINARY_DIR}")
set(ctest_command_args
      --build-and-test
      "${CMAKE_CURRENT_BINARY_DIR}/subdir"
      "${CMAKE_CURRENT_BINARY_DIR}/subdir"
      --build-config "Release"
      --build-generator "${CMAKE_GENERATOR}"
      --build-makeprogram "${CMAKE_MAKE_PROGRAM}"
      --build-options "-DCMAKE_PREFIX_PATH=${prefixes}"
      --test-command ""
      )

# All broken
add_test(test1 ${CMAKE_CTEST_COMMAND} ${ctest_command_args})
add_test(NAME test2
         COMMAND ${CMAKE_CTEST_COMMAND} ${ctest_command_args}
         COMMAND_EXPAND_LISTS
    )
add_test(NAME test3
         COMMAND ${CMAKE_CTEST_COMMAND} ${ctest_command_args}
    )


# Only one prefix value, works.
set(prefixes "${CMAKE_CURRENT_BINARY_DIR}")
set(ctest_command_args
      --build-and-test
      "${CMAKE_CURRENT_BINARY_DIR}/subdir"
      "${CMAKE_CURRENT_BINARY_DIR}/subdir"
      --build-config "Release"
      --build-generator "${CMAKE_GENERATOR}"
      --build-makeprogram "${CMAKE_MAKE_PROGRAM}"
      --build-options "-DCMAKE_PREFIX_PATH=${prefixes}"
      --test-command ""
      )
add_test(test4 ${CMAKE_CTEST_COMMAND} ${ctest_command_args})

OUTPUT:

ctest -V
UpdateCTestConfiguration  from :/Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build/DartConfiguration.tcl
UpdateCTestConfiguration  from :/Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build/DartConfiguration.tcl
Test project /Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build
Constructing a list of tests
Done constructing a list of tests
Updating test list for fixtures
Added 0 tests to meet fixture requirements
Checking test dependency graph...
Checking test dependency graph end
test 1
    Start 1: test1

1: Test command: /Users/alex/Dev/cmake/build/bin/ctest "--build-and-test" "/Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build/subdir" "/Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build/subdir" "--build-config" "Release" "--build-generator" "Ninja" "--build-makeprogram" "/usr/local/bin/ninja" "--build-options" "-DCMAKE_PREFIX_PATH=/Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build" "/Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build" "--test-command"
1: Test timeout computed to be: 10000000
1: Internal cmake changing into directory: /Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build/subdir
1: ======== CMake output     ======
1: Configuring done
1: Generating done
1: CMake Warning:
1:   Manually-specified variables were not used by the project:
1:
1:     CMAKE_PREFIX_PATH
1:
1:
1: Build files have been written to: /Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build
1: ======== End CMake output ======
1: Change Dir: /Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build/subdir
1:
1: Run Clean Command:/usr/local/bin/ninja clean
1: ninja: error: loading 'build.ninja': No such file or directory
1:
1: Run Build Command(s):/usr/local/bin/ninja && ninja: error: loading 'build.ninja': No such file or directory
1:
1/4 Test #1: test1 ............................***Failed    0.05 sec
test 2
    Start 2: test2

2: Test command: /Users/alex/Dev/cmake/build/bin/ctest "--build-and-test" "/Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build/subdir" "/Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build/subdir" "--build-config" "Release" "--build-generator" "Ninja" "--build-makeprogram" "/usr/local/bin/ninja" "--build-options" "-DCMAKE_PREFIX_PATH=/Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build" "/Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build" "--test-command"
2: Test timeout computed to be: 10000000
2: Internal cmake changing into directory: /Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build/subdir
2: ======== CMake output     ======
2: Configuring done
2: Generating done
2: Build files have been written to: /Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build
2: ======== End CMake output ======
2: Change Dir: /Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build/subdir
2:
2: Run Clean Command:/usr/local/bin/ninja clean
2: ninja: error: loading 'build.ninja': No such file or directory
2:
2: Run Build Command(s):/usr/local/bin/ninja && ninja: error: loading 'build.ninja': No such file or directory
2:
2/4 Test #2: test2 ............................***Failed    0.04 sec
test 3
    Start 3: test3

3: Test command: /Users/alex/Dev/cmake/build/bin/ctest "--build-and-test" "/Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build/subdir" "/Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build/subdir" "--build-config" "Release" "--build-generator" "Ninja" "--build-makeprogram" "/usr/local/bin/ninja" "--build-options" "-DCMAKE_PREFIX_PATH=/Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build" "/Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build" "--test-command"
3: Test timeout computed to be: 10000000
3: Internal cmake changing into directory: /Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build/subdir
3: ======== CMake output     ======
3: Configuring done
3: Generating done
3: Build files have been written to: /Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build
3: ======== End CMake output ======
3: Change Dir: /Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build/subdir
3:
3: Run Clean Command:/usr/local/bin/ninja clean
3: ninja: error: loading 'build.ninja': No such file or directory
3:
3: Run Build Command(s):/usr/local/bin/ninja && ninja: error: loading 'build.ninja': No such file or directory
3:
3/4 Test #3: test3 ............................***Failed    0.04 sec
test 4
    Start 4: test4

4: Test command: /Users/alex/Dev/cmake/build/bin/ctest "--build-and-test" "/Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build/subdir" "/Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build/subdir" "--build-config" "Release" "--build-generator" "Ninja" "--build-makeprogram" "/usr/local/bin/ninja" "--build-options" "-DCMAKE_PREFIX_PATH=/Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build" "--test-command"
4: Test timeout computed to be: 10000000
4: Internal cmake changing into directory: /Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build/subdir
4: ======== CMake output     ======
4: The C compiler identification is AppleClang 11.0.3.11030032
4: The CXX compiler identification is AppleClang 11.0.3.11030032
4: Detecting C compiler ABI info
4: Detecting C compiler ABI info - done
4: Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc - skipped
4: Detecting C compile features
4: Detecting C compile features - done
4: Detecting CXX compiler ABI info
4: Detecting CXX compiler ABI info - done
4: Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ - skipped
4: Detecting CXX compile features
4: Detecting CXX compile features - done
4: Configuring done
4: Generating done
4: Build files have been written to: /Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build/subdir
4: ======== End CMake output ======
4: Change Dir: /Volumes/T3/Dev/projects/cmake/general/ctest_prefix_semicolons/build/subdir
4:
4: Run Clean Command:/usr/local/bin/ninja clean
4: [1/1] Cleaning all built files...
4: Cleaning... 0 files.
4:
4: Run Build Command(s):/usr/local/bin/ninja && [1/2] Building CXX object CMakeFiles/lib.dir/lib.cpp.o
4: [2/2] Linking CXX static library liblib.a
4:
4/4 Test #4: test4 ............................   Passed    0.44 sec

25% tests passed, 3 tests failed out of 4

Total Test time (real) =   0.58 sec

The following tests FAILED:
	  1 - test1 (Failed)
	  2 - test2 (Failed)
	  3 - test3 (Failed)
Errors while running CTest

Note that in the first 3 tests, -DCMAKE_PREFIX_PATH has 2 values, and this ends up breaking the ctest invocation because the second value is considered as a standalone command line argument.

The 4th test has only one value, and thus the test succeeds.

Could you use -C to pass an initial cache preload script instead of passing the option(s) using -D?

Not sure if this is supported or would work, but you could also try replacing semi-colons in ${prefixes} with the $<SEMICOLON> generator expression.

Thanks for the suggestions!

$<SEMICOLON> did actually work.

I also noticed the test works with my original code, if I don’t use a ctest_command_args variable, but rather directly specify the arguments in the add_test command. I suppose that avoids one layer of variable expansion.

What I actually ended up using (before your $<SEMICOLON> suggestion) was the unsupported “escape semicolon” trick.

string(REPLACE ";" "\;" prefixes "${prefixes}")

I guess passing -C would work as well.

1 Like