Brent
Brent

Reputation: 4283

CMake "RUN_TESTS" or "test" target

In my "plange_superbuild" CMakeLists.txt, I have:

add_test(plange_test ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR}/prefix/src/plange-build --target test)

which should invoke the "plange" sub-project's test target, and works fine when using the Makefile generator. However, the CMake Testing documentation explains:

[ enable_testing() ] adds another build target, which is test for Makefile generators, or RUN_TESTS for integrated development environments (like Visual Studio).

So, my snippet doesn't work on builds with an IDE because I'm just saying "test". How can I make the command also work in IDE builds?

I've thought of some possible workaround options. One is to use an existing CMake variable, should it exist, to get the name of the test target. That is a variable (lets call it CMAKE_TEST_TARGET) that would be equal to test except in IDE builds where it would be equal to RUN_TESTS, allowing the following:

add_test(plange_test ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR}/prefix/src/plange-build --target ${CMAKE_TEST_TARGET})

I'm not aware of such a variable though. Perhaps I could detect IDE based builds via the CMAKE_GENERATOR variable (or MSVC and similar) and manually set the so-called CMAKE_TEST_TARGET variable. That would require knowing (and maintaining) the exact logic that CMake uses to determine "test" or "RUN_TESTS" in my CMakeLists.txt, which would be unreliable.

My other thought is to invoke ctest directly using a variable (let's call is CTEST_COMMAND) that's similar to CMAKE_COMMAND, but points to the ctest executable. Again, I'm not aware of such a variable.

Edit: There is CMAKE_CTEST_COMMAND See https://stackoverflow.com/a/736838/395029 and my comment therein

I derived this variable from CMAKE_COMMAND, using get_filename_component() to extract the bin directory, but this depends on CMAKE_COMMAND not having any embedded arguments. Is that a safe assumption? This works with the Makefile generator, but not with VC++2017 generator. The error message in VC++ is not clear, but here's what I tried:

get_filename_component(CMAKE_EXECUTABLES_DIR ${CMAKE_COMMAND} DIRECTORY)
set(CTEST_COMMAND "${CMAKE_EXECUTABLES_DIR}/ctest${CMAKE_EXECUTABLE_SUFFIX}")
add_test(NAME plange_test COMMAND ${CTEST_COMMAND} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/prefix/src/plange-build)

The error message in VC++2017 in the superbuild project:

1>The following tests FAILED:
1>    1 - plange_test (Failed)
1>Errors while running CTest
1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\VC\VCTargets\Microsoft.CppCommon.targets(133,5): error MSB3073: The command "setlocal
1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\VC\VCTargets\Microsoft.CppCommon.targets(133,5): error MSB3073: "C:\Program Files\CMake\bin\ctest.exe" --force-new-ctest-process -C Debug
1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\VC\VCTargets\Microsoft.CppCommon.targets(133,5): error MSB3073: if %errorlevel% neq 0 goto :cmEnd
1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\VC\VCTargets\Microsoft.CppCommon.targets(133,5): error MSB3073: :cmEnd
1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\VC\VCTargets\Microsoft.CppCommon.targets(133,5): error MSB3073: endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone
1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\VC\VCTargets\Microsoft.CppCommon.targets(133,5): error MSB3073: :cmErrorLevel
1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\VC\VCTargets\Microsoft.CppCommon.targets(133,5): error MSB3073: exit /b %1
1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\VC\VCTargets\Microsoft.CppCommon.targets(133,5): error MSB3073: :cmDone
1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\VC\VCTargets\Microsoft.CppCommon.targets(133,5): error MSB3073: if %errorlevel% neq 0 goto :VCEnd
1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\VC\VCTargets\Microsoft.CppCommon.targets(133,5): error MSB3073: :VCEnd" exited with code 8.
1>Done building project "RUN_TESTS.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 1 up-to-date, 0 skipped ==========

I was able to run the command from that error output successully:

C:\...\plange.build\prefix\src\plange-build>ctest --force-new-ctest-process -C Debug

but:

C:\...\plange.build>ctest --force-new-ctest-process -C Debug

fails, so that makes the failure even more confusing. Are one of these common practice? Is there some superior (working) approach that I haven't considered?

Edit: with CMAKE_CTEST_COMMAND I learned that "-C Debug" isn't passed, which makes it fail in IDE. See my comments

Upvotes: 3

Views: 5916

Answers (1)

ninjaconcombre
ninjaconcombre

Reputation: 534

In cmake source you can find a variable that is undocummented but may serve your purpose if you are using include(CTest) instead of enable_testing()

Check out this commit: https://github.com/Kitware/CMake/commit/816c9d1aa1f2b42d40c81a991b68c96eb12b6d26#diff-73eaa76f278a4e8afe41a9ffb838ccc4:

 # If requested, add an alias that is the equivalent of the built-in "test"
  # or "RUN_TESTS" target:
  if(CTEST_TEST_TARGET_ALIAS)
    add_custom_target(${CTEST_TEST_TARGET_ALIAS}
      ${CMAKE_CTEST_COMMAND} ${__conf_types}
      USES_TERMINAL
      )
  endif()
endif()

Meaning that if in your Cmakelist.txt you call set(CTEST_TEST_TARGET_ALIAS my_name_for_target_test) and then include(CTest), you can use reliably the my_name_for_target_test acording to this comment (I did not check myself if this really does the trick). Since this alias is created via add_custom_target, this is not a builtins target and you dont have the (really annoying) limitations of thoses, including not being able to add a dependency on it / from it.

Upvotes: 2

Related Questions