gcc编译器遇到的部分问题的总结(二)

 

继续上次的接着写,还有一种常见的错误,也是undefined reference to symbol XXX,但是底下会加上一句:note: 'XXX' is defined in DSO xxx.so so try adding it to the linker command line,当然,这个问题本质上也是一个找不到符号的问题,我们通过再链接参数上增加该库名的问题也能解决这个问题,但是这个错误多出了这一条提示,毕竟与通常的符号未找到有些区别的,下面我们通过一个例子来分析这个问题。

foo1.c

#include <stdio.h>
extern int bar (); 
int main ()
{
    printf ("%d\n", bar ());
}
foo2.c

extern int foo (); 
int bar () { return foo (); }
foo3.c

int foo () { return 0; }

以上是三个很简单的C程序源文件,foo3.c中有一个函数foo(),foo2.c中定义了一个函数bar(),其中调用了函数foo(),foo1.c是主程序,调用bar()函数。直接编译当然没问题,按照上篇讲的,按照调用顺序编译gcc foo1.c foo2.c foo3.c -o foo,没有任何问题。下面我们尝试将其中的一些函数编译成动态链接库。

gcc -c foo1.c foo2.c foo3.c -fPIC

gcc -o foo3.so foo3.o -shared

gcc -o foo2.so foo2.o foo3.so -shared

gcc -o foo foo1.o foo2.so

没有任何问题,程序正常执行。

接着我们将foo1.c稍作修改:

foo1.c

#include <stdio.h>
extern int bar (); 
extern int foo (); 
int main ()
{
    printf ("%d\n", bar ());
    foo();
}

我们在main()函数中增加了直接对foo3.c中的foo()函数的调用。下面重新编译foo1.c

 

出现这个问题了,链接器说找不到符号foo,当然了,我们知道,foo函数在foo3.so中,我们编译命令里没加上foo3.so,当然找不到,加上foo3.so,依然能成功编译。

但是这个note是为什么呢。其实也不难明白,因为我们的foo2.so中也调用了这个foo这个函数,而且我们在编译foo2.so的时候已经将foo3.so作为foo2.so的一个NEEDED项。可以使用readelf -d foo2.so命令查看下:

因此,编译器给你个提示,我虽然没找到foo这个符号(所以要报错undefined reference to symbol),但是可以提示你一下,你其他的DSO(dynamic shared object)中用到过这个符号。那么该如何利用foo2.so中添加过的这个foo函数的符号来解决这个链接问题呢,很简单,告诉链接器,直接把foo2.so中需要用到的东西(带NEEDED标识的)原样copy到主程序中就可以啦,那么,foo2.so中用过的so库,主程序在链接时就不用再写一遍啦。告诉链接器的参数就是--copy-dt-needed-entries。gcc命令中直接写的时候前面要加上"-Wl,"参数,告知编译器后面的参数不是编译器参数,而是链接器参数。

 

成功编译运行!

posted @ 2017-05-22 09:26  重复啦  阅读(916)  评论(0编辑  收藏  举报