如何使用交叉编译的构建调试Qt dll问题?

时间:2013-10-24 20:07:48

标签: c++ linux windows qt cross-compiling

交叉编译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”。可用的平台是:

qt1

  

Microsoft Visual C ++运行时库   此应用程序已请求Runtime以不寻常的方式终止它。   请联系应用程序的支持团队以获取更多信息。

qt2

我真的不相信第一条消息,因为:

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就好了 - 在本机窗口(7)上我得到了上面的错误框。

1 个答案:

答案 0 :(得分:0)

您可以使用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项目文件中。)

查看Process Monitor输出,似乎二进制文件不会尝试在其当前工作目录(CWD)或其基本目录中打开任何插件(平台或其他)。

当我扩展库路径时,二进制文件在其CWD中找到所有需要的插件:

int main(int argc, char **argv)
{
  QApplication::addLibraryPath(QDir::currentPath());
  QApplication app(argc, argv);
  ...

我不知道这是否有资格作为解决办法 - 也许应该做一些这样的事情。但Qt documentation似乎暗示相反:

  

要部署应用程序,我们必须确保将相关的Qt DLL(对应于应用程序中使用的Qt模块)和windows平台插件以及可执行文件复制到release子目录中的同一目录。 / p>

现在完成部署程序:

$ 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插件,就会显示一些图标。