在 Windows 上部署 Qt (C++/QML) 应用程序

Posted

技术标签:

【中文标题】在 Windows 上部署 Qt (C++/QML) 应用程序【英文标题】:Deploying Qt (C++/QML) application on Windows 【发布时间】:2017-06-26 15:09:03 【问题描述】:

我开始了一个只有 C++ 代码的 Qt 项目,此时一切正常。这是我的配置和部署可执行文件的步骤:

在 Windows10 64 位、x64 处理器、联想 Thinkpad 平板电脑上编程。使用Qt5.9框架和MinGW32bit编译器。

(1) 我首先构建项目并在我的构建目录的副本上启动 windeployqt.exe。 (2) 然后,我将每个 DLL 和可执行文件放入一个 Wix 项目中,以制作一个 MSI 包。据我所知,这个MSI 设置的输出应该只是将文件复制到ProgramFiles 目录,并在开始菜单和桌面添加正确的快捷方式。

此时,一切正常。但是从现在开始,QML 代码被添加到项目中(因此一些 OpenGL 依赖插件)。我添加了一个QQuickWidget,它在我的视口上实例化了一个 QML 地理地图对象。在我设法让它在 Windows 上运行后,我无法再获得 独立 * 可执行文件。使用 Qt IDE 运行它可以,但是运行 stand-alone * 可执行文件不能。 (抱歉,如果术语不正确:独立,带有 DLL 和大量文件依赖项)

当所有的 DLL 被复制到可执行文件夹中时,(上面的步骤 1.)应用程序卡在后台,并且什么也没有显示。也没有运行时错误来调试它或找出丢失的 DLL(如果有)。

我的想法是某些 QML 插件未加载,或者 OpenGLES 和 Angle 出现问题,以下是我获得的一些 DLL 作为依赖项:

D3Dcompiler_47.dll 987654328 libgcc_s_dw2-1.dll 987654330 libstdc++-6.dll 987654332 Qt5Core.dll 987654334 Qt5Network.dll 987654336 Qt5Qml.dll 987654338 Qt5QuickWidgets.dll 987654340 Qt5Svg.dll 987654342 @在可执行文件的同一级别。 qwindows.dll 放入“platforms”文件夹,以及其他一些文件夹,例如“qmltooling”、“position”、“platforminputcontexts”...(EDIT 以及看似相关的 QML 插件目录)。李>

我不知道它可能是什么。有人知道吗?


将环境变量 QML_IMPORT_TRACE 设置为 1 时的输出。qt.network.ssl ... 消息不是 qml 跟踪的一部分。自从我添加了 QML 映射后,我总是得到它们,但通过 Qt Creator 运行时似乎不是问题。

