How to copy Qt runtime DLLs to project output
Asked Answered
S

5

34

I have a simple project created in Qt Creator (installed using Qt SDK 1.1.4). It runs just fine from within Qt Creator, but if I then browse to the output directory in Windows and double-click the EXE, I'll get an error like:

The program can't start because QtCored4.dll is missing from your computer.
Try reinstalling the program to fix this problem.

That's obviously because Qt isn't in my PATH (and I don't want it to be, in case I have multiple versions of Qt on my computer), and Qt Creator / qmake didn't copy the Qt DLLs to the project output.

What I would like to do is use qmake to copy the necessary Qt files to the project output directory - wherever it may be. How do I do this?

(I tried creating a custom target in qmake, but I'm not getting too far...)

UPDATE July 19, 2016: Just to clarify, the above post was concerning Qt4. On Qt5, you should instead look into calling windeployqt. This Qt5 tool will read your binary, determine which Qt5 runtime files you need, and copy them to your binary directory. Also note that it will fix absolute paths in the Qt5::Core library that are specific to your PC - so use of this tool is basically mandatory unless you want to provide a qt.conf file yourself.

Stipple answered 5/12, 2011 at 21:14 Comment(10)
oh god,exactly i am working on it right now and looking for a solutionNgocnguyen
Ali Foroughi similar question: #8392424Wilds
@AlessandroPezzato: what we want is to have qmake automatically copy those DLLs to build output, so we don't have to do it by hand.Stipple
that my question dude :DNgocnguyen
@JamesJohnston I have never been so lazy to want this! I use to copy manually needed libraries. +1 for laziness :)Wilds
For the record, you are trying to deploy a debug build instead of a release build.Ide
@Tamas: noted; the solution should copy debug DLLs for debug, and release DLLs for release. :)Stipple
There isn't much use for copying the debug dlls though :)Ide
@Tamas: There is a big use for copying them when the EXE is linked against them. :) (My main concern though, of course, is for the release DLLs).Stipple
Why would you want to run the debug builds outside the IDE?Ide
S
8

OK, here's an ugly hack:

# Copy required DLLs to output directory
CONFIG(debug, debug|release) {
    QtCored4.commands = copy /Y %QTDIR%\\bin\\QtCored4.dll debug
    QtCored4.target = debug/QtCored4.dll
    QtGuid4.commands = copy /Y %QTDIR%\\bin\\QtGuid4.dll debug
    QtGuid4.target = debug/QtGuid4.dll

    QMAKE_EXTRA_TARGETS += QtCored4 QtGuid4
    PRE_TARGETDEPS += debug/QtCored4.dll debug/QtGuid4.dll
} else:CONFIG(release, debug|release) {
    QtCore4.commands = copy /Y %QTDIR%\\bin\\QtCore4.dll release
    QtCore4.target = release/QtCore4.dll
    QtGui4.commands = copy /Y %QTDIR%\\bin\\QtGui4.dll release
    QtGui4.target = release/QtGui4.dll

    QMAKE_EXTRA_TARGETS += QtCore4 QtGui4
    PRE_TARGETDEPS += release/QtCore4.dll release/QtGui4.dll
} else {
    error(Unknown set of dependencies.)
}

Here's some of what I don't like about it:

  • Uses %QTDIR% environment variable; this variable isn't evaluated until the copy command is actually run. Seems like something along the lines of QMAKE_LIBS_QT_DLL would be more appropriate, but I couldn't get that working for some reason.
  • Hard-coded "debug" and "release" names; seems like there ought to be some kind of variable to use for that.
  • Calling out to the environment by using the "copy" command.

I'll accept another answer if somebody can clean this up a good bit, for example by shortening it and/or addressing some of my concerns, or just finding a better way in general.

Stipple answered 5/12, 2011 at 23:42 Comment(5)
$$QMAKE_LIBDIR_QT appears to be the correct replacement for %QTDIR%\\bin.Dive
Update: $$QMAKE_LIBDIR_QT didn't work for one of our developers. We switched to $$[QT_INSTALL_BINS], pointed to by "qmake -query".Dive
Also, using $$QMAKE_COPY, $$QMAKE_DIR_SEP and $$QMAKE_EXTENSION_SHLIB could make this cross-platform.Twitt
I've found that sometimes I need to actually reboot to fix some of the weirder qmake bugs that occasionally happen. Bug happening 100% of the time? Leave it alone, come back, and now it works -_- ...Reginiaregiomontanus
You can always reference the configuration files in your relevant mkespec directories. Just don't forget to check out the common/ folder :)Reginiaregiomontanus
L
8

A bit cleaner method, but it will require doing a make install after a make. It will work on Windows, but would need tweaking for other platforms.

debug { DESTDIR = debug }
release { DESTDIR = release }
debug_and_release { DESTDIR = bin }

