[CMake] Copying DLLs to output directory

Michael Jackson mike.jackson at bluequartz.net
Fri Oct 31 15:42:44 EDT 2014


Never said it was pretty, but here is the code I use for Qt4 based projects. I think I had to revamp a lot of this for Qt5. I call it like so:

CMP_COPY_QT4_RUNTIME_LIBRARIES( "QtCore;QtGui;QtNetwork")


# --------------------------------------------------------------------
#-- Copy all the Qt4 dependent DLLs into the current build directory so that
#-- one can debug an application or library that depends on Qt4 libraries.
#-- This macro is really intended for Windows Builds because windows libraries
#-- do not have any type of rpath or install_name encoded in the libraries so
#-- the least intrusive way to deal with the PATH issues is to just copy all
#-- the dependend DLL libraries into the build directory. Note that this is
#-- NOT needed for static libraries.
macro(CMP_COPY_QT4_RUNTIME_LIBRARIES QTLIBLIST)
    # message(STATUS "CMP_COPY_QT4_RUNTIME_LIBRARIES")
    set(SUPPORT_LIB_OPTION 1)
    if(MSVC_IDE)
      set(SUPPORT_LIB_OPTION 0)
    elseif(APPLE) # Apple systems do NOT need this so just skip this entirely
      set(SUPPORT_LIB_OPTION 2)
    elseif(UNIX AND NOT MSVC)
      set(SUPPORT_LIB_OPTION 3)
    endif()

    if(NOT DEFINED QT_QMAKE_EXECUTABLE)
      message(FATAL_ERROR "Qt is REQUIRED to use this Function or macro. Make sure Qt is found on your system.")
    endif()

    if(SUPPORT_LIB_OPTION EQUAL 0)
      set(TYPE "d")
      FOREACH(qtlib ${QTLIBLIST})
        GET_FILENAME_COMPONENT(QT_DLL_PATH_tmp ${QT_QMAKE_EXECUTABLE} PATH)
        # message(STATUS "CMAKE_GENERATOR: ${CMAKE_GENERATOR}")
        # We need to copy both the Debug and Release versions of the libraries into their respective
        # subfolders for Visual Studio builds
        add_custom_target(ZZ_${qtlib}-Debug-Copy ALL
                            COMMAND ${CMAKE_COMMAND} -E copy_if_different ${QT_DLL_PATH_tmp}/${qtlib}${TYPE}4.dll
                            ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Debug/
                            COMMENT "Copying ${qtlib}${TYPE}4.dll to ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Debug/")
        set_target_properties(ZZ_${qtlib}-Debug-Copy PROPERTIES FOLDER ZZ_COPY_FILES)
      #   message(STATUS "Generating Copy Rule for Qt Release DLL Library ${QT_DLL_PATH_tmp}/${qtlib}d4.dll")
        add_custom_target(ZZ_${qtlib}-Release-Copy ALL
                            COMMAND ${CMAKE_COMMAND} -E copy_if_different ${QT_DLL_PATH_tmp}/${qtlib}4.dll
                            ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Release/
                            COMMENT "Copying ${qtlib}4.dll to ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Release/")
        set_target_properties(ZZ_${qtlib}-Release-Copy PROPERTIES FOLDER ZZ_COPY_FILES)

      ENDFOREACH(qtlib)
    elseif(SUPPORT_LIB_OPTION EQUAL 1)
      set(TYPE "")
      if( ${CMAKE_BUILD_TYPE} STREQUAL "Debug")
          set(TYPE "d")
      endif()
      FOREACH(qtlib ${QTLIBLIST})
          GET_FILENAME_COMPONENT(QT_DLL_PATH_tmp ${QT_QMAKE_EXECUTABLE} PATH)
          #message(STATUS "Generating Copy Rule for Qt DLL: ${QT_DLL_PATH_tmp}/${qtlib}d4.dll")
          add_custom_target(ZZ_${qtlib}-Debug-Copy ALL
                      COMMAND ${CMAKE_COMMAND} -E copy_if_different ${QT_DLL_PATH_tmp}/${qtlib}${TYPE}4.dll
                      ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/
                      COMMENT "Copying ${qtlib}${TYPE}4.dll to ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/")
          set_target_properties(ZZ_${qtlib}-Debug-Copy PROPERTIES FOLDER ZZ_COPY_FILES)
      ENDFOREACH(qtlib)
    endif()
endmacro()


On Oct 31, 2014, at 3:37 PM, Robert Dailey <rcdailey.lists at gmail.com> wrote:

