7

我正在处理 XCode 的一个奇怪行为:

dyld: Library not loaded: /Library/Frameworks/SBJson.framework/Versions/A/SBJson

基本上它忽略了实际上是我的Runpath Search Path( ) 配置。LD_RUNPATH_SEARCH_PATHS@loader_path/../Frameworks

我现在无法加载任何嵌入式框架:/

otool

otool -L /Users/kilian/Library/Developer/Xcode/DerivedData/r-ghohkslxtxgpnuepmblogfjtuefx/Build/Products/Debug/r.app/Contents/MacOS/r
/Users/kilian/Library/Developer/Xcode/DerivedData/r-ghohkslxtxgpnuepmblogfjtuefx/Build/Products/Debug/r.app/Contents/MacOS/r:
  /System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa (compatibility version 1.0.0, current version 19.0.0)
  /Library/Frameworks/SBJson.framework/Versions/A/SBJson (compatibility version 1.0.0, current version 37.0.0)
  /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 945.0.0)
  /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
  /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 169.3.0)
  /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 1186.0.0)

PS 如果您想知道我是否将副本添加到框架构建阶段,答案是肯定的。

4

1 回答 1

19

短版

问题是,当您构建时SBJSON.framework,安装名称未配置为使用@rpath. 因此,当您的应用程序加载动态库时,它会查找/Library/Frameworks而不是您的应用程序的运行路径告诉它查找的位置。

要修复它,您需要更改SBJSON.framework目标上的构建设置。将动态库安装名称设置更改为@rpath/${EXECUTABLE_PATH}. 然后再次构建,链接到新构建的框架,你就可以开始了。

长版

框架的核心只是动态库。这意味着库中包含的代码不会嵌入到您的应用程序中,而是在运行时SBJSON.framework从包中拉入。为此,您的应用需要知道在哪里寻找动态库。

这样做的方式是,当您链接到一个框架时,链接器实际上并没有将整个库嵌入到您的应用程序中。相反,它只是添加了一小部分,告诉应用程序在运行时在哪里可以找到库。当然,这意味着编译器必须知道库在运行时的位置。它通过查看动态库的“安装名称”来查找该信息。

动态库的“安装名称”本质上只是库的预期路径。从历史上看,大多数动态库和框架都是在系统范围内共享的。Foundation.framework和之类的东西CoreData.framework,例如,存在于 中/System/Library/Frameworks,所有应用程序都可以合理地期望在那里找到它们。因此,在CoreData.framework构建时,其安装名称设置为/System/Library/Frameworks/.... 当 Xcode 将您的应用程序与 Core Data 链接时,它会查看框架的安装名称,并告诉它在应用程序启动时在该路径的框架中加载。

这一切都很好,但是当您需要在应用程序中嵌入框架时,它对您没有帮助。您不知道应用程序在运行时将位于系统的哪个位置。用户可以从 运行它/Applications,但他们也可以从 运行它~/Downloads。您无法提供单一路径作为安装名称,该名称在运行时始终正确指向框架。

为了解决这个问题,您可以将框架的安装名称设置为@loader_path/../Frameworks. 当动态加载器看到@loader_path时,它会将其替换为当前正在加载的应用程序的路径。使用此安装名称将允许将框架安装在Frameworks任何应用程序的文件夹中。

然而,事情仍然不完美。该框架仍在规定它应该放在哪里。例如,如果另一个应用程序想要将框架放在Libraries文件夹中,那么它就很不走运。框架负责它可以放置的位置,而不是应用程序。这是依赖树的反转,并不理想。无论其他框架做什么,应用程序都应该能够从想要存储它的任何地方加载框架。

因此,在 OS X 10.5@rpath中引入了。如果 dylib 或框架的安装名称以 开头@rpath,则加载器将转身询问应用程序“运行路径搜索路径”是什么,并将其替换。这允许应用程序指定其框架的位置。通过使用@rpath,框架将决策委托给应用程序。应用程序可以根据需要使用@loader_path,也可以根据需要指定绝对路径。它甚至可以指定一整套应用程序将使用的共享文件夹。

你的问题

所以,关于你的问题。您正确地将应用程序的运行路径搜索路径设置为@loader_path/../Frameworks. 但是,框架的安装名称没有使用@rpath; 事实上,它仍然使用硬编码的路径来/Library/Frameworks/.... 由于框架的安装名称不使用@rpath,因此甚至不咨询应用程序的运行路径。它只是试图从/Library文件夹中链接 SBJSON。由于它不存在,因此您的应用程序在启动之前就崩溃了。

您需要更改 SBJSON 框架的安装名称以使用@rpath. 将动态库安装名称设置为@rpath/${EXECUTABLE_PATH}。(${EXECUTABLE_PATH}是内部动态库的相对路径,来自包含框架的文件夹。)

使用新安装名称构建框架后,您应该能够链接到新框架,确保将其复制到应用程序包的Frameworks/文件夹中,一切顺利!

@rpathPS 如果这还不是很清楚,Mike Ash 对和朋友们做了很好的评论。你可以在这里找到它

于 2012-09-01T06:19:41.557 回答