一、引言

通常情况下,对函数库的链接是放在编译时期(compile time)完成的。所有相关的对象文件(object file)与牵涉到的函数库(library)被链接合成一个可执行文件(executable file)。程序在运行时,与函数库再无瓜葛,因为所有需要的函数已拷贝到自己门下。所以这些函数库被成为静态库(static libaray),通常文件名为“libxxx.a”的形式。

其实,我们也可以把对一些库函数的链接载入推迟到程序运行的时期(runtime)。这就是动态链接库(dynamic link library)技术。

         二、动态链接库的特点与优势

首先让我们来看一下,把库函数推迟到程序运行时期载入的好处:

1. 可以实现进程之间的资源共享。

什么概念呢?就是说,某个程序的在运行中要调用某个动态链接库函数的时候,操作系统首先会查看所有正在运行的程序,看在内存里是否已有此库函数的拷贝了。如果有,则让其共享那一个拷贝;只有没有才链接载入。这样的模式虽然会带来一些“动态链接”额外的开销,却大大的节省了系统的内存资源。C的标准库就是动态链接库,也就是说系统中所有运行的程序共享着同一个C标准库的代码段。

2. 将一些程序升级变得简单。

用户只需要升级动态链接库,而无需重新编译链接其他原有的代码就可以完成整个程序的升级。Windows 就是一个很好的例子。

3. 甚至可以真正坐到链接载入完全由程序员在程序代码中控制。

程序员在编写程序的时候,可以明确的指明什么时候或者什么情况下,链接载入哪个动态链接库函数。你可以有一个相当大的软件,但每次运行的时候,由于不同的操作需求,只有一小部分程序被载入内存。所有的函数本着“有需求才调入”的原则,于是大大节省了系统资源。比如现在的软件通常都能打开若干种不同类型的文件,这些读写操作通常都用动态链接库来实现。在一次运行当中,一般只有一种类型的文件将会被打开。所以直到程序知道文件的类型以后再载入相应的读写函数,而不是一开始就将所有的读写函数都载入,然后才发觉在整个程序中根本没有用到它们。

  三、动态链接库的创建

由于动态链接库函数的共享特性,它们不会被拷贝到可执行文件中。在编译的时候,编译器只会做一些函数名之类的检查。在程序运行的时候,被调用的动态链接库函数被安置在内存的某个地方,所有调用它的程序将指向这个代码段。因此,这些代码必须实用相对地址,而不是绝对地址。在编译的时候,我们需要告诉编译器,这些对象文件是用来做动态链接库的,所以要用地址不无关代码(Position IndependentCode (PIC))。

对gcc编译器,只需添加上-fPIC 标签,如:

gcc -fPIC -c file1.c
        gcc -fPIC -c file2.c
        gcc -shared -o libxxx.so    file1.o file2.o

也可以直接生成.so:

gcc -fPIC -shared -o libxxx.so    file1.c file2.c

注意到最后一行,-shared标签告诉编译器这是要建立动态链接库。这与静态链接库的建立很不一样,后者用的是 ar 命令。也注意到,动态链接库的名字形式为 “libxxx.so” 后缀名为 “.so”

        3.1 编译参数解析

最主要的是GCC命令行的一个选项: -shared  。 该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件

-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。

-L.:表示要连接的库在当前目录中

-ltest:编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称

LD_LIBRARY_PATH:这个环境变量指示动态连接器可以装载动态库的路径。

当然如果有root权限的话,可以修改/etc/ld.so.conf文件,然后调用 /sbin/ldconfig来达到同样的目的,不过如果没有root权限,那么只能采用输出LD_LIBRARY_PATH的方法了。

3.2 注意