> If it were only a matter of style / visual annoyance, I wouldn't mind.
> However it complicates dependency management when you have to specify
> "ZZ_QT_LIB1", "ZZ_QT_LIB2", etc... instead of just "QT" when calling
> target_link_libraries().
> 
> Unless you do it differently...
> 
> On Fri, Oct 31, 2014 at 2:28 PM, Michael Jackson
> <mike.jackson at bluequartz.net> wrote:
>> It sucks, but I do that with Qt's libraries. One target for each library. I prefix the target with "ZZ_" so that in IDEs like Visual Studio and Xcode those targets fall to the bottom of the list. I also group them in folders if Visual Studio will allow it. I use the "copy if different" argument to the CMake command for the copy. Seems to work.
>> 
>> Mike Jackson
>> 
>> On Oct 31, 2014, at 3:11 PM, Robert Dailey <rcdailey.lists at gmail.com> wrote:
>> 
>>> I like this idea but it doesn't seem like it will work for targets
>>> with multiple DLLs... for example boost. It has several DLLs. I don't
>>> want to define 1 target for each DLL either. Sometimes that doesn't
>>> make sense.
>>> 
>>> On Wed, Oct 29, 2014 at 10:45 AM, Hendrk Sattler
>>> <post at hendrik-sattler.de> wrote:
>>>> Am 2014-10-28 18:25, schrieb Robert Dailey:
>>>>> 
>>>>> I have a third party library like OpenSSL prebuilt for each platform
>>>>> and in my own structure in version control. I have a CMake script that
>>>>> creates an INTERFACE library target for it. I setup the include
>>>>> directories and link targets. However, I don't see a way to configure
>>>>> DLLs in the interface library target. How would you do this, and what
>>>>> would CMake do to these targets to make sure they are copied to the
>>>>> output directory of the executable I run from Visual Studio for
>>>>> debugging?
>>>> 
>>>> 
>>>> I have this for ZLib:
>>>> if ( ZLIB_FOUND )
>>>> if ( WIN32 )
>>>>   get_filename_component( ZLIB_LIBDIR "${ZLIB_LIBRARY}" PATH )
>>>>   get_filename_component ( ZLIB_BASENAME "${ZLIB_LIBRARY}" NAME_WE )
>>>>   get_filename_component ( ZLIB_LIBDIR_BASE "${ZLIB_LIBDIR}" PATH )
>>>>   find_file ( ZLIB_DLL
>>>> "${CMAKE_SHARED_LIBRARY_PREFIX}${ZLIB_BASENAME}${CMAKE_SHARED_LIBRARY_SUFFIX}"
>>>>     HINTS
>>>>       "${ZLIB_LIBDIR_BASE}"
>>>>     PATH_SUFFIXES
>>>>       bin
>>>>     NO_DEFAULT_PATH
>>>>   )
>>>>   mark_as_advanced ( ZLIB_DLL )
>>>>   if ( ZLIB_DLL )
>>>>     add_library ( zlib SHARED IMPORTED GLOBAL )
>>>>     set_property ( TARGET zlib PROPERTY IMPORTED_IMPLIB "${ZLIB_LIBRARY}"
>>>> )
>>>>     set_property ( TARGET zlib PROPERTY IMPORTED_LOCATION "${ZLIB_DLL}" )
>>>>   else ( ZLIB_DLL )
>>>>     add_library ( zlib STATIC IMPORTED GLOBAL )
>>>>     set_property ( TARGET zlib PROPERTY IMPORTED_LOCATION
>>>> "${ZLIB_LIBRARY}" )
>>>>   endif ( ZLIB_DLL )
>>>> else( WIN32 )
>>>>   add_library ( zlib UNKNOWN IMPORTED GLOBAL )
>>>>   set_property ( TARGET zlib PROPERTY IMPORTED_LOCATION "${ZLIB_LIBRARY}"
>>>> )
>>>> endif( WIN32 )
>>>> set_property ( TARGET zlib PROPERTY INTERFACE_INCLUDE_DIRECTORIES
>>>>   "${ZLIB_INCLUDE_DIR}"
>>>> )
>>>> 
>>>> set ( ZLIB_LIBRARIES zlib )
>>>> set ( ZLIB_INCLUDE_DIRS "${ZLIB_INCLUDE_DIR}" )
>>>> endif ( ZLIB_FOUND )
>>>> 
>>>> The .lib goes into IMPORTED_IMPLIB and the .dll goes into IMPORTED_LOCATION.
>>>> The way to find the .dll from the location of the .lib might differ for
>>>> different libraries.
>>>> For ZLib, the base name is the same.
>>>> 
>>>> Later, you can use this imported target:
>>>> add_custom_command ( TARGET myTarget POST_BUILD
>>>>   COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:zlib>
>>>> $<TARGET_FILE_DIR:myTarget>
>>>> )
>>>> Now, zlib.dll is in the same directory as myTarget.dll.
>>>> 
>>>> HS
>>>> 
>>>>> On Tue, Oct 28, 2014 at 12:21 AM, Hendrik Sattler
>>>>> <post at hendrik-sattler.de> wrote:
>>>>>> 
>>>>>> Hi,
>>>>>> 
>>>>>> you can use generator expression in a post build rule to copy the dll
>>>>>> file to the same target dir as the target you link it with. The easiest way
>>>>>> to do this is to properly define all 3rd party libraries as imported targets
>>>>>> that contains both, the lib and the dll file.
>>>>>> Sadly, the FindQt4 on Windows doesn't do this and thus make life harder
>>>>>> than needed. CMake configuration files should always do this right.
>>>>>> 
>>>>>> OTOH, you could also write a wrapper batch file or change VS properties
>>>>>> to modify PATH to include all libraries before the regular path.
>>>>>> 
>>>>>> HS
>>>>>> 
>>>>>> 
>>>>>> Am 28. Oktober 2014 02:55:08 MEZ, schrieb Robert Dailey
>>>>>> <rcdailey.lists at gmail.com>:
>>>>>>> 
>>>>>>> This actually used to be a very difficult problem to solve. However,
>>>>>>> to debug in visual studio it's essential.
>>>>>>> 
>>>>>>> If I have DLLs located in third party directories OR from targets that
>>>>>>> I depend on, those must all be copied to the directory of the
>>>>>>> executable I'm debugging in order for those DLLs to be found and
>>>>>>> loaded.
>>>>>>> 
>>>>>>> Using CMake 3.0.2, I hope this task is simpler, especially with the
>>>>>>> introduction of a nice suite of generator expressions. Can anyone
>>>>>>> recommend a good way to do this?
>>>>>> 
>>>>>> 
>>>>> --
>>>>> 
>>>>> 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:
>>>>> http://public.kitware.com/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:
>>>> http://public.kitware.com/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:
>>> http://public.kitware.com/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:
>> http://public.kitware.com/mailman/listinfo/cmake



More information about the CMake mailing list