myqtlibs.path = $$DESTDIR
myqtlibs.files = $$QMAKE_LIBDIR_QT/*.dll junk.txt fred.out
myqtlibs.CONFIG = no_check_exist

INSTALLS += myqtlibs

If qmake is run just for debug, all output will go into ./debug . If it is just for release, all output goes in ./release . If both, then into ./bin .

I did notice that enabling shadow building in QtCreator caused the executable not to end up in the DESTDIR. I'm not quite sure why.

Loathly answered 10/1, 2012 at 19:47 Comment(0)
T
6

Copy Dependencies with windeployqt

# Deployment - Automatically Detect and Copy Dependencies to Build Folder

TARGET_CUSTOM_EXT = .exe
DEPLOY_COMMAND = windeployqt

DEPLOY_OPTIONS = "--no-svg --no-system-d3d-compiler --no-opengl --no-angle --no-opengl-sw"

CONFIG( debug, debug|release ) {
    # debug
    DEPLOY_TARGET = $$shell_quote($$shell_path($${OUT_PWD}/debug/$${TARGET}$${TARGET_CUSTOM_EXT}))
    DEPLOY_OPTIONS += "--debug"
} else {
    # release
    DEPLOY_TARGET = $$shell_quote($$shell_path($${OUT_PWD}/release/$${TARGET}$${TARGET_CUSTOM_EXT}))
    DEPLOY_OPTIONS += "--release"
}

# Uncomment the following line to help debug the deploy command when running qmake
#message($${DEPLOY_COMMAND} $${DEPLOY_OPTIONS} $${DEPLOY_TARGET})

QMAKE_POST_LINK = $${DEPLOY_COMMAND} $${DEPLOY_OPTIONS} $${DEPLOY_TARGET}

or Copy dependencies manually

# Deployment - Copy Dependencies to Build Folder

dlls.path  =  $${DESTDIR}
dlls.files += $$[QT_INSTALL_BINS]/icudt51.dll
dlls.files += $$[QT_INSTALL_BINS]/icuin51.dll
dlls.files += $$[QT_INSTALL_BINS]/icuuc51.dll
dlls.files += $$[QT_INSTALL_BINS]/libgcc_s_dw2-1.dll
dlls.files += $$[QT_INSTALL_BINS]/libstdc++-6.dll
dlls.files += $$[QT_INSTALL_BINS]/libwinpthread-1.dll
dlls.files += $$[QT_INSTALL_BINS]/Qt5Core.dll
dlls.files += $$[QT_INSTALL_BINS]/Qt5Network.dll
dlls.files += $$[QT_INSTALL_BINS]/Qt5Gui.dll
dlls.files += $$[QT_INSTALL_BINS]/Qt5Widgets.dll
dllA.path   += $${DESTDIR}/platforms
dllA.files  += $$[QT_INSTALL_PLUGINS]/platforms/qwindows.dll
dllB.path   += $${DESTDIR}/plugins/imageformats/
dllB.files  += $$[QT_INSTALL_PLUGINS]/imageformats/qico.dll
dllB.files  += $$[QT_INSTALL_PLUGINS]/imageformats/qwbmp.dll
INSTALLS   += dlls dllA dllB

Referencing: http://doc.qt.io/qt-5/qmake-variable-reference.html#deployment


In case you need to identify prerequisites / dependencies cross-platform, please take a look at CMake's getPrerequisites(). It uses dumpbin, objbin, ldd, otool for the identification of dependencies.

Referencing: https://cmake.org/cmake/help/v3.0/module/GetPrerequisites.html

Tadzhik answered 1/2, 2015 at 19:32 Comment(2)
Is there a generic / placeholder way I could do this when making for multiple platforms? like, DEPLOY_COMMAND = *deploy, or do these all need to be individually/explicitly specified?Reginiaregiomontanus
Not with Qt on-board tools. But for instance with CMake you could use getPrerequisites(). It uses dumpbin, objbin, ldd, otool (cross-platform) for the identification of dependencies. See cmake.org/cmake/help/v3.0/module/GetPrerequisites.htmlTadzhik
H
4

I ran into the same problem and jwernerny's solution helped me a lot. However, I was using Shadow Build on Window 7 and it needed a bit more tweeking.

I also needed to set the DESTDIR according to the current configuration.

In my case I wanted to copy *.qml files, that's how I achieved it:

CONFIG(release, debug|release): DESTDIR = $$OUT_PWD/release
CONFIG(debug, debug|release): DESTDIR = $$OUT_PWD/debug

QmlFiles.path = $$DESTDIR/Qml
QmlFiles.files += $$files(Qml/*.qml)

INSTALLS += QmlFiles

EDIT :

Since I use Shadow Build I need to use $$OUT_PWD to get the output folder.

Hama answered 31/10, 2012 at 22:19 Comment(0)
P
0

A verbose but clear example:

find_package(Qt5 CONFIG COMPONENTS Widgets REQUIRED)
if (WIN32)
    MESSAGE("Copying dlls...")
    set(QtBin ${Qt5Core_DIR}/../../../bin)
    if (${CMAKE_BUILD_TYPE} STREQUAL Debug)
        file(COPY ${QtBin}/Qt5Cored.dll DESTINATION ${CMAKE_BINARY_DIR})
        file(COPY ${QtBin}/Qt5Widgetsd.dll DESTINATION ${CMAKE_BINARY_DIR})
        file(COPY ${QtBin}/Qt5Guid.dll DESTINATION ${CMAKE_BINARY_DIR})
    else ()
        file(COPY ${QtBin}/Qt5Core.dll DESTINATION ${CMAKE_BINARY_DIR})
        file(COPY ${QtBin}/Qt5Widgets.dll DESTINATION ${CMAKE_BINARY_DIR})
        file(COPY ${QtBin}/Qt5Gui.dll DESTINATION ${CMAKE_BINARY_DIR})
    endif ()
endif ()
Procephalic answered 7/4, 2023 at 9:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.