大家都知道,在WINDOWS系统中有很多的动态链接库(以.DLL为后缀的文件,DLL即Dynamic Link Library)。这种动态链接库,和静态函数库不同,它里面的函数并不是执行程序本身的一部分,而是根据执行程序需要按需装入,同时其执行代码可在多个执行程序间共享,节省了空间,提高了效率,具备很高的灵活性,得到越来越多程序员和用户的青睐。那么,在LINUX系统中有无这样的函数库呢?

答案是肯定的,LINUX的动态链接库不仅有,而且为数不少。在/lib目录下,就有许多以.so作后缀的文件,这就是LINUX系统应用的动态链接库,只不过与WINDOWS叫法不同,它叫so,即Shared Object,共享对象。(在LINUX下,静态函数库是以.a作后缀的) X-WINDOW作为LINUX下的标准图形窗口界面,它本身就采用了很多的动态链接库(在/usr/X11R6/lib目录下),以方便程序间的共享,节省占用空间。著名的APACHE网页服务器,也采用了动态链接库,以便扩充程序功能。你只需将PHP动态链接库拷到其共享目录,修改一下配置,APACHE就可以支持PHP网页了。如果你愿意,可以自己编写动态链接库,让APACHE支持你自己定义的网页格式。这就是动态链接的好处。

1、LINUX下动态链接库的创建
       在LINUX系统下,创建动态链接库是件再简单不过的事情。只要在编译函数库源程序时加上-shared选项即可,这样所生成的执行程序即为动态链接库。从某种意义上来说,动态链接库也是一种执行程序。按一般规则,程序名应带.so后缀。下面举个例子说说。我准备编写两个函数,一个用于查询当前日期getdate,一个用于查询当前时间gettime,并将这两个函数存于动态链接库my.so中。为此,需要做以下几项工作。

1.1 编写用户接口文件datetime.h,内容如下(每行前面的数字为行号):

  1. /* datetime.h :*/
  2. #ifndef __DATETIME_H
  3. #define __DATETIME_H
  4. /* 日期结构 */
  5. typedef struct
  6. {
  7. int year;
  8. int mon;
  9. int day;
  10. }DATETYPE;
  11. /* 时间结构 */
  12. typedef struct
  13. {
  14. char hour;
  15. char min;
  16. char sec;
  17. } TIMETYPE;
  18. /* 函数原型说明 */
  19. #ifdef SHARED
  20. int (*getdate)(DATETYPE *d);
  21. #else
  22. int getdate(DATETYPE *d);
  23. #endif
  24. #ifdef SHARED
  25. int (*gettime)(TIMETYPE *t);
  26. #else
  27. int gettime(TIMETYPE *t);
  28. #endif
  29. #endif

这个用户接口文件中,先定义了日期与时间结构,接着定义一下函数的原型。动态函数与静态函数的原型说明不同的是,动态函数应使用(*函数名)的形式,以便引用其指针。若要引用文件中的动态函数说明,用户应该定义一下SHARED宏,这样才能使用。

1.2 编写getdate.c,源程序如下:

  1. /* getdate.c : */
  2. #include "time.h"
  3. #include "datetime.h"
  4. int getdate(DATETYPE *d)
  5. {
  6. long ti;
  7. struct tm *tm;
  8. time(&ti);
  9. tm=localtime(&ti);
  10. d->year=tm->tm_year+1900;
  11. d->mon=tm->tm_mon+1;
  12. d->day=tm->tm_mday;
  13. }

在getdate函数中,先调用time取得以秒计的系统时间,再用localtime函数转换一下时间结构,最后调整得到正确的日期。

1.3 编写gettime.c,源程序如下:

  1. /* gettime.c :  */
  2. #include "time.h"
  3. #include "datetime.h"
  4. int gettime(TIMETYPE *t)
  5. {
  6. long ti;
  7. struct tm *tm;
  8. time(&ti);
  9. tm=localtime(&ti);
  10. t->hour=tm->tm_hour;
  11. t->min=tm->tm_min;
  12. t->sec=tm->tm_sec;
  13. }

gettime函数与getdate函数相仿,先用time函数取得以秒计的系统时间,再

用localtime函数转换一下时间结构,最后返回当前的时间(不需调整)。

1.4 编写维护文件makefile-lib,内容如下:

  1. # makefile-lib : .
  2. all : my.so
  3. SRC = getdate.c gettime.c
  4. TGT = $(SRC:.c=.o)
  5. $(SRC) : datetime.h
  6. @touch $@
  7. %.o : %.c
  8. cc -c $?
  9. # 动态函数库(my.so)生成
  10. my.so : $(TGT)
  11. cc -shared -o $@ $(TGT)

编写维护文件的目的,在于方便程序员维护程序,尤其是维护比较大的工

程项目。一个素质良好的程序员应该学会熟练地编写维护文件makefile。定

义了文件间的依赖关系后,一旦源文件发生变化,仅需make一下,其目标

文件维护代码会自动执行,从而自动更新目标文件,减少了许多工作量。

注意: 每行维护代码必须以TAB(跳格键)开始,不是的话make时将出错。