调用动态库的时候有几个问题会经常碰到,有时,明明已经将库的头文件所在目录 通过 “-I” include进来了,库所在文件通过 “-L”参数引导,并指定了“-l”的库名,但通过ldd命令察看时,就是死活找不到你指定链接的so文件,这时你要作的就是通过修改 LD_LIBRARY_PATH或者/etc/ld.so.conf文件来指定动态库的目录。通常这样做就可以解决库无法链接的问题了。

  四、LINUX下动态链接库的使用

  4.1 重要的dlfcn.h头文件

  LINUX下使用动态链接库,源程序需要包含dlfcn.h头文件,此文件定义了调用动态链接库的函数的原型。下面详细说明一下这些函数。

  4.1.1 dlerror

  原型为: const char *dlerror(void);

  当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时表示操作函数执行成功。

  4.1.2 dlopen

  原型为: void *dlopen (const char *filename, intflag);

  dlopen用于打开指定名字(filename)的动态链接库,并返回操作句柄。

  filename: 如果名字不以/开头,则非绝对路径名,将按下列先后顺序查找该文件。

  (1) 用户环境变量中的LD_LIBRARY值;

  (2) 动态链接缓冲文件/etc/ld.so.cache

  (3) 目录/lib,/usr/lib

  flag表示在什么时候解决未定义的符号(调用)。取值有两个:

  1) RTLD_LAZY : 表明在动态链接库的函数代码执行时解决。

  2) RTLD_NOW : 表明在dlopen返回前就解决所有未定义的符号,一旦未解决,dlopen将返回错误。

  dlopen调用失败时,将返回NULL值,否则返回的是操作句柄。

  4.1.3 dlsym : 取函数执行地址

  原型为: void *dlsym(void *handle, char*symbol);

  dlsym根据动态链接库操作句柄(handle)与符号(symbol),返回符号对应的函数的执行代码地址。由此地址,可以带参数执行相应的函数。

  如程序代码: void (*add)(int x,int y); /* 说明一下要调用的动态函数add */

                      add=dlsym("xxx.so","add");/* 打开xxx.so共享库,取add函数地址 */

                      add(89,369); /* 带两个参数89和369调用add函数 */

  

4.1.4 dlclose : 关闭动态链接库

  原型为: int dlclose (void *handle);

  dlclose用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。

  4.2 在程序中使用动态链接库函数

  4.2.1 程序范例

  下面的程序装载了动态链接库my.so,并用getdate,gettime取得当前日期与时间后输出。

  ----------------------------------------------------------------------

  1 /************************************/

  2 /* 文件名称: dy.c */

  3 /* 功能描述: 动态链接库应用示范程序 */

  6 /************************************/

  7

  8 #include "stdio.h" /* 包含标准输入输出文件 */

  9

  10 #include "dlfcn.h" /* 包含动态链接功能接口文件 */

  11 #define SOFILE "./my.so" /* 指定动态链接库名称 */

  12

  13 #define SHARED /* 定义宏,确认共享,以便引用动态函数 */

  14 #include "datetime.h" /* 包含用户接口文件 */

  15

  16 main()

  17 {

  18 DATETYPE d;

  19 TIMETYPE t;

  20 void *dp;

  21 char *error;

  22

  23 puts("动态链接库应用示范");

  24

  25 dp=dlopen(SOFILE,RTLD_LAZY); /* 打开动态链接库 */

  26

  27 if (dp==NULL) /* 若打开失败则退出 */

  28 {

  29 fputs(dlerror(),stderr);

  30 exit(1);

  31 }

  32

  33 getdate=dlsym(dp,"getdate"); /*定位取日期函数 */

  34

  35 error=dlerror(); /* 检测错误 */

  36 if (error) /* 若出错则退出 */

  37 {

  38 fputs(error,stderr);

  39 exit(1);

  40 }

  41

  42 getdate(&d); /* 调用此共享函数 */

  43 printf("当前日期:%04d-%02d-%02d\n",d.year,d.mon,d.day);

  44

  45 gettime=dlsym(dp,"gettime"); /*定位取时间函数 */

  46

  47 error=dlerror(); /* 检测错误 */

  48 if (error) /* 若出错则退出 */

  49 {

  50 fputs(error,stderr);

  51 exit(1);

  52 }

  53

  54 gettime(&t); /* 调用此共享函数 */

  55 printf("当前时间:%02d:%02d:%02d\n",t.hour,t.min,t.sec);

  56

  57 dlclose(dp); /* 关闭共享库 */

  58

  59 exit(0); /* 成功返回*/

  60

  61 }

  ----------------------------------------------------------------------

