Xcode上的Other Linker Flags参数详解
Other Linker Flags
因为项目中遇到相关问题,对多篇文章进行了融合记录。
Other Linker Flags位置
在Xcode的工程中Tergets -> Build Settings -> linking -> Other Linker Flags,链接系统的标准库 ,链接其他三方库的参数,引用链接器参数
原理介绍
从C代码到可执行文件经历的步骤是:
源代码 > 预处理器 > 编译器 > 汇编器 > 机器码 > 链接器 > 可执行文件
- 预处理器(预编译):在该阶段,编译器将C或者OC中源代码中包含的stdio.h和#import 的库编译进来
- 编译器:在这个阶段,编译器首先要检查代码的规范性,是否有语法错误等,用来确定代码实际要做的工作,在检查无误后,编译器把代码翻译成汇编语言
- 汇编器:汇编阶段把编译阶段生成的汇编代码转化成二进制目标文件
- 链接器:将不同部分的代码和数据收集和组合成一个单一文件的过程,也就是把不同目标文件合并成最终可执行文件的过程,将编译输出的二进制文件链接成最终可执行的目标文件
- 在最后一步需要把.o文件和C语言运行库链接起来,这时候需要用到ld命令。源文件经过一系列处理以后,会生成对应的.obj文件,然后一个项目必然会有许多.obj文件,并且这些文件之间会有各种各样的联系,例如函数调用。
- 静态库:是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时就不需要额外的库文件(.a) 。
- 动态库:在程序执行时,由运行时链接文件加载库,这样可以节省系统的开销(.so)。
通过这个流程你也应该知道,为什么在编译的过程中没事,而在运行的时候就会报错了。
那我们为什么要设置Other Linker Flags呢?
因为Other Linker Flags其实就是链接器工作时,除了默认参数外的其他参数。Other linker flags设置的值实际上就是ld命令执行时后面所加的参数。
常用参数
下面逐个介绍3个常用参数:
-ObjC
:
加了这个参数后,链接器就会把静态库中所有的Objective-C
类和分类都加载到最后的可执行文件中。
这样编译之后的app会变大(因为加载了其他的Objc代码进来)。但是如果静态库中有类和category的话,只有加入这个flag才行。
但是Objc也不是万能的,当静态库中只有分类而没有类的时候,Objc就失效了,这就需要使用-all_load
或者-force_load
了。-all_load
:
这个flag是专门处理-ObjC
的一个bug的。用了-ObjC
以后,如果类库中只有category没有类的时候这些category还是加载不进来。变通方法就是加入-all_load
或者-force-load
。
-all_load
会让链接器把所有找到的目标文件都加载到可执行文件中,即使没有Objc代码,所以千万不要随便使用这个参数!假如你使用了不止一个静态库文件,然后又使用了这个参数,那么你很有可能会遇到ld: duplicate symbol错误,因为不同的库文件里面可能会有相同的目标文件。
这里会有两种方法解决:- 用命令行就行拆包;
- 在遇到-ObjC失效的情况下使用
-force_load
参数 。
-force_load
:
所做的事情跟-all_load
其实是一样的,但是-force_load
需要指定要进行全部加载的库文件的路径,这样的话,你就只是完全加载了一个库文件,不影响其余库文件的按需加载。
总结
个人建议-ObjC
与-force_load
搭配使用比较好。
包含静态库时候需要在Target的Other Linker Flags里面加上值:-ObjC
,-all_load
,-force_load
。
-ObjC
就是会加载静态库文件中实现一个类或者分类的所有成员;-all_load
会强迫链接器加载所有静态库中的所有对象文件,甚至那些没有OC代码的文档;-force_load
(包的路径)就是会加载指定路径的静态库文件中的所有成员,它允许finer得到文档加载的控制,每一个-force_load
操作必须跟着一个文档路径,文档中的每一个对象文件将会被加载。