Copying Shared Libraries (DLLs) Next to the Executable

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Copying Shared Libraries (DLLs) Next to the Executable

Marek Vojtko (Firaxis)
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
Reply | Threaded
Open this post in threaded view
|

Re: Copying Shared Libraries (DLLs) Next to the Executable

Daniel Schepler
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 [[hidden email]] on behalf of Marek Vojtko (Firaxis) [[hidden email]]
Sent: Wednesday, February 21, 2018 7:20 PM
To: [hidden email]
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


--

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
Reply | Threaded
Open this post in threaded view
|

Re: Copying Shared Libraries (DLLs) Next to the Executable

Hendrik Sattler
In reply to this post by Marek Vojtko (Firaxis)


Am 22. Februar 2018 04:20:40 MEZ schrieb "Marek Vojtko (Firaxis)" <[hidden email]>:
>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).

Actually at the point of installation this is the best approach especially for multi-config generators like e.g. Visual Studio. Else you'd have to know if a found .lib file is a shared or a static library (how?) and what DLL file it references. That's actually much more work than just looking at the actually dependencies of the binaries. Additionally if you don't exactly know for 3rd party binaries or plugins.

Catching all directories to find the dll files is also not simple but easier.

HS

--
Diese Nachricht wurde von meinem Android-Mobiltelefon mit K-9 Mail gesendet.
--

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