程序说明:

  第8行: 包含标准输入输出头文件,因为程序中使用了printf,puts,fputs等标准输入输出函数,需要让编译器根据头文件中函数的原型,检查一下语法;

  第10-11行: 包含动态链接库功能头文件,并定义动态链接库名称;

  第13-14行: 定义宏SHARED以便引用14行的头文件datetime.h中的动态函数说明;

  第25行: 用dlopen打开SOFILE共享库,返回句柄dp;

  第27-31行: 检测dp是否为空,为空则显示错误后退出;

  第33行: 用dlsym取得getdate函数动态地址;

  第35-40行: 如果dlerror返回值不为空,则dlsym执行出错,程序显示错误后退出;

  第42-43行: 执行getdate调用,输出当前日期;

  第45行: 用dlsym取得gettime函数动态地址;

  第47-52行: 如果dlerror返回值不为空,则dlsym执行出错,程序显示错误后退出;

  第54-55行: 执行gettime调用,输出当前时间;

  第57行: 用dlclose关闭dp所指示的动态链接库;

  第59行: 程序退出,返回0值。

  

2.2.2 编写维护文件

  维护文件makefile内容如下:

  ----------------------------------------------------------------------

  1 # makefile :

  2

  3 all : dy

  4

  5 DYSRC = dy.c

  6

  7 DYTGT = $(DYSRC:.c=.o)

  8

  9 %.o : %.c

  10 cc -c $?

  11

  12 # 动态库应用示范程序

  13 dy : $(DYTGT)

  14 cc -rdynamic -s -o $@ $(DYTGT) -ldl

  15

  ----------------------------------------------------------------------

  维护文件说明:

  第3行: 定义所有需要维护的模块;

  第5行: 定义源程序;

  第7行: 定义目标文件;

  第9-10行: 定义.o文件依赖于.c文件,维护代码为“cc -c 变动的源文件名”;

  第13-14行: 定义dy依赖于变量DYTGT指示的值,维护代码中采用-rdynamic选项以指定输出文件为动态链接的方式,选项-s指定删除目标文件中的符号表,最后的选项-ldl则指示装配程序ld需要装载dl函数库。

  4.2.3 运行make命令

  运行make后将产生执行文件dy,运行后将产生如下类似信息:

  动态链接库应用示范

  当前日期: 2012-12-27

  当前时间: 21:10:30

  当删除my.so文件时,将出现以下信息:

  动态链接库应用示范

  my.so: cannot open shared object file: 文件或目录不存在

  五、小结

  LINUX创建与使用动态链接库并不是一件难事。

  编译函数源程序时选用-shared选项即可创建动态链接库,注意应以.so后缀命名,最好放到公用库目录(如/lib,/usr/lib等)下面,并要写好用户接口文件,以便其它用户共享。

  使用动态链接库,源程序中要包含dlfcn.h头文件,写程序时注意dlopen等函数的正确调用,编译时要采用-rdynamic选项与-ldl选项,以产生可调用动态链接库的执行代码。