QQmlImportDatabase::addImportPath: "C:/Qt/5.9/mingw53_32/qml"
QQmlImportDatabase::addImportPath: "qrc:/qt-project.org/imports"
QQmlImportDatabase::addImportPath: "C:/Users/hermes/Documents/build-MyApplication-Desktop_Qt_5_9_0_MinGW_32bit-Release/src/release"
QQmlImportDatabase::addImportPath: "C:/Qt/5.9/mingw53_32/qml"
QQmlImportDatabase::addImportPath: "qrc:/qt-project.org/imports"
QQmlImportDatabase::addImportPath: "C:/Users/hermes/Documents/build-MyApplication-Desktop_Qt_5_9_0_MinGW_32bit-Release/src/release"
QQmlImports(qrc:/qml.qrc/main.qml)::addLibraryImport: "QtQuick" 2.0 as ""
QQmlImports(qrc:/qml.qrc/main.qml)::importExtension: loaded "C:/Qt/5.9/mingw53_32/qml/QtQuick.2/qmldir"
QQmlImportDatabase::registerPluginTypes: "QtQuick" from "C:/Qt/5.9/mingw53_32/qml/QtQuick.2"
QQmlImports(qrc:/qml.qrc/main.qml)::addLibraryImport: "QtQuick.Controls" 1.4 as ""
QQmlImports(qrc:/qml.qrc/main.qml)::importExtension: loaded "C:/Qt/5.9/mingw53_32/qml/QtQuick/Controls/qmldir"
QQmlImportDatabase::registerPluginTypes: "QtQuick.Controls" from "C:/Qt/5.9/mingw53_32/qml/QtQuick/Controls"
QQmlImports(qrc:/qml.qrc/main.qml)::addLibraryImport: "QtLocation" 5.9 as ""
QQmlImports(qrc:/qml.qrc/main.qml)::importExtension: loaded "C:/Qt/5.9/mingw53_32/qml/QtLocation/qmldir"
QQmlImportDatabase::registerPluginTypes: "QtLocation" from "C:/Qt/5.9/mingw53_32/qml/QtLocation"
QQmlImports(qrc:/qml.qrc/main.qml)::addLibraryImport: "QtPositioning" 5.5 as ""
QQmlImports(qrc:/qml.qrc/main.qml)::importExtension: loaded "C:/Qt/5.9/mingw53_32/qml/QtPositioning/qmldir"
QQmlImportDatabase::registerPluginTypes: "QtPositioning" from "C:/Qt/5.9/mingw53_32/qml/QtPositioning"
QQmlImports(qrc:/qml.qrc/main.qml)::resolveType: "PluginParameter" => "QDeclarativeGeoServiceProviderParameter" TYPE
QQmlImports(qrc:/qml.qrc/main.qml)::resolveType: "MapQuickItem" => "QDeclarativeGeoMapQuickItem" TYPE
QQmlImports(qrc:/qml.qrc/main.qml)::resolveType: "Image" => "QQuickImage" TYPE
QQmlImports(qrc:/qml.qrc/main.qml)::resolveType: "Rotation" => "QQuickRotation" TYPE
QQmlImports(qrc:/qml.qrc/main.qml)::resolveType: "Map" => "QDeclarativeGeoMap" TYPE
QQmlImports(qrc:/qml.qrc/main.qml)::resolveType: "Plugin" => "QDeclarativeGeoServiceProvider" TYPE
QQmlImports(qrc:/qml.qrc/main.qml)::resolveType: "Connections" => "QQmlConnections" TYPE
QQmlImports(qrc:/qml.qrc/main.qml)::resolveType: "Component" => "QQmlComponent" TYPE
qt.network.ssl: QSslSocket: cannot resolve TLSv1_1_client_method
qt.network.ssl: QSslSocket: cannot resolve TLSv1_2_client_method
qt.network.ssl: QSslSocket: cannot resolve TLSv1_1_server_method
qt.network.ssl: QSslSocket: cannot resolve TLSv1_2_server_method
qt.network.ssl: QSslSocket: cannot resolve SSL_select_next_proto
qt.network.ssl: QSslSocket: cannot resolve SSL_CTX_set_next_proto_select_cb
qt.network.ssl: QSslSocket: cannot resolve SSL_get0_next_proto_negotiated
qt.network.ssl: QSslSocket: cannot resolve SSL_set_alpn_protos
qt.network.ssl: QSslSocket: cannot resolve SSL_CTX_set_alpn_select_cb
qt.network.ssl: QSslSocket: cannot resolve SSL_get0_alpn_selected
qt.network.ssl: QSslSocket: cannot call unresolved function SSL_get0_next_proto_negotiated
mincore\com\oleaut32\dispatch\ups.cpp(2128)\OLEAUT32.dll!74865072: (caller: 7486FE4F) ReturnHr(1) tid(2e20) 8002801D Bibliothèque non inscrite.
mincore\com\oleaut32\dispatch\ups.cpp(2128)\OLEAUT32.dll!74865072: (caller: 7486FE4F) ReturnHr(2) tid(2e20) 8002801D Bibliothèque non inscrite.
qt.network.ssl: QSslSocket: cannot call unresolved function SSL_get0_next_proto_negotiated
qt.network.ssl: QSslSocket: cannot call unresolved function SSL_get0_next_proto_negotiated
qt.network.ssl: QSslSocket: cannot call unresolved function SSL_get0_next_proto_negotiated
qt.network.ssl: QSslSocket: cannot call unresolved function SSL_get0_next_proto_negotiated

【问题讨论】:

