Linux下动态链接库的使用

Linux下的静态链接库,做起来比较容易,只要将目标文件用ar打包就可以,下面写一下动态链接库的制作和使用方法,完全是根据个人理解和经验总结,有不对的地方还请大家指正。

动态链接库的生成:

代码上与写静态链接库没什么区别,主要是在编译时,以两个文件举例:

复制代码
/*mylib.h*/
void Print();

/*mylib.c*/
#include 
<stdio.h>
#include 
"mylib.h"

void Print()
{
    printf(
"This is in mylib\n");
}
复制代码

编译方法如下:

gcc -fpic -shared mylib.c -o mylib.so

此时将生成mylib.so动态链接库文件。

动态链接库在使用时,分为“隐式调用”和“显式调用”两种,如果是隐式调用,则与静态库的使用方法差不多,注意需要包含导出函数的头文件,即mylib.h:

复制代码
#include <stdio.h>
#include 
"mylib.h"

int main()
{
    Print();
}
复制代码

编译方法:

gcc -o main main.c -L./ mylib.so

注意要加上动态链接库的搜索路径,否则编译器只会到系统路径中去寻找。

显式调用的方式,不必包含mylib.h,但是需要增加几个系统调用:

复制代码
#include <stdio.h>
#include 
<dlfcn.h> // 显式加载需要用到的头文件

int  main()
{
    
void *pdlHandle = dlopen("./mylib.so", RTLD_LAZY); // RTLD_LAZY 延迟加载
    char *pszErr = dlerror();
    
if!pdlHandle || pszErr )
    {
        printf(
"Load mylib failed!\n")
        
return 1;
    }

    
void (*Print)() = dlsym(pdlHandle, "Print"); // 定位动态链接库中的函数
    if!Print )
    {
        pszErr 
= dlerror();
        printf(
"Find symbol failed!%s\n", pszErr);
        dlclose(pdlHandle);
        
return 1;
    }

    Print(); 
// 调用动态链接库中的函数

    dlclose(pdlHandle); 
// 系统动态链接库引用数减1

    
return 0;
}
复制代码

 

可以看到,显式调用的代码看上去要复杂很多,但是却比隐式调用要灵活,我们不必在编译时就确定要加载哪个动态链接库,可以在运行时再确定,甚至重新加载。

看一下显式调用的编译方式:

gcc -ldl -o main main.c

注意要添加-ldl选项,以使用显式调用相关的函数调用。

 

/****************************************************这是一条分割线************************************/

 

2.2  动态调用,使用dl系列函数,完成对动态库函数的调用。

2.2.1 重要的dlfcn.h头文件
    LINUX下使用动态链接库,源程序需要包含dlfcn.h头文件,此文件定义了调用动态链接库的函数的原型。

2.2.2 dlerror
    原型为: const char *dlerror(void);
    当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时表示操作函数执行成功。

2.2.3 dlopen
    原型为: void *dlopen (const char *filename, int flag);
    dlopen用于打开指定名字(filename)的动态链接库,并返回操作句柄。
filename: 如果名字不以/开头,则非绝对路径名,将按下列先后顺序查找该文件。
    (1) 用户环境变量中的LD_LIBRARY_PATH值;
    (2) 动态链接缓冲文件/etc/ld.so.cache
    (3) 目录/lib,/usr/lib
flag表示在什么时候解决未定义的符号(调用)。取值有两个:
    1) RTLD_LAZY : 表明在动态链接库的函数代码执行时解决。
    2) RTLD_NOW : 表明在dlopen返回前就解决所有未定义的符号,一旦未解决,dlopen将返回错误。
    dlopen调用失败时,将返回NULL值,否则返回的是操作句柄。

2.2.4 dlsym : 取函数执行地址
    原型为: void *dlsym(void *handle, char *symbol);
    dlsym根据动态链接库操作句柄(handle)与符号(symbol),返回符号对应的函数的执行代码地址。由此地址,可以带参数执行相应的函数。
如程序代码: void (*print_func)(char *buf); /* 说明一下要调用的动态函数print_func*/
    print_func=dlsym("libfunc.so","print"); /* 打开libfunc.so共享库,取print函数地址 */
    print_func("John"); /* 调用print_func函数 */

2.2.5 dlclose : 关闭动态链接库
    原型为: int dlclose (void *handle);
    dlclose用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。

 

2.3
执行程序时若出现error while loading shared libraries: libfunc.so: cannot open shared object file: No such file or directory


很明显,是动态库的路径不正确,编译时用-L指定的库文件路径,在执行文件时不起作用了.怎样让可执行文件找到我们自己建立的库呢?这里有几种方法:

( a ) 将库文件libfunc.so拷贝到/usr/lib 或 /lib 或 /usr/local/lib下,默认情况下,系统从这几个地方寻找库文件.
( b ) 导出 符号LD_LIBRARY_PATH,如export  LD_LIBRARY_PATH=/apps/src/demo/如果有多条路径,用 ‘:’ 分割.
( c ) 将库文件的路径添加到 /etc/ld.so.conf 中去,并执行/sbin/ldconfig
( d )在编译链接时添加选项目 -Wl,--rpath指定,如:gcc -Wl,--rpath,/apps/src/demo/ -L/apps/src/demo/ test.c -lfunc -o test 或者 gcc -Wl,--rpath -Wl,/apps/src/demo/ -L/apps/src/demo/ test.c -lfunc -o test


补充:查看文件使用的动态库用ldd命令.

 

转自:http://www.cnblogs.com/Xiao_bird/archive/2010/03/01/1675821.html
        http://www.rosoo.net/a/201101/10780.html
还可参考:http://blog.csdn.net/jenshy/article/details/674621

posted @ 2013-03-04 21:50  wust.zjf  阅读(417)  评论(0编辑  收藏  举报