








Linux下用g++编译共享库的一个问题
最近在使用linux下的共享库so的时候遇到一个奇怪的问题,做个记录,方便备查。
一般来说,如果用gcc编译的时候加上-shared和-fPIC选项,可以把源文件编译成一个so文件,可以在其他源程序连接阶段把这个链接上去,从而可以调用so文件提供的函数接口,这样可以多文件共用一个so文件提供的函数,即节省内存空间,也便于更新,所有的接口只需要更新so文件就行。
其实除了上面的方法,还有一个方法,那就是在运行时由程序自己动态加载so文件,使用一系列系统调用如dlopen,dlsym,dlclose等来进行动态加载,获取函数地址从而进行函数调用,关闭加载的so文件等。
一般以第一种方法用得多,但是第二种方法更灵活,结合配置文件,更具一般意义上的服务扩展性。 但是就是在用第二种方法的时候出现了一点问题。
这里把问题抽象一下,假设有一个源文件是要编译为so文件的,假设这个源文件只提供一个简单的函数,add,取两个整数为参数,返回它们的和,源文件为add.c,代码如下:
1 2 3 4 5 6 | #include <stdio.h> int add( int a, int b) { return a+b; } |
gcc -shared -fPIC add.c -o libadd.so
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | #include <stdio.h> #include <stdlib.h> #include <dlfcn.h> int main( int argc, char *argv[]) { void * handle; int (*func)( int , int ); char *error; handle = dlopen( "libadd.so" , RTLD_LAZY); if (!handle) { fprintf (stderr, "%s\n" , dlerror()); exit (1); } func = ( int (*)( int , int ))dlsym(handle, "add" ); if ((error = dlerror()) != NULL) { fprintf (stderr, "%s\n" , error); exit (1); } func(3, 4); dlclose(handle); return 0; } |
gcc test.c -o test -ldl
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
./libadd.so: undefined symbol: add
$ nm libadd.so |grep add
00000000000005ec T _Z3addii
$ c++filt _Z3addii
add(int, int)
1 2 3 4 | extern "C" { // the function code ... } |
$ nm libadd.so |grep add
00000000000005dc T add