如何在 Xcode 中将库与 rpath 链接?

Posted

技术标签:

【中文标题】如何在 Xcode 中将库与 rpath 链接?【英文标题】:How do I link libraries with rpath in Xcode? 【发布时间】:2020-05-07 18:43:29 【问题描述】:

我在任何地方都找不到此信息。我的系统中安装了一些库,因此它可以在我的计算机上运行,​​但我想将这些库与我的应用程序一起分发。我看到的问题是 otool 显示系统库的绝对路径,因此当我将二进制文件复制到其他机器时,即使我将它们放在“运行路径搜索路径”中添加的目录中,也找不到它们。我有一个本地库(位于项目目录中),它与@rpath 前缀链接。其他系统库的链接方式相同,但它们具有 otool 显示的绝对路径。如何强制它们与 @rpath 前缀链接?

【问题讨论】:

【参考方案1】:

这部分回答了我的问题:How to set dyld_library_path in Xcode

我尝试将其自动化,所以当添加任何新库时,它会正确设置,但我放弃了(天哪,为什么必须这么复杂!?)

【讨论】:

【参考方案2】:

TL;DR

使用install_name_tool -change 肯定会为引用的框架/库设置@rpath。但是,它不会更改库本身的名称。

为此,您需要使用install_name_tool -id


使用我目前正在处理的一个项目的粗略示例,其中QtGui.framework(其中包括QtCore 等)是一个名为serialplot.app 的应用程序包中的捆绑框架。

首先运行 install_name_tool -change 以修复 serialplot 应用程序二进制文件调用的 QtGui(和 QtCore 等)的相对路径

$ install_name_tool -change /usr/local/opt/qt@5/lib/QtGui.framework/Versions/5/QtGui @rpath/QtGui.framework/Versions/5/QtGui serialplot.app/Contents/MacOS/serialplot

... (omitted commands for clarity)
 
$ install_name_tool -change /usr/local/opt/qt@5/lib/QtCore.framework/Versions/5/QtCore @rpath/QtCore.framework/Versions/5/QtCore serialplot.app/Contents/MacOS/serialplot

以及install_name_tool -change 修复由QtGui 本身调用的QtCore 的相对路径

$ install_name_tool -change /usr/local/Cellar/qt@5/5.15.2/lib/QtCore.framework/Versions/5/QtCore @rpath/QtCore.framework/Versions/5/QtCore serialplot.app/Contents/Frameworks/QtGui.framework/Versions/5/QtGui

现在在应用程序二进制文件上运行otool -L

serialplot.app/Contents/MacOS/serialplot:
    @rpath/qwt.framework/Versions/6/qwt (compatibility version 6.2.0, current version 6.2.0)
    @rpath/QtSvg.framework/Versions/5/QtSvg (compatibility version 5.15.0, current version 5.15.2)
    @rpath/QtWidgets.framework/Versions/5/QtWidgets (compatibility version 5.15.0, current version 5.15.2)
    @rpath/QtGui.framework/Versions/5/QtGui (compatibility version 5.15.0, current version 5.15.2)
    /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 1671.10.106)
    /System/Library/Frameworks/Metal.framework/Versions/A/Metal (compatibility version 1.0.0, current version 1.0.0)
    @rpath/QtSerialPort.framework/Versions/5/QtSerialPort (compatibility version 5.15.0, current version 5.15.2)
    @rpath/QtNetwork.framework/Versions/5/QtNetwork (compatibility version 5.15.0, current version 5.15.2)
    @rpath/QtCore.framework/Versions/5/QtCore (compatibility version 5.15.0, current version 5.15.2)

所以一切看起来都很好,@rpath 被用于QtGui(以及其他 Qt 框架)。

但是,在应用程序包内捆绑的 QtGui 上运行 otool -L 会显示

serialplot.app/Contents/Frameworks/QtGui.framework/QtGui:
    /usr/local/opt/qt@5/lib/QtGui.framework/Versions/5/QtGui (compatibility version 5.15.0, current version 5.15.2)
    /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 1671.10.106)
    /System/Library/Frameworks/Metal.framework/Versions/A/Metal (compatibility version 1.0.0, current version 1.0.0)
    @rpath/QtCore.framework/Versions/5/QtCore (compatibility version 5.15.0, current version 5.15.2)
    /System/Library/Frameworks/DiskArbitration.framework/Versions/A/DiskArbitration (compatibility version 1.0.0, current version 1.0.0)
    /System/Library/Frameworks/IOKit.framework/Versions/A/IOKit (compatibility version 1.0.0, current version 275.0.0)
    /System/Library/Frameworks/CoreGraphics.framework/Versions/A/CoreGraphics (compatibility version 64.0.0, current version 1247.4.1)
    /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 1560.12.0)
    /System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL (compatibility version 1.0.0, current version 1.0.0)
    /System/Library/Frameworks/AGL.framework/Versions/A/AGL (compatibility version 1.0.0, current version 1.0.0)
    /System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices (compatibility version 1.0.0, current version 50.1.0)
    /usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.11)
    /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.4)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.200.5)
    /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1560.12.0)
    /System/Library/Frameworks/CoreText.framework/Versions/A/CoreText (compatibility version 1.0.0, current version 1.0.0)
    /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)

请注意(如您所说)使用的是绝对路径 (/usr/local/opt/qt@5/lib/),而不是 @rpath

$ otool -L serialplot.app/Contents/Frameworks/QtGui.framework/QtGui 
serialplot.app/Contents/Frameworks/QtGui.framework/QtGui:
    /usr/local/opt/qt@5/lib/QtGui.framework/Versions/5/QtGui (compatibility version 5.15.0, current version 5.15.2)
...

现在运行install_name_tool -id

$ install_name_tool -id @rpath/QtGui.framework/Versions/5/QtGui serialplot.app/Contents/Frameworks/QtGui.framework/Versions/5/QtGui

otool -L 的输出现在可以满足您的需求

$ otool -L serialplot.app/Contents/Frameworks/QtGui.framework/QtGui 
serialplot.app/Contents/Frameworks/QtGui.framework/QtGui:
    @rpath/QtGui.framework/Versions/5/QtGui (compatibility version 5.15.0, current version 5.15.2)
...

是的,它很复杂,也很烦人,但只要有一点耐心,它就可以完美地编写脚本。

有关此特定示例的更多详细信息,请参阅我关于此项目的博客:Porting serialplot to OS X

【讨论】:

以上是关于如何在 Xcode 中将库与 rpath 链接?的主要内容,如果未能解决你的问题,请参考以下文章

在 Windows 中将 VS2005 静态库与 gcc 链接

如何将 .dll 库与 C++ VS 项目链接?

在 Scons 中将“-W1,-rpath=\$ORIGIN”替换为“-W1,-rpath,\$ORIGIN”

我不明白-Wl,-rpath -Wl,

如何在 Eclipse 中将“其他链接器标志”设置为 Xcode?

未加载库:Xcode10 中 UITests 中的 @rpath/libswiftMetalKit.dylib