linux 下动态链接库的创建与使用——dlopen,dlsym相关推荐

  1. 《LINUX下动态链接库的创建与应用》

    大家都知道,在windows系统中有很多的动态链接库(以.dll为后缀的文档,dll即dynamic link library).这种动态链接库,和静态函数库不同,他里面的函数并不是执行程式本身的一部 ...

  2. linux path环境变量检索目录,Linux下动态链接库加载路径及搜索路径问题

    引子 近日,服务器迁移后,偷懒未重新编译nginx的,直接./nginx启动,结果遇到如下问题: "error while loading shared libraries" 这是 ...

  3. Linux下动态链接库调用

    Linux下动态链接库调用 2014-11-01 10:39 3人阅读 评论(0) 收藏 编辑 删除 Linux下动态链接库调用 2013-06-08 20:52:48|  分类:集成开发环境相关 | ...

  4. Linux下动态链接库的查找问题

    Linux下动态链接库的查找问题 上一篇文章我们从 Linux C 编程的角度分析了一下 Linux 中的静态链接库和动态链接库的区别,这篇文章着重从 Linux 编译和运行的角度分析一下 Linux ...

  5. linux lvm添加磁盘,Linux下添加磁盘创建lvm分区

    shell> fdisk /dev/xvdb #### 选择磁盘 Command (m for help): m #### 帮助 Command action a toggle a bootab ...

  6. linux下多线程的创建与等待详解 【转载】

    linux下多线程的创建与等待详解 http://blog.chinaunix.net/uid-23842323-id-2656572.html 所有线程都有一个线程号,也就是Thread ID.其类 ...

  7. linux cvs账户,在linux下为cvs创建用户

    在linux下为cvs创建用户 1.创建可以登陆cvs服务器的用户名和密码: #> su cvsroot #> vi /home/cvsroot/CVSROOT/passwd test1: ...

  8. linux查看进程加载了哪些dll,linux下动态链接库的加载及解析过程

    http://hi.baidu.com/hust_chen/blog/item/54a8c516231d0c0ec93d6d3e.html linux下动态链接库的加载及解析过程(ZZ) 2008-1 ...

  9. linux下使用mdadm组软raid,Linux下使用mdadm创建和管理软raid

    Linux下使用mdadm创建和管理软raid 注:本次操作以RHEL4为例,但应该可以应用到其它大部分的distro上(guess). mdadm的几个常用参数 -C 创建Raid,后面跟参数,代表 ...

最新文章

  1. windows远程桌面如果超出最大连接数, 使用命令行mstsc /console登录即可
  2. 2015/4/24~GET方式和POST方式传值大小的限制
  3. 技术工坊|解密区块链DApp的代码逻辑,从请求到数据存储都要经历什么?(上海)...
  4. WebSocket协议探究(序章)
  5. Win7下IIS7 ASP出现HTTP 500错误的解决办法
  6. 花了一年时间开发出来的基于DXF文件的加工路径自动生成软件
  7. c 站点下html页面拦截器,HTML内容拦截器「HTML Content Blocker」
  8. 13 张图带你学懂 Kubernetes Service(转载)
  9. 【POJ2411】Mondriaan's Dream
  10. 《系统工程》--课程笔记二(系统工程方法论)
  11. 数学建模分享part2--主成分分析(spss)
  12. 离散数学-7 二元关系
  13. adb 截屏和录屏命令
  14. 分数排名 mysql_MYSQL分数排名
  15. element rules不生效
  16. Sort By、Distribute By 使用说明书
  17. linux7/centos7下源码安装nginx-1.16.1详解
  18. 关于电脑注册表regedit自定义管理右键菜单选项实例(删除增加)
  19. Windows 10 ISO 官方镜像下载
  20. 线性SVM与非线性SVM

热门文章

  1. 爬虫第四战爬取糗事百科搞笑段子
  2. 【DFS题型九/双向DFS】王子救公主
  3. 关于CSS动画播放完后消失
  4. 津门杯GoOSS和302重定向漏洞
  5. arduino 红外遥控器控制LED灯
  6. 带你了解无人机的大脑-飞控
  7. 35 | 前端安全:如何打造一个可信的前端环境?
  8. css弹性盒模型详解----flex-direction
  9. USB PD v1.0快速充电通信原理
  10. 计算机初级培训教学大纲,计算机初级培训教学大纲.doc