如何在Xcode 4中使用dylib文件创建工作框架
我在Xcode中创建了一个新的可可框架,除了支持文件以外,它删除了它包含的所有库和文件。
我有2个文件:
add.h
#ifndef add_add_h
#define add_add_h
void add(void);
#endif
和
add.c
#include <stdio.h>
#include "add.h"
void add(void)
{
printf("adfding");
}
在构建阶段,我添加了add.c来编译源代码,add.h来编译头文件public。 项目构建没有问题,但在框架中没有dylib文件,并且当我将框架拖放到另一个项目时,它表示无法找到dylib文件。
dyld: Library not loaded: @rpath/add.framework/Versions/A/add
Referenced from: /Users/vjoukov/Desktop/Projects/test/build/Debug/test.app/Contents/MacOS/test
Reason: image not found
我怎样才能制作一个简单的框架,并保持里面的dylib文件?
我认为你误解了错误信息。
.framework
作为动态库工作,但在.framework文件夹内不会有任何带有实际.dylib
文件扩展名的Mach-O可加载对象文件。
有几个原因可能会在运行时从dyld
(动态链接库加载器)中获取该错误消息。 首先是你忘记在构建过程中将.frameworks复制到构建的应用程序包中。 虽然可以将它们复制到应用程序包内的任何位置,但传统位置在AppName.app/Contents/Frameworks/中。 如果您还没有这样做,请选择“项目”>“新建构建阶段”>“新建文件构建阶段”。 将目标弹出框更改为框架,如下图所示。
然后将框架图标拖到文件夹中,以便在构建过程中将其复制。
在运行时无法找到框架的第二个也是更可能的原因是,您没有为主要可执行文件指定任何运行路径搜索路径。 (这是必须的,因为正如我们从错误消息中看到的那样,您的框架是使用更新的@rpath/
style安装名称( @rpath/add.framework/Versions/A/add
)而不是旧的@executable_path/
或@loader_path/
styles)。
假设您将自定义框架复制到上述位置,您可以添加@loader_path/../Frameworks
的运行路径搜索路径条目,如下图所示:
以下摘录解释了在运行时如何找到动态库来自dyld
的联机帮助页面:
动态库加载
与许多其他操作系统不同,达尔文没有通过它们的叶文件名来定位相关的动态库。 而是使用每个dylib的完整路径(例如/usr/lib/libSystem.B.dylib
)。 但有时候完整路径不合适; 例如,可能希望您的二进制文件可以安装在磁盘上的任何位置。 为了支持这一点,有三个@xxx/
变量可以用作路径前缀。 在运行时, dyld
用@xxx/
前缀替代动态生成的路径。
@executable_path/
该变量将替换为包含进程主要可执行文件的目录的路径。 这对于加载嵌入到.app目录中的dylib /框架非常有用。 如果主要可执行文件位于/some/path/My.app/Contents/MacOS/My
并且框架dylib文件位于
/some/path/My.app/Contents/Frameworks/Foo.framework/Versions/A/Foo
,那么框架加载路径可以编码为@executable_path/../Frameworks/Foo.framework/Versions/A/Foo
和.app目录可以在文件系统中移动, dyld
仍然可以加载嵌入式框架。
@loader_path/
该变量被替换为包含使用@loader_path
包含加载命令的mach-o二进制文件的目录的路径。 因此,在每个二进制文件中, @loader_path
解析为不同的路径,而@executable_path
始终解析为相同的路径。 如果插件的最终文件系统位置未知(因此无法使用绝对路径),或者插件被多个插件使用,则@loader_path
可用作插件中嵌入的framework / dylib的加载路径应用程序(所以@executable_path
不能使用)。 如果插件mach-o文件位于/some/path/Myfilter.plugin/Contents/MacOS/Myfilter
并且框架dylib文件位于/some/path/Myfilter.plugin/Contents/Frameworks/Foo.framework/Versions/A/Foo
,则框架负载路径可以编码为@loader_path/../Frameworks/Foo.framework/Versions/A/Foo
和Myfilter.plugin
目录可以围绕在文件系统中移动,并且dyld
仍然会能够加载嵌入式框架。
@rpath/
Dyld维护一个称为运行路径列表的路径的当前堆栈。 遇到@rpath
时,它将被运行路径列表中的每个路径替换,直到找到可加载的dylib。 运行路径堆栈是根据导致当前dylib加载的LC_RPATH
链中的LC_RPATH
加载命令构建的。 可以添加一个LC_RPATH
到图像加载命令与-rpath
选项ld
(1)。 您甚至可以添加以@loader_path/
开头的LC_RPATH
加载命令路径,并且它将在运行路径堆栈上推送相对于包含LC_RPATH
的映像的LC_RPATH
。 当你有一个复杂的程序和dylibs目录结构时, @rpath
的使用是非常有用的,它可以被安装在任何地方,但保持它们的相对位置。 这个场景可以使用@loader_path
来实现,但是dylib的每个客户端可能需要不同的加载路径,因为它在文件系统中的相对位置是不同的。 @rpath
的使用引入了简化事物的间接级别。 您在目录结构中选择一个位置作为定位点。 每个dylib都会得到一个以@rpath
开头的安装路径,并且是dylib相对于定位点的路径。 每个主要可执行文件都与-rpath @loader_path/zzz
,其中zzz
是从可执行文件到定位点的路径。 在运行时, dyld
将其运行路径设置为定位点,然后每个dylib都相对于定位点找到。
上一篇: How do I create a working framework with dylib files in Xcode 4