Qt 交叉编译 Linux -> MacOS 无法链接到 Qt 库

Posted

技术标签:

【中文标题】Qt 交叉编译 Linux -> MacOS 无法链接到 Qt 库【英文标题】:Qt cross-compile Linux -> MacOS cannot link to Qt libs 【发布时间】:2012-08-06 22:46:03 【问题描述】:

我正在尝试链接我为 Linux 主机上的 MacOS 目标交叉编译的 Qt 程序。我按照此处的说明 (https://github.com/Tatsh/xchain) 成功构建了 gcc,我可以编译和链接该页面上的两个简单测试程序,以生成在 MacOS 上运行良好的可执行文件。

我已经使用这个 gcc 从源代码构建了我自己的 Qt,我可以顺利编译我的 Qt 程序。问题出现在链接阶段,当我的程序的目标文件应该链接到 Qt 库时,似乎根本找不到 Qt 库,或者因为它们不兼容而被忽略。

我的程序的目标文件和我构建的 Qt 库似乎都可以:

$ file MainWindow.o
MainWindow.o: Mach-O object i386

$ file /usr/local/myqt/mac32/Qt-4.8.2/lib/libQtCore.dylib.4.8.2
/usr/local/myqt/mac32/Qt-4.8.2/lib/libQtCore.dylib.4.8.2: Mach-O dynamically linked shared library i386

g++ 调用如下:

$ i686-apple-darwin10-g++ -o myapp.app/Contents/MacOS/myapp 
     main.o MainWindow.o ... 
     -L/usr/local/myqt/mac32/Qt-4.8.2/lib -lQtCore -lQtGui ...

当然还有更多的目标文件和更多的 Qt 库,为简洁起见,我将它们省略了。

我得到的错误是典型的没有将对象或库添加到命令行,例如:

...
  "QMainWindow::event(QEvent*)", referenced from:
      vtable for MainWindowin moc_MainWindow.o
  "QDir::~QDir()", referenced from:
      _main in main.o
ld: symbol(s) not found
collect2: ld returned 1 exit status

而且似乎基本上没有找到每个 Qt 库。

我也尝试过直接指定 lib 文件而不是 -L/path 和 -lQtFoo 组合,我什至尝试将它们从 .dylib 重命名为 .so :)

如果我使用 -v 运行 g++ 来查看链接器调用,然后在其中添加 -v,我可以看到正在检查库的路径看起来没问题:

$ i686-apple-darwin10-ld64 -dynamic -arch i386 -headerpad_max_install_names 
     -macosx_version_min 10.4 -syslibroot /usr/i686-apple-darwin10 
     -weak_reference_mismatches non-weak -o myapp.app/Contents/MacOS/myapp
     -lcrt1.o /usr/i686-apple-darwin10/SDKs/MacOSX10.6.sdk/usr/bin/../lib/gcc/i686-apple-darwin10/4.2.1/crt3.o 
     main.o MainWindow.o 
     ... 
     -L/usr/local/myqt/mac32/Qt-4.8.2/lib -lQtCore -lQtGui ...
     -v
