如何使用交叉编译的构建调试 Qt dll 问题?
Posted
技术标签:
【中文标题】如何使用交叉编译的构建调试 Qt dll 问题?【英文标题】:How to debug Qt dll issues with cross compiled builds? 【发布时间】:2013-10-24 20:07:48 【问题描述】:在交叉编译 Qt 5 应用程序(主机:Fedora 19/64 位,目标:Windows 32 位)后,我执行以下步骤来部署可执行文件:
$ DEST=/windows/testdir
$ cp /usr/i686-w64-mingw32/sys-root/mingw/bin/*.dll $DEST
$ mkdir $DEST/platforms
$ cp /usr/i686-w64-mingw32/sys-root/mingw/lib/qt5/plugins/platforms/qwindows.dll\
$DEST/platforms
$ cp release/main.exe $DEST # the cross-compiled Qt5 binary
我在 Windows 上这样测试它:
say /windows is mounted on f:
start command prompt window
f:
cd testdir
main
我得到了:
无法加载平台插件“windows”。可用平台有:
Microsoft Visual C++ 运行时库 此应用程序已请求运行时以不寻常的方式终止它。 请联系应用程序的支持团队了解更多信息。
我不太相信第一条消息,因为:
a) 上述步骤过去有效(在同一个 Fedora 19 系统上执行)
b) 平台目录是 documented in the qt docs。
改变的是现在应用程序在对话框中包含了一些 PNG/JPG(通过 Qt 的资源文件系统读取,作为 QIcons)。
因此,我也复制了一些插件:
$ cp -r /usr/i686-w64-mingw32/sys-root/mingw/lib/qt5/plugins $DEST
这无助于解决上述问题。
结论
有没有办法调试这些动态运行时链接器问题?
我可以指示它以某种方式获得应用程序/链接器尝试加载的 dll 以及它的查找在哪里的输出吗? (以及他们失败的原因......)
例如这样的事情会很棒:
ldd: main.exe -> load of foo.dll in work-dir failed (no such file)
ldd: main.exe -> load of bar.dll in work-dir/platforms failed (wrong file format)
ldd: main.exe -> load of baz.dll in work-dir successful
...
编译步骤
我在 Fedora 19 上使用以下步骤进行交叉编译:
$ mingw32-qmake-qt5 main.pro -o win32.mf
$ mingw32-make -f win32.mf
$ # -> binary is created in release/main.exe
葡萄酒
出于测试目的,我查看了葡萄酒。这很有帮助,因为它在找不到 DLL 时会显示错误消息,例如:
$ wine $DEST/main.exe
err:module:import_dll Library libEGL.dll (which is needed by L"Z:\\usr\\i686-w64-mingw32\\sys-root\\mingw\\lib\\qt5\\plugins\\platforms\\qwindows.dll") not found
err:module:import_dll Library libjpeg-62.dll (which is needed by L"Z:\\usr\\i686-w64-mingw32\\sys-root\\mingw\\lib\\qt5\\plugins\\imageformats\\qjpeg.dll") not found
有趣的是,它直接在Z:\\usr\\i686-w64-mingw32\\sys-root\\mingw\\lib\\qt5\\
下找到了平台库和需要的插件。
但是当所有需要的来自 /usr/i686-w64-mingw32/sys-root/mingw/bin/*.dll
的 DLL 都复制到 $DEST 时,wine 运行相同的 main.exe
就好了 - 在本机 Windows (7) 上我得到了上述错误框。
【问题讨论】:
使用依赖walker dependencywalker.com 检查平台插件DLL。 procmon technet.microsoft.com/en-us/sysinternals/bb896645.aspx 应该显示 LoadLibrary 调用以及搜索 DLL 的位置。 【参考方案1】:您可以使用Dependency Walker 等工具检查单个 DLL 的依赖关系,Wine 用于快速检查编译主机上的启动,Process Monitor 以查看在进程运行期间访问了哪些目录/文件。
从 Qt 应用程序中调试输出库路径也很有意义,例如
int main(int argc, char **argv)
qDebug() << "Library paths: " << QApplication::libraryPaths();
QApplication app(argc, argv);
...
我在本机窗口上得到以下输出:
Library paths: ()
(要启用 qDebug() 语句 - 即使是发布二进制文件 - 您必须将 CONFIG += console
添加到您的 qmake 项目文件中。)
查看进程监视器的输出,似乎二进制文件没有尝试在其当前工作目录 (CWD) 或其基本目录中打开任何插件(平台或其他)。
当我扩展库路径时,二进制文件会在其 CWD 中找到所有需要的插件:
int main(int argc, char **argv)
QApplication::addLibraryPath(QDir::currentPath());
QApplication app(argc, argv);
...
我不知道这是否可以作为一种解决方法 - 也许应该做这样的事情。但Qt documentation 似乎暗示相反:
要部署应用程序,我们必须确保将相关的Qt DLL(对应应用程序中使用的Qt模块)和windows平台插件以及可执行文件复制到release子目录下的同一目录下。
完整的部署过程现在是:
$ cp /usr/i686-w64-mingw32/sys-root/mingw/bin/*.dll $DEST
# copying platforms, imageformats etc. plugin directories:
$ cp /usr/i686-w64-mingw32/sys-root/mingw/lib/qt5/plugins/* $DEST -r
$ cp release/main.exe $DEST
(根据您的编译主机上安装的软件包,您可能不需要复制所有 DLL - 使用 wine 很容易为所有需要的非插件 dll 启动定点迭代。)
缺少非平台插件不一定会中止程序启动 - 例如。如果没有 jpeg 插件,一些图标就不会显示。
【讨论】:
以上是关于如何使用交叉编译的构建调试 Qt dll 问题?的主要内容,如果未能解决你的问题,请参考以下文章