我使用简单libvec.a
和addv.o
的AR工具创建了一个简单的静态库multo.o
。目标文件addv.o
包含1个函数符号(addvec
),multo.o
包含1个函数(multvec
)。我还编写了一个简单的程序来测试它(driver.c
,它添加了2个向量并使用了库中的addvec
函数;它还包含了定义函数原型的vector.h
。然后我用
gcc -static driver.o ./libvec.a
一切都很顺利。但起初我尝试用
编译它gcc -static ./libvec.a driver.o
我收到了一个错误:
undefined reference to 'addvec'
我想知道为什么在我首先指定库时出现错误?订单是否重要?
答案 0 :(得分:4)
始终在库,期间之前链接目标文件。至少在你完全了解所发生的事情之前,首先不需要问这个问题。
问题是链接器扫描库,它正在寻找main()
。它没有找到它,因此它不会从库中取出任何东西。然后它会扫描driver.o
,找到正在寻找的内容,但不会找到libvec.a
中的内容(它已经忘记了它们并不相关)。因此,来自libvec.a
的函数是不满意的引用 - 并且链接失败。
请注意库之前的对象文件'链接静态库或共享库时可以使用。
答案 1 :(得分:3)
现在,这完全可以从计算机系统:程序员的透视书中获得。
在符号解析阶段,链接器扫描 可重定位目标文件和归档以相同的顺序从左到右 它们出现在编译器驱动程序的命令行中。 (司机自动 将命令行上的任何.c文件转换为.o文件。)在此扫描期间, 链接器维护一组可重定位目标文件,这些文件将被合并以形成 可执行的,未解决的符号集合U(即,所指的符号,但尚未 已定义),以及在先前输入文件中定义的符号集D. 最初,E,U和D是空的。
对于命令行上的每个输入文件f,链接器确定是否 f是目标文件或存档。如果f是目标文件,则 链接器将f添加到E,更新U和D以反映符号 f中的定义和引用,并进入下一个输入 文件
如果f是归档,则链接器会尝试匹配U中未解析的符号 针对存档成员定义的符号。如果有些存档 member,m,定义一个解析U中引用的符号,然后添加m 到E,链接器更新U和D以反映符号定义和 m中的参考文献。此过程迭代在中的成员对象文件 存档直到达到U和D不再变化的固定点。在 这一点,E中未包含的任何成员对象文件都被简单地丢弃 并且链接器进入下一个输入文件。
如果链接器完成扫描输入文件,则U为非空 在命令行中,它会输出错误并终止。否则,它 合并并重新定位E中的目标文件以构建输出 可执行文件。
不幸的是,这种算法会导致一些令人困惑的链接时错误,因为 命令行上的库和目标文件的排序很重要。如果 定义符号的库出现在目标文件之前的命令行上 引用该符号,然后将不解析和链接引用 会失败。