链接器如何使用静态库解析引用
解析引用过程
在符号解析阶段,链接器从左到右按照它们在编译器驱动程序命令行上的出现顺序来扫描可重定位目标文件和存到文件。
在这次扫描中,链接器维护一个可重定位目标文件的集合E(这个集合中的文件就是确定的最后合并成可执行文件的模块文件),
一个未解析的符合(即引用了但尚未定义的符号)集合U,以及一个已解析(前面已经定义但没有被引用)集合D。
对于命令行上的每个文件 f ,链接器会判断 f 是一个目标文件还是存档文件。
1.判断输入文件类型
如果是目标文件
链接器将会把这个文件添加到集合E,并根据符号引用情况修改集合U和D的状态。然后处理下一个文件。
如果是存档文件
链接器将尝试匹配集合U中未解析的符号和存档文件成员定义的符号,如果存档文件的成员m定义了一个符号来解析U中的一个引用,
那么久将m加入到集合E中,然后修改U和D的状态。对存档文件中的每个成员都重复这个过程,直到U和D不再发生变化,然后简单地丢弃
不包含在集合E中的成员目标文件。然后链接器继续处理下一个文件。
2.判断集合U是否为空
如果链接器扫描完命令行上的所以文件后,集合U仍不为空,则说明引用了未定义的符号,则链接器将会报错并终止程序。
如果链接器扫描完命令行上的所以文件后,集合U仍为空,则将合并和重定位E中的目标文件,并输出可执行文件。
注意命令行上的库和目标文件的顺序
一般将库放在命令行的结尾
1.如果库之间是相互独立的,则可以以任意的顺序放在命令行的结尾处。
2.如果库之间是相互依赖的关系,则必须对他们排序,使得对于每个被存档文件的成员外部引用的符号s,在命令行中至少有一个s的定义是在对s的引用之后的。
例如,a和b表示当前目录中的目标模块或者静态库,而a->b表示a依赖于b,也就是说b定义了一个被a引用的符号。
p.o->libx.a->liby.a且liby.a->libx.a->p.o
可得最小命令行 gcc p.o libx.a liby.a libx.a
注意不要写成 gcc p.o libx.a liby.a libx.a p.o //要注意区分存档文件和目标文件,目标文件将整个添加到E,并不会像存档文件一样遍历。