Reputation: 12510
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):
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
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
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
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