I have a project which is basically a library DLL and some test code for the DLL. It is structured with a top level directory a subdirectory for the library code and a subdirectory for the test code.
When I run the tests in my IDE they fail because the DLL is not in the same subdirectory as the test executable. To get around this I tried to use some CMake magic which doesn't work, contrary to the documentation.
My magic works as follows:
CMakelists.txt in library subdirectory to copy DLL up to the top level so that the test code (and in future, applications that use the DLL) can always find it in a consistent place:
add_custom_command(
OUTPUT "${CMAKE_BINARY_DIR}/my.dll"
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_BINARY_DIR}/my.dll" "${CMAKE_BINARY_DIR}/my.dll"
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/my.dll"
)
add_custom_target(export_my_dll
DEPENDS "${CMAKE_BINARY_DIR}/my.dll"
)
This all works and I see in the build output that the targets are built, and the output file is up to date.
CMakelists.txt in tests subdirectory to copy DLL down from the top level:
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/my.dll"
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_BINARY_DIR}/my.dll" "${CMAKE_CURRENT_BINARY_DIR}/my.dll"
DEPENDS export_my_dll
)
add_custom_target(dlls_for_tests
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/my.dll"
)
add_dependencies(tests dlls_for_tests)
"tests" is the target for my test executable. The build output says it builds the "dlls_for_tests" target, but the DLL is not up to date in the binary directory for the tests executable - the tests executable is using an old outdated DLL.
The build output (QtCreator) looks like:
...
[ 75%] Generating ../my.dll
[ 79%] Built target export_my_dll
[ 82%] Built target dlls_for_tests
Scanning dependencies of target SpectreCtrl_Tests
[ 89%] Building CXX object project/tests/CMakeFiles/tests.dir/test_func.cpp.obj
[ 94%] Linking CXX executable tests.exe
[ 100%] Built target tests
I have two questions:
1) Why doesn't this work?
2) Is there a better way to do this that avoids copying the DLl when it hasn't changed or just that is easier to read?
===============
I have found two ways that work, but I don't much like either:
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/my.dll"
COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_FILE:my_dll>" "${CMAKE_CURRENT_BINARY_DIR}"
DEPENDS "$<TARGET_FILE:my_dll>"
)
add_custom_target(dlls_for_test
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/my.dll"
)
add_dependencies(tests dlls_for_test)
This explicitly uses the file name - you need to get it right and if you change the target name of the library (and hence the library name) this will break. Hopefully it will skip the copy if the DLL didn't change.
add_custom_target(dlls_for_tests
COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_FILE:my_dll>" "${CMAKE_CURRENT_BINARY_DIR}"
)
add_dependencies(tests dlls_for_tests)
This is much shorter and sweeter, but it will always copy the DLL even if it didn't change.