[CMake] DLL handling under CMake
Louis-Paul CORDIER
lp.cordier at dynamixyz.com
Tue Jul 4 04:19:55 EDT 2017
Hi,
Thank you very much for this code snippet. However I don't like the
fixup_bundle function, as it takes the first dll that it found to be
linked against.
I also did a try with a dependency scanning function. It is quiet long
to write, but I guess it is the cleanest way to handle DLL under Windows.
Note: I still have an issue with this function. Indeed, if user uses
Generator expressions for library dependencies, it will not work.
e.g:
add_library(Foo_lib IMPORTED GLOBAL)
# ... set location properties
target_link_libraries(${PROJECT_NAME} optimized
$<$<CONFIG:Release_Production>:Foo_lib>)
Any idea for a workaround? What do you think about this CMake code?
Also, I would see a real benefit to add a LINK_DEPENDENT_LIBRARIES
property (inspired of IMPORTED_LINK_DEPENDENT_LIBRARIES) to each target
that could be automatically filled by each target_link_libraries() calls.
# This function scan all dependencies of a project recursively, and
retrieve all shared
# library associated with it.
# Prerequisite: your upstream CMakeLists.txt must make use of
add_library(foo SHARED IMPORTED GLOBAL),
# and fill the following properties on the imported target:
# set_target_properties(foo PROPERTIES IMPORTED_IMPLIB "path_to_foo.lib")
# set_target_properties(foo PROPERTIES IMPORTED_LOCATION "path_to_foo.dll")
# set_target_properties(foo PROPERTIES IMPORTED_LINK_DEPENDENT_LIBRARIES
"path_to_dll_on_which_foo_depends.dll")
# GLOBAL keyword is important as it allows downstream CMakeLists.txt to
scan dependencies.
# Input parameters:
# dep_to_scan: your downstream project
# config_to_scan: configuration to use for the scanning.
# output_variable: variable in which the function stores the result.
# Usage:
# RECURSIVE_SCAN(my_app Release DLLS)
# install(FILES ${DLLS}
# DESTINATION release
# CONFIGURATIONS Release)
set(COUNT 0)
function(RECURSIVE_SCAN dep_to_scan config_to_scan output_variable)
MATH(EXPR COUNT "${COUNT}+1")
string(RANDOM LENGTH ${COUNT} ALPHABET "-" SPACES)
message("${SPACES} Scanning ${dep_to_scan}")
if(NOT TARGET ${dep_to_scan})
MATH(EXPR COUNT "${COUNT}-1")
#message("${dep_to_scan} Is not target")
return()
endif()
get_target_property(_is_imported ${dep_to_scan} IMPORTED)
if(_is_imported)
# We need to check if the imported library rely on other shared
libraries.
get_target_property(_dependent_dll ${_lib}
IMPORTED_LINK_DEPENDENT_LIBRARIES_${config_to_scan})
if(NOT _dependent_dll)
get_target_property(_dependent_dll ${_lib}
IMPORTED_LINK_DEPENDENT_LIBRARIES)
endif()
if(_dependent_dll)
list(APPEND ${output_variable} ${_dependent_dll})
endif()
#Otherwise, check if it is a shared library. (LOCATION variable can be
# either .lib or DLL regarding of the type of library.)
get_target_property(_TYPE ${dep_to_scan} TYPE)
if(NOT _TYPE STREQUAL STATIC_LIBRARY)
get_target_property(_dll_found ${dep_to_scan}
LOCATION_${config_to_scan})
if(_dll_found)
list(APPEND ${output_variable} ${_dll_found})
endif()
endif()
message("${SPACES}- DLL found: (${${output_variable}})")
endif(_is_imported)
get_target_property(_libraries ${dep_to_scan} INTERFACE_LINK_LIBRARIES)
if(_libraries)
foreach(_lib ${_libraries})
RECURSIVE_SCAN(${_lib} ${config_to_scan} ${output_variable})
endforeach()
endif()
# If we reach our first recursion, we need to clean the list of
# DLL in order to remove duplicates.
MATH(EXPR COUNT "${COUNT}-1")
if(${COUNT} EQUAL 0)
list(REMOVE_DUPLICATES ${output_variable})
endif()
set(${output_variable} ${${output_variable}} PARENT_SCOPE)
endfunction(RECURSIVE_SCAN)
Best regards,
Louis-Paul CORDIER
Le 04/05/2017 à 09:51, lectem at gmail.com a écrit :
>
> I managed to get it working by using an intermediate script.
>
> One might want to generate the script instead of using the « RUN_IT »
> variable trick.
>
> This was only tested on Windows, but seems to work fine.
>
> Put the following code in a xxxxxx.cmake file, include it from your
> CMakeLists.txt and enjoy.
>
> # This is a helper script to run BundleUtilities fixup_bundle as postbuild
>
> # for a target. The primary use case is to copy .DLLs to the build
> directory for
>
> # the Windows platform. It allows generator expressions to be used to
> determine
>
> # the binary location
>
> #
>
> # Usage : run_fixup(TARGET LIBS DIRS)
>
> # - TARGET : A cmake target
>
> # - See fixup_bundle for LIBS and DIRS arguments
>
> if(RUN_IT)
>
> # Script ran by the add_custom_command
>
> include(BundleUtilities)
>
> fixup_bundle("${TO_FIXUP_FILE}" "${TO_FIXUP_LIBS}" "${TO_FIXUP_DIRS}")
>
> # End of script ran by the add_custom_command
>
> else()
>
> set(THIS_FILE ${CMAKE_CURRENT_LIST_FILE})
>
> message(${THIS_FILE})
>
> function(run_fixup _target _libs _dirs)
>
> message(${THIS_FILE})
>
> add_custom_command(
>
> TARGET ${_target} POST_BUILD
>
> COMMAND ${CMAKE_COMMAND}
> -DRUN_IT:BOOL=ON -DTO_FIXUP_FILE=$<TARGET_FILE:${_target}>
> -DTO_FIXUP_LIBS=${_libs} -DTO_FIXUP_DIRS=${_dirs} -P ${THIS_FILE}
>
> COMMENT "Fixing up dependencies for
> ${_target}"
>
> VERBATIM
>
> )
>
> endfunction()
>
> endif()
>
> *De : *Clément Gregoire <mailto:lectem at gmail.com>
> *Envoyé le :*jeudi 4 mai 2017 08:37
> *À : *Hendrik Sattler <mailto:post at hendrik-sattler.de>; Louis-Paul
> CORDIER <mailto:lp.cordier at dynamixyz.com>; Cmake Mailing List
> <mailto:cmake at cmake.org>
> *Objet :*Re: [CMake] DLL handling under CMake
>
> I'd also be interested in this. I saw an old mail in the ML about
> this, but it seems fixup_bundle is old and cant use generator
> expressions, making it hard to use (I don't want to hardcode the
> executable path).
>
> Do you have a sample for this ?
>
> CMake would really benefit from having those features made more
> accessible instead of everyone having to write its own script
>
> Le sam. 29 avr. 2017 22:10, Hendrik Sattler <post at hendrik-sattler.de
> <mailto:post at hendrik-sattler.de>> a écrit :
>
>
>
> Am 27. April 2017 10:43:50 MESZ schrieb Louis-Paul CORDIER
> <lp.cordier at dynamixyz.com <mailto:lp.cordier at dynamixyz.com>>:
> >This steps are tedious and I'm wondering if there is a mechanism that
> >exists or that have to be imagined to make the DLL nightmare end.
>
> I use BundleUtilities to achieve the copying of DLL files to the
> installation directory. The main problem for this is to enumerate the
> needed directories.
>
> I use the same for copying DLL files to the output directory to ease
> debugging.
>
> The advantage is the inspection of the exe for really needed DLL
> files. This AUTOMATICALLY handles the case debug vs. release.
>
> HS
>
> --
> Diese Nachricht wurde von meinem Android-Mobiltelefon mit K-9 Mail
> gesendet.
> --
>
> Powered by www.kitware.com <http://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:
> http://public.kitware.com/mailman/listinfo/cmake
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://public.kitware.com/pipermail/cmake/attachments/20170704/57fe10e6/attachment.html>
More information about the CMake
mailing list