[CMake] Copying Shared Libraries (DLLs) Next to the Executable

Daniel Schepler dschepler at scalable-networks.com
Thu Feb 22 13:44:17 EST 2018


Personally, I find it much simpler just to expect the Path to include the locations of the DLL files as opposed to copying them.  (And I often write small batch scripts to set up this development environment, and then optionally start cmake-gui.exe / devenv.exe / etc.)
-- 
Daniel Schepler
________________________________________
From: CMake [cmake-bounces at cmake.org] on behalf of Marek Vojtko (Firaxis) [Marek.Vojtko at firaxis.com]
Sent: Wednesday, February 21, 2018 7:20 PM
To: cmake at cmake.org
Subject: [CMake] Copying Shared Libraries (DLLs) Next to the Executable

Hi,

I need to copy external shared libraries (DLLs on Windows) next to the generated executable. Is calling "cmake -E copy_if_different" through a custom command added to the executable target still the best way to achieve this? CMake tracks include directories, compile definitions or options, link flags, etc. through its dependency system, but it doesn't provide an easy way to list / copy all shared libraries a target depends on?

I am trying to follow the "new" CMake paradigms, using add_subdirectory(), set_target*() with PUBLIC/PRIVATE/INTERFACE scope, etc. to create a modular, re-usable setup, but that actively prevents me from using a custom command on the executable target. To wit:

App depends on Lib. Lib depends on several third-party, pre-built DLLs and encapsulates the logic of when to depend on them. The third-party, pre-built shared libraries (DLLs) are located through custom Find*.cmake modules and used as IMPORTED targets.

/CMakelists.txt
/App
    /CMakelists.txt
/Lib
    /CMakelists.txt

/CMakelists.txt
*************
set(CMAKE_MODULE_PATH "<my_modules>")
project("DLLTest")
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/Lib")
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/App")

/App/CMakelists.txt
*****************
add_executable(App WIN32 main.cpp)
target_link_libraries(App PRIVATE Lib)

/Lib/CMakelists.txt
****************
add_library(Lib STATIC lib.h lib.cpp)
target_include_directories(Lib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")

if(Lib_NEEDS_DEPENDENCY)
    find_package(Dependency REQUIRED)
    target_link_libraries(Lib PUBLIC Dependency::Dependency)
endif()

FindDependency.cmake
********************
[snip]
add_library(Dependency::Dependency SHARED IMPORTED)
set_target_properties(Dependency::Dependency PROPERTIES
            INTERFACE_INCLUDE_DIRECTORIES "inc"
            IMPORTED_IMPLIB "dependency.lib"
            IMPORTED_LOCATION "dependency.dll"
)

In this setup, it is impossible to propagate a shared library (DLL) from Lib to App. This is because Lib and App have different BINARY_DIRs and Lib must create its target before App calls target_link_libraries(). That means that Lib does not know where App will generate its executable. If Lib is a SHARED target, I cannot set its RUNTIME_OUTPUT_DIRECTORY to be the same as App's. If Lib depends on IMPORTED targets (as is my case), I cannot create either a file(COPY) step, or an install(FILES) step, or even an add_custom_command() step in Lib to copy the shared library, because I don't know the destination.

The only solution, it would seem, is to add a custom command to App's target, because then I know where to copy the shared libraries to. But that means that App now has to know it needs to copy a shared library from a "hidden" dependency of Lib. App also needs to know about every SHARED or IMPORTED target Lib depends on, not to mention duplicate the logic in Lib's CMakelists.txt that decided whether Lib depends on Dependency in the first place.

I was looking into GetPrerequisites and FixupBundle, but both of those operate on an already existing executable and try to guess what shared libraries (DLLs) it might need. It feels silly to guess at something that CMake already knows (as the IMPORTED target sets the IMPORTED_IMPLIB and IMPORTED_LOCATION properties).

Setting a common CMAKE_RUNTIME_OUTPUT_DIRECTORY for both App and Lib is problematic if I have multiple executables in my root CMakelists.txt and they depend on different versions of the shared libraries or I have other name clashes.

Is there no automated way to get the list of shared libraries a target depends on?

Thanks,
Marek
--

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
https://cmake.org/mailman/listinfo/cmake




More information about the CMake mailing list