|
上面的代码执行结果如下:
$ make ab gcc main.c -c gcc a.c -c ar -cr liba.a a.o gcc b.c -c ar -cr libb.a b.o gcc main.o -L. -la -lb $ ./a.out This is a $ make ba gcc main.o -L. -lb -la $ ./a.out This is b |
解释如下:
链接过程中从左向右扫描目标文件和库中的符号,并维护一个Undefined符号表。在遇到main.o时,由于test函数未定义,Undefined符号表中记录下test。接下来,如果先链接liba.a,则由liba.a提供test函数的实现,并且由于链接完liba.a后已经没有未解决的符号了,后面的libb.a不会再扫描,链接过程结束,main函数中的test函数为a.c中的实现。当链接顺序反过来时,则只会链接liba.a。
|
执行结果:
$ make ab gcc main.c -c gcc a.c -c ar -cr liba.a a.o gcc b.c -c ar -cr libb.a b.o gcc main.o -L. -la -lb /usr/bin/ld: ./libb.a(b.o): in function `test': b.c:(.text+0x0): multiple definition of `test'; ./liba.a(a.o):a.c:(.text+0x0): first defined here collect2: error: ld returned 1 exit status make: *** [Makefile:5: ab] Error 1 $ make ba gcc main.o -L. -lb -la /usr/bin/ld: ./liba.a(a.o): in function `test': a.c:(.text+0x0): multiple definition of `test'; ./libb.a(b.o):b.c:(.text+0x0): first defined here collect2: error: ld returned 1 exit status make: *** [Makefile:8: ba] Error 1 |
解释如下:
链接过程同样是从左向右扫描目标文件和库中的符号,并维护Undefined符号表。在遇到main.o时,由于test函数和外部变量a、b都未定义,Undefined符号表中记录下这三项。接下来,如果先链接liba.a,则由liba.a提供test函数和变量a的定义,但此时还有变量b未解决,所以会继续链接后面的库。接下来是链接libb.a,libb.a中有变量b的定义,但还有一个test函数的定义,由于静态链接中没有全局符号介入问题,并且两个test函数的符号优先级相同,所以报重复定义错误。不管是先链接liba.a还是先链接libb.a都存在同样的问题。
|
执行结果:
$ make ab gcc main.c -c gcc a.c -c ar -cr liba.a a.o gcc b.c -c ar -cr libb.a b.o gcc main.o -L. -la -lb /usr/bin/ld: ./libb.a(b.o): in function `testb': b.c:(.text+0x9): undefined reference to `testa' collect2: error: ld returned 1 exit status make: *** [Makefile:5: ab] Error 1 $ make ba gcc main.o -L. -lb -la $ ./a.out This is a |
解释如下:
链接过程同样是从左向右扫描目标文件和库中的符号,并维护Undefined符号表。在遇到main.o时,由于testb函数未定义,Undefined符号表中记录下testb。接下来,如果先链接liba.a,由于liba.a中并没有提供testb函数,而此时链接器还没遇到libb.a,不知道libb.a需testa函数,所以链接器认为liba.a对整个链接过程没作用,直接抛弃掉了。接下来遇到libb.a,libb.a提供了testb函数的实现,但需要testa函数的实现,而前面的liba.a已经被抛弃了,所以报未定义错误。
以上过程如果反过来,先链接libb.a,再链接liba.a,则不会有问题。
总结起来就是,链接器链接时如果发现一个库对当前的链接没有作用,那就会跳过这个库,不管后续的库是否对这个库有依赖。
|
执行结果:
$ make ab gcc main.c -c gcc -fPIC -shared a.c -o liba.so gcc -fPIC -shared b.c -o libb.so gcc main.o -L. -la -lb -Wl,-rpath=. $ ./a.out This is a $ make ba gcc main.o -L. -lb -la -Wl,-rpath=. $ ./a.out This is b |
结果解释:
同静态库,liba.so和libb.so只要链接一个就可以解决所有的符号冲突,整个链接过程就结束了,所以先链接哪个就用哪个的实现。
通过ldd命令查看生成的可执行文件中依赖的动态库也可以验证上面的结论,如下:
$ make ab gcc main.o -L. -la -lb -Wl,-rpath=. $ ldd a.out linux-vdso.so.1 (0x00007ffc593a0000) liba.so => ./liba.so (0x00007fa175d70000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa175b76000) /lib64/ld-linux-x86-64.so.2 (0x00007fa175d7c000) $ make ba gcc main.o -L. -lb -la -Wl,-rpath=. $ ldd a.out linux-vdso.so.1 (0x00007ffd41d2d000) libb.so => ./libb.so (0x00007fe5505b3000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe5503b9000) /lib64/ld-linux-x86-64.so.2 (0x00007fe5505bf000) |
可以看到,生成的可执行文件只会依赖liba.so或libb.so中的一个。
|
执行