malat
malat

Reputation: 12510

How to integrate CTest with Visual Studio?

I have been following the guide from:

However I fail to understand how to integrate the ctest mechanism in Visual Studio 2019. Right now my shared library (dll) is not found upon execution (only on Windows):

enter image description here

Here is the simple project setup:

> cat .\CMakeLists.txt
cmake_minimum_required (VERSION 3.8)
project (p LANGUAGES C)
set(CMAKE_C_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)
add_subdirectory ("src")
enable_testing()
add_subdirectory ("tests")

And then src is simply:

> cat .\src\CMakeLists.txt
add_library(foo SHARED foo.c foo.h)
target_include_directories(
  foo PUBLIC $<BUILD_INTERFACE:${p_SOURCE_DIR}/src>
)

finally tests is:

> cat .\tests\CMakeLists.txt
add_executable(footest footest.c)
target_link_libraries(footest PRIVATE foo)
add_test(NAME footest COMMAND footest)

Running the above under WSL works as expected:

$ make && make test
[ 50%] Built target foo
[100%] Built target footest
Running tests...
Test project /mnt/c/Users/malat/CMakeProject1/bin-gcc
    Start 1: footest
1/1 Test #1: footest ..........................   Passed    0.01 sec

100% tests passed, 0 tests failed out of 1

Total Test time (real) =   0.03 sec

Upvotes: 1

Views: 485

Answers (3)

Alex Reinking
Alex Reinking

Reputation: 20016

As of CMake 3.27, you should use the TARGET_RUNTIME_DLL_DIRS generator expression, along with the ENVIRONMENT_MODIFICATION test property to set up your tests for running, rather than by copying the DLLs anywhere.

To do this, simply add the following code to your tests\CMakeLists.txt file:

set_tests_properties(
    footest
    PROPERTIES
    ENVIRONMENT_MODIFICATION "PATH=path_list_append:$<TARGET_RUNTIME_DLL_DIRS:footest>"
)

On non-DLL platforms, this will do nothing, as intended. On those platforms, RPATH takes over.

This improves on Corristo's answer by not requiring updates when you add dependencies to your tests. It also works with IMPORTED targets. It also avoids issues with setting CMAKE_RUNTIME_OUTPUT_DIRECTORY in FetchContent scenarios.

Upvotes: 2

malat
malat

Reputation: 12510

A modern approach to this issue seems to TARGET_RUNTIME_DLLS:

Documentation suggest to use:

find_package(foo CONFIG REQUIRED) # package generated by install(EXPORT)

add_executable(exe main.c)
target_link_libraries(exe PRIVATE foo::foo foo::bar)
add_custom_command(TARGET exe POST_BUILD
  COMMAND ${CMAKE_COMMAND} -E copy -t $<TARGET_FILE_DIR:exe> $<TARGET_RUNTIME_DLLS:exe>
  COMMAND_EXPAND_LISTS
)

Watch out that the -t flag which seems to have been introduced lately.

Reference:


When using Visual Studio 2019, you may need to change the default cmake version used:

Upvotes: -1

Corristo
Corristo

Reputation: 5520

In contrast to Linux where additional search paths for libraries can be embedded into an executable (via RPATH or RUNPATH), on Windows the only places the loader looks for .dll files is next to the executable, in directories in the PATH environment variable and in C:\System32.

So in order for the test executable to find foo.dll you either need to ensure that they are located in the same directory, or add the directory the library is in to the PATH when running the tests.

You can have CMake put them into the same directory by setting the RUNTIME_OUTPUT_DIRECTORY property, which is initialized to the value of the CMAKE_RUNTIME_OUTPUT_DIRECTORY variable. If you set that variable before the first target is defined then both the .dll and the .exe will end up in the same directory. For example, you can add

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" CACHE PATH "")

to the top-level CMakeLists.txt file before the add_subdirectory ("src") call.

Alternatively, you can modify the PATH variable when running the tests. This can also be necessary if your test depends on libraries that aren't built by your project, where setting CMAKE_RUNTIME_OUTPUT_DIRECTORY alone won't be sufficient. To do so, with CMake 3.22 and later you can set the ENVIRONMENT_MODIFICATION property on the test after the add_test call:

set_tests_properties(footest
  PROPERTIES
    ENVIRONMENT_MODIFICATION "PATH=path_list_append:$<TARGET_FILE_DIR:foo>"
)

Upvotes: 0

Related Questions