尝试使用QML_IMPORT_TRACE=1 运行应用程序并在此处提供输出。 @herme5 你使用了windeployqt 的--qmldir 选项吗?并且你是否部署了windeployqt生成的所有文件夹(包括使用--qmldir时创建的文件夹)? @BenjaminT。我改为尝试使用 c++ 命令QCoreApplication::addLibraryPath("C:/path/to/plugins")。我总是运送windeployqt 生成的所有文件夹,但从未尝试过--qmldir。我会看看这个。 @king_nak 我尝试运行 Dependency Walker ,除了 API-MS-WIN 缺少依赖项外,它没有报告任何内容。但根据this topic,只要 Windows 动态解决这些问题,就可以忽略它(如果我理解得很好)。 您必须开始分析(菜单 > 配置文件 > 开始分析)。这会启动程序并为所有 DLL、符号等生成大量日志。在将所需的 QML 复制到应用程序目录之前,我遇到了类似 QQmlApplicationEngine failed to load component qrc:/main.qml:3 module "QtQuick.Controls.Styles" is not installed 的错误 【参考方案1】:

对于 QML 应用程序,您应该在使用 windeploy.exe 时遵循以下命令

windeployqt --qmldir [path-to-app-qml-files] [path-to-app-binary]

【讨论】:

【参考方案2】:

从 Qt 安装文件夹复制到您的 .exe 文件夹:

bin\Qt5QuickControls2.dll bin\Qt5QuickTemplates2.dll qml\QtQuick qml\QtQuick.2

让你的 .exe 文件夹看起来像这样:

如果程序现在运行正常,那么您可以进入 QtQuick 文件夹并尝试删除您未在程序中使用的库。

【讨论】:

祝你好运。如果这还不够,请尝试将 [qt_install_dir]\qml 的全部内容复制到您的 .exe 文件夹中,然后通过反复试验将其删除。 我试过了,很抱歉告诉你它没有效果。我开始添加您的不在我的文件中的文件:只有Qt5DBus.dll。顺便说一下 scenegraph 文件夹不适用于 MinGW (?!)。然后我复制了qml 文件夹的所有内容,然后复制了plugins 文件夹的所有内容,然后是所有“核心” DLL(与 Qt5***.dll 和 libGL 位于同一文件夹中的那些D3D编译器...)。显然,每次尝试时,我都会注意杀死我的应用程序。 很遗憾听到这个消息,在这种情况下,我很遗憾无法提供帮助。我要删除我的答案吗? 我想我会尝试用 MSVC 编译它。顺便说一句,我看过几个论坛,据说windeployqt 有问题并且没有复制所有必需的文件,不知道您的帖子是否可以帮助其他人。随意删除它,但还是谢谢你! 是的,我一直在使用 MSVC。仅供参考,我尝试删除场景图文件夹,但我的应用程序仍然可以正常运行。【参考方案3】:

您可以使用有用的windeployqt 工具将所有需要的依赖项收集到发布目录中:

rem %1 H:\src\trunk\src\qt\cargofinder
pushd f:\qt\5.9\msvc2015_64\bin
call qtenv2.bat
popd
windeployqt --qmldir %1 .

【讨论】:

感谢您的回答,我正在使用windeployqt.exe 和类似 git bash unix 的终端。所以请原谅我的无知,但是你用你写的命令行做什么?我不习惯使用 Windows shell,也不习惯使用批处理文件编写脚本。【参考方案4】:

我最近遇到这个问题,我用的是编译器cl(MSVC2017)QT version 5.12 64bit。我解决的过程如下: p>

    我复制了所有依赖于程序的 Dllsdepends.exe 提示。但是当我双击exe时,任务管理器程序中甚至没有任何反应。 然后我了解了监控 Process Explorer 依赖的 Dll,我发现了一些其他依赖的 dll,例如 Qt5QuickQt5QuickTemplates2.dll、 *Qt5QuickControls2.dll**等以及msvc2017_64\qml文件夹中的许多Dll。 我也用过图表,所以我不能忘记Qt5Charts.dll

好的,到目前为止它有效。这么多依赖于Qt的Dll,我都累死了 闲置的文件很爽。(ps:qml\QtQuick中的一些闲置的东西好像不能删除,如果我删除了,双击exe什么都没有。)

【讨论】:

您为什么不使用windeployqt 工具?还是您有问题,迫使您自己动手做这项工作?

以上是关于在 Windows 上部署 Qt (C++/QML) 应用程序的主要内容,如果未能解决你的问题,请参考以下文章

qt-qml移动开发之在ios上开发和部署app流程简单介绍

在 Windows 上部署 Qt 5 应用程序

在 Windows 上部署 Qt 5 应用程序

如何在 windows xp 上部署 Qt 5.10 Quick 2 应用程序?

如何在Windows XP上部署Qt 5.10 Quick 2应用程序?

Windows 上 Webview 的 Qt QML 后备组件