@(#)PROGRAM:ld64  PROJECT:odcctools-622.3od16
Library search paths:
    /usr/local/myqt/mac32/Qt-4.8.2/lib
    /usr/i686-apple-darwin10/usr/X11/lib
    /usr/local/myqt/mac32/Qt-4.8.2/lib
    /usr/i686-apple-darwin10/usr/lib/i686-apple-darwin10/4.2.1
    /usr/i686-apple-darwin10/usr/lib
    /usr/i686-apple-darwin10/SDKs/MacOSX10.6.sdk/usr/lib/gcc/i686-apple-darwin10/4.2.1
    /usr/i686-apple-darwin10/SDKs/MacOSX10.6.sdk/usr/lib/gcc
    /usr/i686-apple-darwin10/usr/lib/gcc/i686-apple-darwin10/4.2.1
    /usr/i686-apple-darwin10/SDKs/MacOSX10.6.sdk/usr/i686-apple-darwin10/lib
    /usr/i686-apple-darwin10/SDKs/MacOSX10.6.sdk/usr/i686-apple-darwin10/lib
    /usr/i686-apple-darwin10/usr/lib
    /usr/local/lib
Framework search paths:
    /usr/i686-apple-darwin10/Library/Frameworks/
    /usr/i686-apple-darwin10/System/Library/Frameworks/

lib 位置和设置看起来没问题:

$ ls -lh /usr/local/myqt/mac32/Qt-4.8.2/lib/libQtCore.dylib*
lrwxrwxrwx. 1 root root   21 Aug  7 05:22 /usr/local/myqt/mac32/Qt-4.8.2/lib/libQtCore.dylib -> libQtCore.dylib.4.8.2
lrwxrwxrwx. 1 root root   21 Aug  7 05:22 /usr/local/myqt/mac32/Qt-4.8.2/lib/libQtCore.dylib.4 -> libQtCore.dylib.4.8.2
lrwxrwxrwx. 1 root root   21 Aug  7 05:22 /usr/local/myqt/mac32/Qt-4.8.2/lib/libQtCore.dylib.4.8 -> libQtCore.dylib.4.8.2
-rwxr-xr-x. 1 root root 2.7M Aug  7 05:22 /usr/local/myqt/mac32/Qt-4.8.2/lib/libQtCore.dylib.4.8.2

lib 的内容似乎还可以,但是我对这部分不太熟悉...实际上我刚刚在另一个问题上发现了“nm”。

$ i686-apple-darwin10-nm /usr/local/myqt/mac32/Qt-4.8.2/lib/libQtGui.dylib.4.8.2 | grep event
     U __ZN16QCoreApplication5eventEP6QEvent
     U __ZN16QEventTransition5eventEP6QEvent
     U __ZN16QEventTransition9eventTestEP6QEvent
     U __ZN17QVariantAnimation5eventEP6QEvent
     U __ZN19QAbstractTransition5eventEP6QEvent
     U __ZN23QCoreApplicationPrivate15eventDispatcherE
     U __ZN7QObject11eventFilterEPS_P6QEvent
     U __ZN7QObject5eventEP6QEvent

我也不太熟悉“名称修改”,但我觉得这可能与此有关。

到目前为止,整个交叉编译的过程已经很长了,所以在接近尾声的时候遇到了让我非常难过的东西,真是太糟糕了——任何建议都将不胜感激!

** 编辑 ***

我发现如果我为 ld64 调用去掉 -dynamic 标志,不同的函数名会显示为缺失。例如上面提到的对“QMainWindow::event(QEvent*)”的缺失引用变为:

  "__ZN11QMainWindow5eventEP6QEvent", referenced from:
      __ZTV10MainWindow in moc_MainWindow.o

现在我可以看到这些名称确实在我构建的 Qt 库中找不到(配置问题...?)。这并没有让我知道应该怎么做才能解决这个问题,但也许它可能会给其他人一些线索。

【问题讨论】:

【参考方案1】:

我没有完整的答案,但我可以告诉你,nm 输出中的“U”表示该符号未在该可执行文件(或本例中的库)中定义,但预计会被定义在外部链接的库中,表明该库实际上可能有问题。

作为旁注,您可以使用 nm 的 -C 参数来解开您的 C++ 符号。

【讨论】:

【参考方案2】:

我设法克服了这个问题,尽管没有完全理解它的细节。最初我在 mkspecs 文件中有这两行,虽然它们在构建 Qt 时没有导致任何错误,但将它们注释掉可以解决问题:

QMAKE_RANLIB    = i686-apple-darwin10-ranlib
QMAKE_STRIP     = i686-apple-darwin10-strip

我已将这些设置为像这样认为有必要的交叉编译器可执行文件,但似乎只需指定正确的 gcc 和 g++ 即可处理工具链中的所有内容。

【讨论】:

以上是关于Qt 交叉编译 Linux -> MacOS 无法链接到 Qt 库的主要内容,如果未能解决你的问题,请参考以下文章

从 Mac 为 Windows、Linux 交叉编译 C++/QT [关闭]

如何建立Qt Creator交叉编译嵌入式Linux

QT 使用 MinGW 启用交叉编译(预编译)

如何配置 Qt 以实现从 Linux 到 Windows 目标的交叉编译?

使用动态链接在 Linux 上为 Windows 交叉编译 Qt 应用程序

由 arm-none-linux-gnueabi 进行的 Qt 5.8 交叉编译失败?