如何将 Qt 运行时 DLL 复制到项目输出

发布于 2024-12-19 22:15:32 字数 878 浏览 3 评论 0原文

我在 Qt Creator 中创建了一个简单的项目(使用 Qt SDK 1.1.4 安装)。它在 Qt Creator 中运行得很好,但是如果我浏览到 Windows 中的输出目录并双击 EXE,我会收到如下错误:

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

这显然是因为 Qt 不在我的 PATH 中(而且我不这样做)我不想这样,以防我的计算机上有多个版本的 Qt),并且 Qt Creator / qmake 没有将 Qt DLL 复制到项目输出。

我想做的是使用 qmake 将必要的 Qt 文件复制到项目输出目录 - 无论它在哪里。我该怎么做?

(我尝试在 qmake 中创建自定义目标,但我并没有走得太远......)

2016 年 7 月 19 日更新:只是为了澄清一下,上面的帖子是关于 Qt4 的。在 Qt5 上,您应该考虑调用 windeployqt。这个 Qt5 工具将读取您的二进制文件,确定您需要哪些 Qt5 运行时文件,并将它们复制到您的二进制目录。另请注意,它将修复 Qt5::Core 库中特定于您的 PC 的绝对路径 - 因此基本上必须使用此工具,除非您想提供 qt.conf 文件您自己。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

生生不灭 2024-12-26 22:15:32

好吧,这是一个丑陋的黑客:

# 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.)
}

这是我不喜欢它的一些地方:

  • 使用%QTDIR%环境变量;在实际运行复制命令之前不会评估此变量。似乎类似于 QMAKE_LIBS_QT_DLL 的东西更合适,但由于某种原因我无法让它发挥作用。
  • 硬编码的“调试”和“发布”名称;似乎应该有某种变量可以用于此目的。
  • 使用“复制”命令调用环境。

如果有人可以很好地解决这个问题,例如通过缩短它和/或解决我的一些问题,或者只是找到一种更好的方法,我会接受另一个答案。

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.

蓝色星空 2024-12-26 22:15:32

一种更简洁的方法,但需要在 make 之后执行 make install。它可以在 Windows 上运行,但需要针对其他平台进行调整。

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

如果 qmake 只是为了调试而运行,则所有输出都将进入 ./debug 。如果只是为了发布,所有输出都放在 ./release 中。如果两者都存在,则进入 ./bin 。

我确实注意到,在 QtCreator 中启用影子构建会导致可执行文件不会出现在 DESTDIR 中。我不太清楚为什么。

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.

欲拥i 2024-12-26 22:15:32

使用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}

手动复制依赖项

# 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

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


如果您需要确定先决条件/依赖跨平台,请看一下CMake的getPrecessions()。它使用 dumpbinobjbinlddotool 来识别依赖项。

参考:https://cmake.org/cmake/help/v3。 0/module/GetPrecessions.html

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

许一世地老天荒 2024-12-26 22:15:32

我遇到了同样的问题,jwernerny 的解决方案对我帮助很大。然而,我在 Window 7 上使用 Shadow Build,它需要更多的调整。

我还需要根据当前配置设置DESTDIR

在我的例子中,我想复制*.qml文件,这就是我实现它的方法:

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

编辑:

由于我使用Shadow Build,所以我需要使用$$OUT_PWD 获取输出文件夹。

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.

陈年往事 2024-12-26 22:15:32

一个冗长但清晰的例子:

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 ()

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 ()
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文