Other Linker Flags到底是用来干嘛的?
- 它是用来链接的, 一个程序从
代码
到可执行文件
往往要经历以下步骤:
源代码 > 预处理器 > 编译器 > 汇编器 > 机器码 > 链接器 > 可执行文件
为什么我们调用静态库
的方法时候会闪退
- selector not recognized
- 简单来说,因为UNIX 静态库(.a文件) 与 OC 的动态机制不协调导致, 因为Objective-C的链接器并不会为
每个方法
建立符号表,而是仅仅为类
建立了符号表。这样的话,如果静态库中定义了已存在的一个类的分类,链接器就会以为这个类已经存在,不会把分类和核心类
的代码合起来。这样的话,在最后的可执行文件中,就会缺少分类里的代码,这样函数调用就失败了。
- 简单来说,因为UNIX 静态库(.a文件) 与 OC 的动态机制不协调导致, 因为Objective-C的链接器并不会为
UNIX静态库及C程序链接过程:
当一个C语言程序编译时,所有源码会编译为对象文件,即.o文件(object file)。这些对象文件中包含了可执行程序和静态数据。链接器最终将所有文件组合到一起, 产生最终的可执行文件。
当一个源文件
引用了定义在其他文件中
的一些东西时(一个方法),一个 undefined symbol 就写入了它所产生的object 文件中,等待最终被解释掉。在最终构建可执行文件的时,链接器将包含这些undefined symbols的object文件中拉取信息, 解决掉被标记的undefined symbols。
一个UNIX的静态库其实就是一系统object file的集合,一般情况下, 它只会拉取它需要的文件。好处是减小最终可执行文件的大小。
举个例子
比如main.c
使用一个函数,名叫foo( )
,而这个函数定义myMain.c里面。在生成.o文件
的时候,main.o
就会有一个foo( )
的undefined symbols
标记。链接期间,myMain.o
便会被打入最终的可执行文件中。但是,假如还有一个heMain.c
文件,但是里面的函数没被使用,那这个heMain.o
文件便不会出现最后的可执行文件中。
Objective-C链接过程有什么不同?
oc是动态性语言,对象方法的实现
只有到被调用
时候才被确定。基于这个原因,Objective-C没有方法级别
定义符号,只有类级别
定义符号。
举个例子
main.c中包含以下代码: [[FooClass alloc] initWithBar:nil];
那么在链接的时候,main.o文件就会生成一个未定义符号如:(Undefined Symbols) FooClass
,但不会定义initWithBar方法
的符号。
坑在哪?
Category只是一个类的分类
- 如果静态库中已经定义这个类, 链接器就会认为这个类已经存在都链接过了, 还链接啥。不会把
分类
和这个类
的代码合起来, 所以会缺少分类里的代码, 报错selector not recognized
- 如果静态库中没有定义这个类的,Category只是一个方法的集合,而Objective-C没有
方法级别
定义符号。于所以连接器不会加载Cateogry生成的文件。
解决方法
在Other Linker Flags里加上所需的参数,用到的参数一般有以下3个:
-ObjC
-all_load
-force_load
- 首先是-ObjC,连接器会把静态库中所有的Objective-C类和分类都加载到最后的可执行文件中,虽然这样可能会因为加载了很多不必要的文件而导致可执行文件变大
重要提示: 对于64位和iPhone OS应用程序,当静态库只包含类别,没有类, 会存在一个链接器bug,它阻止-ObjC从静态库加载对象文件
- 再说说-all_load, 会让链接器把所有找到的目标文件都加载到可执行文件中
重要提示: 假如你使用了不止一个静态库文件,那么很可能会遇到ld: duplicate symbol错误,因为不同的库文件里面可能会有相同的目标文件
- 最后说说-force_load, 做的事跟-all_load一样, 但是-force_load需要指定库文件路径,这样, 就只是完全加载了一个库文件,不影响其余库文件。
网友评论