正常链接过程
假设一个工程里有两个源码文件和两个静态库:
- main.m
实现了程序入口main
,它又调用了未知方法Fun1
和Fun2
- object.m
实现了方法Fun1
和Fun3
,其中Fun1
调用了未知方法Fun4
- libA.a
包含两个目标文件,第一个实现了Fun2
和Fun5
,第二个实现了Fun6
- libB.a
包含一个目标文件,它实现了Fun2
和Fun4
下图是链接过程:

- 解析所有目标文件,生成一个个符号图(符号图用来表示各符号间的引用关系,紫色节点表示未定义符号)
- 将所有的符号图合并成一张符号主图(master graph),中间会用已定义符号替换掉同名的未定义符号。同时生成一张全局符号表,用于记录每个符号的状态。
- 若生成的符号主图中仍存在未定义的符号,则按顺序扫描静态库,否则跳转第6步直接生成可执行文件。
- 静态库其实就是带有符号目录的目标文件集合。若符号目录匹配到了主图所需符号,则从静态库里找到定义该符号的目标文件,并把它所有的符号都合并到主图和全局符号表中,过程中会替换掉已有的同名符号(包括已定义的)。重复执行第3步和第4步,如果所有静态库都扫描完了,仍然存在未定义符号,则报符号找不到的错误
symbol not found
- 如果有需要(一般Release下才做),会进行死代码剥离的操作,即从主图入口(main)开始遍历,不能访问到的节点就是无效可剥离的符号。
- 将主图中的符号都写入可执行文件中去。 每个符号在可执行文件中的地址顺序,与输入文件的先后顺序保持一致。
经典链接错误
-
symbol not found
报错时机:链接过程中扫描完所有的静态库和动态库后,仍然存在未定义的符号。
解决方法:工程中添加定义该符号的静态库,同时添加正确的静态库搜索路径。 -
duplicated symbol
报错时机:- 如果
main.o
和object.o
实现了同名方法,那链接过程中合并符号图时会报错。 - 如果
object.o
和libA.a
中实现了同名方法,而且libA.a
使用了-force_load
描述,它会强行加载libA
中所有的目标文件,导致符号冲突。 - 多个静态库,往往会引用相同的第三方库,极容易冲突。
解决方法:
- 同工程源码中不能定义多个同名方法,可以通过修改方法前缀、修改命名空间(宏替换也可)、使用static方法等方式
- 谨慎使用'-force_load',它主要用来强制加载OC的category,对于纯C++库来说没多大意义。
- 多个静态库冲突时,如果你是第三方库的提供者,应该用使用prelink等方式减少无用符号的导出(参考如何隐藏SDK符号)。如果你只是第三方库使用者(无源码),有一种风险较大的方法就是在其中一个静态库里剔除冲突的目标文件。
- 如果
网友评论