0

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

  1. Add meow's include directory to the include path. ✔
  2. Link the static part of meow (meow.lib/meow.a). ✔
  3. Use the correct library configuration (DEBUG or RELEASE). ✔
  4. 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).

Neonit
  • 680
  • 8
  • 27
  • Usually you don't add subprojects using `include()` but instead you make sure the subproject recides in its own dir and use `add_subdirectory`. For making the shared libs available you can set the rpath on unix.For Visual Studio there's the `VS_DEBUGGER_ENVIRONMENT` target property you an use to specify a custom value for the `PATH` environment variable to use with the ide debugger;not sure if there's an equivalent for vs code.As for simply navigating there via command line: this is indeed more complex on windows,since either you copy the dlls to the working dir or modify the "global" path var – fabian Apr 16 '21 at 16:40
  • Of course you could allow the option of setting the output dir for `meow` by setting a certain var before doing `add_subdirectory`; this would of course only work for a single executable in your project; you could of course create a macro for creating the copy commands; furthermore you of course can set the directory where the executable goes explicitly as well; just make sure there are no name conflicts between configurations... – fabian Apr 16 '21 at 16:46
  • The duplicate question solves your immediate problem - copying `.dll`. Other considerations: 1. The script `meow.cmake` could be renamed to `Findmeow.cmake`, so after adjusting variable `CMAKE_MODULE_PATH` it can be included via `find_package(meow)`. [CMake documentation](https://cmake.org/cmake/help/latest/manual/cmake-developer.7.html) describes how to write `FindXXX.cmake` scripts. 2. Whatever additional script you would create, it is not responsible for **runtime** settings of the library (and is not responsible for copiing `.dll`). – Tsyvarev Apr 16 '21 at 18:34
  • This question is technically **not** a duplicate of the linked one. I'm asking for an independent, reusable way and the answer to the linked question provides a dependent (on the depending target) workaround. I expect the answer to my question to be *there is no way*, so I'm not sure if reopening would do any good, though. – Neonit Apr 17 '21 at 07:30

0 Answers0