0

交叉编译 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++ 运行时库 此应用程序已请求运行时以不寻常的方式终止它。请联系应用程序的支持团队以获取更多信息。

qt2

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

a) 上述步骤过去有效(在同一个 Fedora 19 系统上执行)

b) 平台目录在 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\\.

但是,当所有需要的 DLL/usr/i686-w64-mingw32/sys-root/mingw/bin/*.dll都被复制到 $DEST 时,wine 运行同样main.exe正常 - 在本机 Windows (7) 上,我得到上述错误框。

4

1 回答 1

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 文档似乎提出了相反的建议:

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

完整的部署过程现在是:

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

于 2013-10-25T19:32:28.463 回答