11

I have a simple QT project. I'm developing on Linux. But it's meant to be deployed to Linux, Mac and Windows ultimately.

I'm attempting to package it for distribution. I'm running into problems locating the dependencies and packaging them up and doing this in an idiomatic way (IOW: No hardcoded paths to DLLs or including the DLLs in my source repo)

For the Windows port, I'm using MinGW and compiling like this:

mingw64-cmake -G "Unix Makefiles" .. -DCMAKE_INSTALL_PREFIX=../install -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=/usr/share/mingw/toolchain-mingw64.cmake
make && ctest && make install && cpack -G "TGZ" && cpack -G "NSIS64"

I've set it to product a tar.gz file and an NSIS installer. There's no particular reason for NSIS and not Wix at the moment. This is just to figure things out.

It compiles a Windows executable, but it does not include the DLLs necessary to run the program. It's these:

Libgcc_s_seh-1.dll
Qt5Core.dll
Qt5Gui.dll

A quick find on my computer shows me that those DLLs are present here:

/usr/x86_64-w64-mingw32/sys-root/mingw/bin/Qt5Widgets.dll
/usr/x86_64-w64-mingw32/sys-root/mingw/bin/libgcc_s_seh-1.dll
...

Is there a way to automatically get CPack to dig up the DLLs and include them in the installer?

Here is my CMakeLists.txt file:

cmake_minimum_required(VERSION 2.8.11)

project(myapp)

enable_testing()

set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

find_package(Qt5Core REQUIRED)
find_package(Qt5Gui REQUIRED)
find_package(Qt5Widgets REQUIRED)

add_executable(myapp WIN32 main.cpp mainwindow.cpp resources.qrc)

target_link_libraries(myapp Qt5::Widgets)
target_link_libraries(myapp Qt5::Core)
target_link_libraries(myapp Qt5::Gui)

INSTALL(TARGETS myapp
        BUNDLE DESTINATION .
        RUNTIME DESTINATION bin
        LIBRARY DESTINATION lib
        ARCHIVE DESTINATION lib
        )

INSTALL(FILES ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} DESTINATION bin COMPONENT Libraries)     

IF(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS)
    INSTALL(PROGRAMS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} DESTINATION bin COMPONENT System)
ENDIF(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS)

INCLUDE(CPack)

I've looked around for some help on this. The best thing I came across was this link

But it's not looking so idiomatic. If we look closer at the CMakeLists.txt file, it's got machine-specific hard coded paths that are certain to change in the future:

IF(    WIN32 AND ${ARCH_32BIT})

    SET(QT_INSTALLED_PATH "C:/QtMSVCX86/Qt5.5.0/5.5/msvc2013" )

ELSEIF(WIN32 AND ${ARCH_64BIT})

    SET(QT_INSTALLED_PATH "C:/QtMSVCX64/Qt5.5.0/5.5/msvc2013_64" )

ELSEIF(UNIX  AND NOT MINGW AND ${ARCH_32BIT})

    SET(QT_INSTALLED_PATH "/opt/Qt5.5.0/5.5/gcc/" )

ELSEIF(UNIX  AND NOT MINGW AND ${ARCH_64BIT})

    SET(QT_INSTALLED_PATH "/opt/Qt5.5.0/5.5/gcc_64/" )

ENDIF()

SET(CMAKE_AUTOMOC ON)
SET(CMAKE_AUTOUIC ON)
SET(CMAKE_AUTORCC ON)

FIND_PACKAGE(Qt5Widgets PATHS  ${QT_INSTALLED_PATH} NO_DEFAULT_PATH)
FIND_PACKAGE(Qt5Qml     PATHS  ${QT_INSTALLED_PATH} NO_DEFAULT_PATH)
FIND_PACKAGE(Qt5Quick   PATHS  ${QT_INSTALLED_PATH} NO_DEFAULT_PATH)
101010
  • 14,866
  • 30
  • 95
  • 172
  • Packaging binaries for linux without using distro-specific packages doesn't make much sense. Distribute your project as source if you can, otherwise stick to one or two supported distros, and provide packages for them. – Kuba hasn't forgotten Monica Sep 01 '16 at 14:05
  • I don't think that's right. Assuming I'm at least shipping for my distro that I'm building on (Fedora), I'm compiling with my distro's version of mingw64-cmake and it comes with all the QT5 dll's and all of those "Find_Package" scripts.... I'm wondering if anything in there will tell me "The QT5 DLL's you are looking for are exactly ${here}". – 101010 Sep 02 '16 at 02:59
  • Why do you need to know where they are? By the time cmake gets running, the SRPM has ensured that proper build dependencies are met. cmake should know about the paths as long as Fedora's Qt -devel RPMs properly support cmake. It should all work automagically, if it doesn't, then it's a packaging bug that you may wish to temporarily work around by hardcoding platform-specific paths in the SRPM and passing them to cmake via command line. Still, nothing distro-specific is called for in the CMakelist. And you definitely don't want to bundle any Qt .so files with your RPM! – Kuba hasn't forgotten Monica Sep 02 '16 at 12:35
  • Perhaps I'm misunderstanding something. When I used cmake and the mingw tool chain on Linux, my intent is to cross-compile binaries that will execute on Windows. Windows does not normally ship with the QT5 dlls so I should probably supply them. My Windows users will not have the MingGW compiler, so I can't send them source. The dll proxies (the .lib files) involved in the compilation process are on the build machine (which is Linux) and have the DLL files that I should probably ship sitting right next to them. – 101010 Sep 02 '16 at 15:02
  • OK, now it makes more sense. You should be passing a path to qmake to cmake, and the CMakeList should use the qmake binary to figure everything else out. If you need to use it yourself, `qmake -query` gives you a lot of goodies - presumably all the goodies you need. – Kuba hasn't forgotten Monica Sep 02 '16 at 15:38
  • qmake is already included by way of using the mingw cross-compiler in conjunction with the FIND_PACKAGE commands for Qt5. A quick grep in /lib/cmake (the cross-compiler one) shows qmake is included. I guess the trick is to figure out which environment variable contains what I need. So far, that info hasn't availed itself to me. – 101010 Sep 03 '16 at 19:48
  • Take a look at http://stackoverflow.com/a/14292554/4069571 for a way to do it for OSX, using `${QT_PLUGINS_DIR}` - it could be possible to transfer this approach to Windows – GPMueller Dec 19 '16 at 10:05

1 Answers1

4

Have a look at CMake's Bundle Utilities It contains a FIXUP_BUNDLE macro which collects all the necessary dependencies of an executable, including Qt. It works basically the same way on Windows, Linux and Mac. You could start by adding FIXUP_BUNDLE(myapp) to your CMake file. the actual dependency resolving and copying happens during the CPack run. Depending on project size and complexity, some tweaks are necessary, but in general I have seen it used successfully in larger cross-platform Qt projects with a CMake based build system

manol
  • 572
  • 3
  • 13
  • 2
    I am currently trying to get this to work on a project I'm starting from scratch and I'm wondering if you can point me to any of these large projects that may have a working example (assuming any are open source). I'm using FIXUP_BUNDLE but it's not copying the Qt libraries into the generated package. – Rotsiser Mho Mar 29 '19 at 14:16