Linux下用g++编译共享库的一个问题
最近在使用linux下的共享库so的时候遇到一个奇怪的问题,做个记录,方便备查。
一般来说,如果用gcc编译的时候加上-shared和-fPIC选项,可以把源文件编译成一个so文件,可以在其他源程序连接阶段把这个链接上去,从而可以调用so文件提供的函数接口,这样可以多文件共用一个so文件提供的函数,即节省内存空间,也便于更新,所有的接口只需要更新so文件就行。
其实除了上面的方法,还有一个方法,那就是在运行时由程序自己动态加载so文件,使用一系列系统调用如dlopen,dlsym,dlclose等来进行动态加载,获取函数地址从而进行函数调用,关闭加载的so文件等。
一般以第一种方法用得多,但是第二种方法更灵活,结合配置文件,更具一般意义上的服务扩展性。 但是就是在用第二种方法的时候出现了一点问题。
这里把问题抽象一下,假设有一个源文件是要编译为so文件的,假设这个源文件只提供一个简单的函数,add,取两个整数为参数,返回它们的和,源文件为add.c,代码如下:
#include <stdio.h> int add(int a, int b) { return a+b; }
gcc -shared -fPIC add.c -o libadd.so
#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)
extern "C" { // the function code ... }
$ nm libadd.so |grep add
00000000000005dc T add