在 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,例如 Qt5Quick、Qt5QuickTemplates2.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 xp 上部署 Qt 5.10 Quick 2 应用程序?