本维护文件第1行是注释行,以#号开头;文件第3行定义所有需要维护的

函数库;第5行定义相关源程序文件;第7行定义目标文件;第9-10行说明

所有源程序依赖于datetime.h头文件,并有相应维护代码,即touch一下,

更新一下源文件的时间;第12-13行定义.o文件依赖于相应的.c文件,并指

定了维护代码,即用cc编译一下;第16-17行定义共享库my.so依赖的目标

文件,维护代码中用-shared编译选项,以生成动态链接库my.so。

1.5 运行make -f makefile-lib 命令
make运行后,动态链接库my.so就产生了,我们就可以在程序中调用了。

如果想让系统所有用户都可以使用,则应以root用户登录系统,将这个库

拷贝到/lib目录下(命令:cp my.so /lib),或者在/lib目录下建个符号连接即可

(命令:ln -s `pwd`/my.so /lib)。

2、LINUX下动态链接库的使用
2.1 重要的dlfcn.h头文件
LINUX下使用动态链接库,源程序需要包含dlfcn.h头文件,此文件定义了调

用动态链接库的函数的原型。下面详细说明一下这些函数。

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

NULL时表示操作函数执行成功。

2.1.2 dlopen
原型为: void *dlopen (const char *filename, int flag);
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值,否则返回的是操作句柄。
2.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函数 */
2.1.4 dlclose : 关闭动态链接库
原型为: int dlclose (void *handle);
dlclose用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数

为0时,才会真正被系统卸载。

2.2 在程序中使用动态链接库函数
2.2.1 程序范例
下面的程序装载了动态链接库my.so,并用getdate,gettime取得当前日期与

时间后输出。

  1. #include "stdio.h" /* 包含标准输入输出文件 */
  2. #include "dlfcn.h" /* 包含动态链接功能接口文件 */
  3. #define SOFILE "./my.so" /* 指定动态链接库名称 */
  4. #define SHARED /* 定义宏,确认共享,以便引用动态函数 */
  5. #include "datetime.h" /* 包含用户接口文件 */
  6. main()
  7. {
  8. DATETYPE d;
  9. TIMETYPE t;
  10. void *dp;
  11. char *error;
  12. puts("动态链接库应用示范");
  13. dp=dlopen(SOFILE,RTLD_LAZY); /* 打开动态链接库 */
  14. if (dp==NULL) /* 若打开失败则退出 */
  15. {
  16. fputs(dlerror(),stderr);
  17. exit(1);
  18. }
  19. getdate=dlsym(dp,"getdate"); /* 定位取日期函数 */
  20. error=dlerror(); /* 检测错误 */
  21. if (error) /* 若出错则退出 */
  22. {
  23. fputs(error,stderr);
  24. exit(1);
  25. }
  26. getdate(&d); /* 调用此共享函数 */
  27. printf("当前日期: %04d-%02d-%02d\n",d.year,d.mon,d.day);
  28. gettime=dlsym(dp,"gettime"); /* 定位取时间函数 */
  29. error=dlerror(); /* 检测错误 */
  30. if (error) /* 若出错则退出 */
  31. {
  32. fputs(error,stderr);
  33. exit(1);
  34. }
  35. gettime(&t); /* 调用此共享函数 */
  36. printf("当前时间: %02d:%02d:%02d\n",t.hour,t.min,t.sec);
  37. dlclose(dp); /* 关闭共享库 */
  38. exit(0); /* 成功返回 */
  39. }

程序说明:
第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 : 纵横软件制作中心雨亦奇编写, 2001-06-28.
  2. all : dy
  3. DYSRC = dy.c
  4. DYTGT = $(DYSRC:.c=.o)
  5. %.o : %.c
  6. cc -c $?
  7. # 动态库应用示范程序
  8. dy : $(DYTGT)
  9. cc -rdynamic -s -o $@ $(DYTGT) -ldl

维护文件说明:
第3行: 定义所有需要维护的模块;
第5行: 定义源程序;
第7行: 定义目标文件;
第9-10行: 定义.o文件依赖于.c文件,维护代码为“cc -c 变动的源文件名”;
第13-14行: 定义dy依赖于变量DYTGT指示的值,维护代码中采用-rdynamic选项以指定输出文件为动态链接的方式,选项-s指定删除目标文件中的符号表,最后的选项-ldl则指示装配程序ld需要装载dl函数库。

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

动态链接库应用示范
当前日期: 2001-06-28
当前时间: 10:06:21
当删除my.so文件时,将出现以下信息:
动态链接库应用示范
my.so: cannot open shared object file: 文件或目录不存在
3、小结
LINUX创建与使用动态链接库并不是一件难事。编译函数源程序时选用-shared选项即可创建动态链接库,注意应以.so后缀命名,最好放到公用库目录(如/lib,/usr/lib等)下面,并要写好用户接口文件,以便其它用户共享。使用动态链接库,源程序中要包含dlfcn.h头文件,写程序时注意dlopen等函数的正确调用,编译时要采用-rdynamic选项与-ldl选项,以产生可调用动态链接库的执行代码。

