/*
 * author: hjjdebug
 * date: 2012
 * title: linux 动态链接库的创建和使用--动态连接
*/

动态连接,链接程序(gcc等)链接时无需指定第三方动态连接库,而是由调用者显式调用指定库,并获取对应库的函数入口地址

linux 动态链接库的创建和使用
1. 先创建一个动态链接库。源码如下:
$ cat max.cpp
extern "C"
{
    int max(int a, int b)
    {
        return a>b? a:b;
    }
}
加上extern "C", 是为了导出函数名称不用C++格式,而用C格式
编译生成动态库
g++ -shared -o libmax.so max.cpp

把库copy 到系统目录。

sudo cp libmax.so /lib

具体copy 到哪里可以用strace 跟踪一下, 它会按一定次序搜索目录加载。


2. 再创建一个测试用例,源码如下:
gitserver@gitserver-desktop:~/share/android4.0.3/hjj/pc$ cat test_d.cpp
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>    // 动态加载的函数头文件
// int max(int a, int b);
typedef int (*maxptr)(int a, int b);
int main(int argc, char *argv[])
{
        maxptr max;        // 定义max 型函数指针
        void *handle = dlopen("libmax.so",RTLD_LAZY);
        if(!handle)
        {
                printf("error open librayry libmax.so");
                exit(1);
        }
        max = (maxptr)dlsym(handle,"max");
        if(!max)
        {
                char *err=dlerror();
                printf("%s",err);
                exit(2);
        }
        int a=max(3,5);
        printf("the bigger is %d\n",a);
        dlclose(handle);
        return 0;
}

编译生成可执行文件
g++ -o test test.cpp -ldl

libdl.so 是必需的动态库

3. 运行可执行文件。
$ ./test
the bigger is 5

注意:
当没有用extern "C" 包含代码时, 运行会出现下列错误。
/lib/libmax.so: undefined symbol: max
你可以用nm 来查看libmax.so, 看其输出符号到底是什么,一看,知道应该用C 名称导出。
其它常见错误为:
1.没有包含dlfcn.h 头文件, 引起编译错误
test_d.cpp: In function ‘int main(int, char**)’:
test_d.cpp:9:36: error: ‘RTLD_LAZY’ was not declared in this scope
test_d.cpp:9:45: error: ‘dlopen’ was not declared in this scope
test_d.cpp:15:34: error: ‘dlsym’ was not declared in this scope
test_d.cpp:18:21: error: ‘dlerror’ was not declared in this scope
test_d.cpp:24:16: error: ‘dlclose’ was not declared in this scope

2.连接没有包含libdl.so, 出现连接错误
$ g++ -o test_d test_d.cpp  
/tmp/ccv8xKSN.o: In function `main':
test_d.cpp:(.text+0x19): undefined reference to `dlopen'
test_d.cpp:(.text+0x50): undefined reference to `dlsym'
test_d.cpp:(.text+0x60): undefined reference to `dlerror'
test_d.cpp:(.text+0xbd): undefined reference to `dlclose'
collect2: ld returned 1 exit status

3. 生成动态库没有采用-share 选项,出现连接错误
$ g++ -o libmax.so max.cpp
/usr/lib/gcc/i686-linux-gnu/4.6.1/../../../i386-linux-gnu/crt1.o: In function `_start':
(.text+0x18): undefined reference to `main'
collect2: ld returned 1 exit status

4. 当动态库中调用printf 等调用时,编译需要加上 -fPIC 选项(生成位置无关代码)否则出错

/usr/bin/ld: /tmp/ccVnb7rP.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
/tmp/ccVnb7rP.o: could not read symbols: Bad value

所以完整的编译选项是:

g++ -shared -fPIC -o libmax.so max.cpp


调试动态库与调试普通代码没有差别, 当然,要加上-g 选项才能跟踪代码调试。



Logo

更多推荐