Initial Situation
Say I have a project named kitten. For this project I need to link an external, shared library meow with either no or bad/ancient CMake support. For some reason I decide to not simply make adjusted rules for linking and copying the required files for this very project, but rather want to create an independent CMake file for reuse, sharing or just because I like to keep things tidy.
Aim
Basically this:
include(cmake/meow.cmake)
add_executable(kitten kitten.cpp)
target_link_libraries(kitten meow)
Then I want to be able to build kitten and run it from the build directory. My IDE, VS Code, runs it automatically from the build directory so I assume it is commonly expected to work this way.
Challenges
- Add meow's include directory to the include path. ✔
- Link the static part of meow (
meow.lib
/meow.a
). ✔ - Use the correct library configuration (
DEBUG
orRELEASE
). ✔ - Make sure the shared part of meow (
meow.dll
/meow.so
) is found when executing kitten in the build directory. ❌
Solution Approach
Challenge 1 to 3 are no problem. In my meow.cmake
I just put:
add_library(meow SHARED IMPORTED)
target_include_directories(meow INTERFACE "${MEOW_DIR}/include")
set_target_properties(meow PROPERTIES
# set location of DLL/SO files depending on the configuration
IMPORTED_LOCATION "${MEOW_DIR}/bin/Release/meow${CMAKE_SHARED_MODULE_SUFFIX}"
IMPORTED_LOCATION_DEBUG "${MEOW_DIR}/bin/Debug/meow_d${CMAKE_SHARED_MODULE_SUFFIX}"
# set location of LIB/A files depending on the configuration
IMPORTED_IMPLIB "${MEOW_DIR}/lib/Release/meow${CMAKE_IMPORT_LIBRARY_SUFFIX}"
IMPORTED_IMPLIB_DEBUG "${MEOW_DIR}/lib/Debug/meow_d${CMAKE_IMPORT_LIBRARY_SUFFIX}"
IMPORTED_CONFIGURATIONS "RELEASE;DEBUG"
)
Challenge 4, however, I am struggling with. I don't even know if CMake supports the idea of executing the executable in the build directory or if the proper way is installing the target first. Or maybe this use case is so uncommon or irrelevant that nobody bothered to make it handlable? Or maybe I just haven't figured out yet, how to do this?
I have come up with the following messy idea and it just needs one detail fixed to be working as expected, but all in all I find the whole procedure a bit tedious for just two or three files to link and copy, which is why I'm asking here for the proper way, if there is any.
add_custom_target(meow-copy
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"$<TARGET_FILE:meow>" # this automatically points to the right DLL/SO
"${CMAKE_CURRENT_BINARY_DIR}" # PROBLEM: this points to the build root
)
add_library(meow-autocopy INTERFACE)
target_link_libraries(meow-autocopy INTERFACE meow)
add_dependencies(meow-autocopy meow-copy)
(I would need target_link_libraries(kitten meow-autocopy)
in this case to get the auto-copying.)
The problem here is that CMAKE_CURRENT_BINARY_DIR
does point to the build root (e.g. ./build
), the executable will be stored in ./build/Debug
or ./build/Release
respectively or even in a subdirectory, if the targets are sorted into subdirectories (which they usually are in my projects).