LINUX系统中动态链接库的创建与使用的更多相关文章

  1. LINUX系统中动态链接库的创建与使用{补充}

    大家都知道,在WINDOWS系统中有很多的动态链接库(以.DLL为后缀的文件,DLL即Dynamic Link Library).这种动态链接库,和静态函数库不同,它里面的函数并不是执行程序本身的一部 ...

  2. linux系统中利用vagrant创建虚拟开发环境

    Vagrant简介 作为程序员,可能需要同时开发多个项目,使用多种编程语言,需要使用各种操作系统,如果将很多东西放在同一个电脑上,肯定会被各种配置环境搞晕.一个比较好的办法就是每个项目都有一个干净的开 ...

  3. linux中动态链接库的创建与使用

    LINUX系统中动态链接库的创建与使用 http://www.cnblogs.com/ardar/articles/357321.html 正常C源文件编写,编译时-shared即可得到SO, gcc ...

  4. Linux系统中“动态库”和“静态库”那点事儿 /etc/ld.so.conf 动态库的后缀为*.so 静态库的后缀为 libxxx.a ldconfig 目录名

    Linux系统中“动态库”和“静态库”那点事儿 /etc/ld.so.conf  动态库的后缀为*.so  静态库的后缀为 libxxx.a   ldconfig   目录名 转载自:http://b ...

  5. Linux系统中“动态库”和“静态库”那点事儿【转】

    转自:http://blog.chinaunix.net/uid-23069658-id-3142046.html 今天我们主要来说说Linux系统下基于动态库(.so)和静态(.a)的程序那些猫腻. ...

  6. Linux系统中“动态库”和“静态库”那点事儿

    摘自http://blog.chinaunix.net/uid-23069658-id-3142046.html 今天我们主要来说说Linux系统下基于动态库(.so)和静态(.a)的程序那些猫腻.在 ...

  7. VMware下的Linux系统中Windows的共享目录,不支持创建软连接

    [问题]  在编译VMware下的Linux系统对从Windows中共享过来的文件,进行编译的时候,遇到:  ln: creating symbolic link XXXXXX : Operation ...

  8. 实例讲解Linux系统中硬链接与软链接的创建

    导读 Linux链接分两种,一种被称为硬链接(Hard Link),另一种被称为符号链接(Symbolic Link).默认情况下,ln命令产生硬链接.硬链接与软链接的区别从根本上要从Inode节点说 ...

  9. (转)浅谈 Linux 系统中的 SNMP Trap

    原文:https://www.ibm.com/developerworks/cn/linux/l-cn-snmp/index.html 简介 本文讲解 SNMP Trap,在介绍 Trap 概念之前, ...

随机推荐

  1. 基于.net 职责链来实现 插件模式

    插件式的例子 QQ电脑管家,有很多工具列表,点一下工具下载后就可以开始使用了 eclipse ,X Server 等等 插件式的好处 插件降低框架的复杂性,把扩展功能从框架中剥离出来 让第三方有机会来 ...

  2. ManualResetEvent的使用与介绍

    它可以通知一个或多个正在等待的线程已发生事件,允许线程通过发信号互相通信,来控制线程是否可心访问资源 当一个线程开始一个活动(此活动必须完成后,其他线程才能开始)时,它调用 Reset 以将 Manu ...

  3. (转)php连接mysql如何判断数据为空?

    <?php$result_a=mysql_query("select * from product_tag where product_id=$row[id]");$num ...

  4. 使用LuaInterface遇到的编码问题

    今天使用LuaInterface加载脚本时忽然报“未知字符”错误信息!于是检查文件编码 将其修改为“US ASCII” 就好了.

  5. Jenkins corbertura问题

    最近在Jenkins上部署项目时遇到无法展示覆盖率测试报告的问题. build success后,出现配置的覆盖率报告存储位置not exists的失败问题,评估是Jenkins每次按照publish ...

  6. jquery”ScriptResourceMapping

    要“jquery”ScriptResourceMapping.请添加一个名为 jquery (区分大小写)的 ScriptResourceMapping.”的解决办法. 1.先将aspnet.scri ...

  7. C# CRC校验的一点感悟

    今天在鼓捣一个手持操作器的时候,遇到一点问题,记录一下今天的经验包 由于之前公司产品在校验时基本上都是和校验,今天在准备用C#模拟一个古董操作器的时候,却遇到一个问题,模拟器发出的数据,主板一律不回复 ...

  8. CSS3 文本装饰

    浏览器对CSS3文本特性的支持情况,如下表所示: 浏览器 text-shadow text-overflow word-wrap hyphens Opera 9.5+ 9+.带前缀-o- 10.5+ ...

  9. Lucene 排序 Sort与SortField

    在sql语句中,有升序和降序排列.在Lucene中,同样也有. Sort里的属性 SortField里的属性 含义 Sort.INDEXORDER SortField.FIELD_DOC 按照索引的顺 ...

  10. 【BZOJ1875】【矩阵乘法】[SDOI2009]HH去散步

    Description HH有个一成不变的习惯,喜欢饭后百步走.所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离. 但是同时HH又是个喜欢变化的人,所以他不会立刻沿着刚刚走来的路走回. 又因 ...