Linux中动态链接库总结

来源:互联网 发布:飞鹰网络通信有限公司 编辑:程序博客网 时间:2024/06/03 21:20
#参考:#    http://www.abc188.com/info/html/wangzhanyunying/jianzhanjingyan/20080417/70810.html#    http://os.51cto.com/art/201001/176625.htm#    http://os.51cto.com/art/201001/176618.htm[概述]本文是我在学习linux下动态链接库的总结,主要内容为:为什么要使用动态链接库、动态链接库的制作、使用。0 为什么要使用动态链接库     linux下的库文件有:静态库和动态库两种。静态库文件的制作和使用在前文中已简要总结。LINUX系统中动态链接库,类似于 WINDOWS中以.dll为后缀的文件(dll即Dynamic Link Library)。    静态库与动态库的区别。如果程序是在编译时加载库文件的,就是使用了静态库。如果是在运行时加载目标代码,就成为动态库。换句话说,如果是使用静态库,则静态库代码在编译时就拷贝到了程序的代码段,程序的体积会膨胀。如果使用动态库,则程序中只保留库文件的名字和函数名,在运行时去查找库文件和函数体,程序的体积基本变化不大。    静态库的原则是“以空间换时间”,增加程序体积,减少运行时间;    动态库则是“以时间换空间”,增加了运行时间,但减少了程序本身的体积。1 动态链接库的制作     在LINUX系统下,创建动态链接库是件非常简单的事情。只要在编译函数库源程序时加上-shared选项即可,这样所生成的执行程序即为动态链接库。从某种意义上来说,动态链接库也是一种执行程序。按一般规则,动态库的命名应为lib*.so.*。其中第一个*为动态库的名字,第二个*为版本号,比如libc.so.6。编译生成动态库的命令: gcc -o libmy.so -fpic -shared getdate.c gettime.c    下面制作动态库的例子中有3个文件: adatetime.h, getdate.c, gettime.c。adatetime.h为动态链接库的头文件; getdate.c和gettime.c分别实现getDate()和getTime()函数。1.1 编写动态库头文件adatetime.h,代码如下:[cpp] view plain copy/*  * adatetime.h  */  #ifndef _DATETIME_H  #define _DATETIME_H  typedef struct      /*日期结构*/  {      int year;      int month;      int day;  }DATETYPE;  typedef struct      /*时间结构*/  {      char hour;      char min;      char sec;  }TIMETYPE;  /*函数原型说明*/  int getDate(DATETYPE *d);       /*取当前日期*/  int getTime(TIMETYPE *t);       /*取当前时间*/  #endif  1.2 编写getdate.c和gettime.c,代码如下:[cpp] view plain copy/*  * getdate.c: 定义获取系统日期的函数getDate()  */  #include<time.h>  #include "adatetime.h"  int getDate( DATETYPE *d )  {      long ti;      struct tm *tm;      time(&ti);      tm = localtime(&ti);      d -> year = tm -> tm_year + 1900;      d -> month = tm -> tm_mon + 1;      d -> day = tm -> tm_mday;  }  /*  * gettime.c: 定义获取系统时间的函数getTime()  */  #include<time.h>  #include "adatetime.h"  int getTime( TIMETYPE *t )  {      long ti;      struct tm *tm;      time(&ti);      tm = localtime(&ti);      t -> hour = tm -> tm_hour;      t -> min = tm -> tm_min;      t -> sec = tm -> tm_sec;  }  1.3 编译生成动态库(1) 编写维护文件makefile-lib,内容如下[cpp] view plain copy#makefile-lib: 动态库实例维护文件  all: libmy.so  SRC = getdate.c gettime.c  TGT = $(SRC:.c=.o)  $(SRC): adatetime.h      @touch $@  %.o: %.c      cc -c $?  #生成动态链接库(libmy.so)  libmy.so: $(TGT)      cc -s -fpic -shared -o $@ $(TGT)        #-fpic选项,增加动态库的可重定位性  注意: 每行维护代码必须以TAB(跳格键)开始,不是的话make时将出错。编写维护文件的目的,在于方便程序员维护程序,尤其是维护比较大的工程项目。(2) 运行命令make -f makefile-lib, 则生成名为libmy.so的动态库文件。1.4 共享动态库文件    /etc/ld.so.conf文档中,存放着可被LINUX共享的动态链接库所在目录的名字(系统目录/lib,/usr/lib除外)。我们可以把自己制作的动态库放到/lib或/usr/lib;也可以新建用户自己的库文件夹:/home/uname/lib,然后把此文件夹路径写入/etc/ld.so.conf中(并把自己的动态库复制到该文件夹下)。#ldconfig        //刷新缓存文档/etc/lb.so.cache,使共享设置生效    然后就可以使用动态库文件libmy.so了。2 动态库文件的使用 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/libflag表示在什么时候解决未定义的符号(调用)。取值有两个:    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.0动态库的分为隐式调用和显式 调用两种调用方法。隐式调用的使用使用方法和静态库的调用差不多,具体方法如下:    gcc -c -I/home/weil/inc main.c     gcc -o main1 -L/home/ weil /lib main.o libmytime.so   //这里是*.so      在这种调用方式中,需要维护动态链接库的 配置文件/etc/ld.so.conf 来让动态链接库为系统所使用,通常将动态链接库所在目录名追加到动态链接库配置文件中。否则在执行相关的可执行文 件的时候就会出现载入动态链接库失败的现象。 在编译所引用的动态库时,可以在gcc采用 –l或-L选项或直接引用所需的动态链接库方式进行编译。      在Linux里面,可以采用ldd命令来检查程序依赖共享库。显式调用 :    gcc -o main -ldl main.c     用gcc编译对应的源文件生成可执行文件,-ldl选项,表示生成的对象模块需要使用共享库。    在示例程序ady.c中调用动态库libmy.so中的getDate()和getTime()函数,用来显式系统的当前时间。2.2.1 编写ady.c (本例中使用显示调用的方法)[cpp] view plain copy/*  * ady.c: 动态链接库应用示范程序  */  #include<stdio.h>  #include<dlfcn.h>  #include<string.h>  #define SOFILE "libmy.so"  #include "adatetime.h"  int main()  {      DATETYPE d;      TIMETYPE t;      void *dp;      char *error;      printf("A sample for loading SO!/n");      dp = dlopen(SOFILE, RTLD_LAZY);   /* 打开动态链接库 */      if(dp == NULL)      {          fputs(dlerror(), stderr);          return -1;      }      int (*getDate)();   /*定义指针函数用于获取动态库中getDate()的入口地址*/      getDate = dlsym(dp, "getDate");      error=dlerror(); /* 检测错误 */      if ( error ) /* 若出错则退出 */      {          fputs(error,stderr);          return -1;      }      getDate(&d); /* 调用此共享函数 */      printf("Current Date: %04d-%02d-%02d/n",d.year,d.month,d.day);      int (*getTime)();      getTime=dlsym(dp,"getTime"); /* 定位取时间函数 */      error=dlerror(); /* 检测错误 */      if (error) /* 若出错则退出 */      {          fputs(error,stderr);          return -1;      }      getTime(&t); /* 调用此共享函数 */      printf("Current Time: %02d:%02d:%02d/n",t.hour,t.min,t.sec);      dlclose(dp); /* 关闭共享库 */      return 0;  }   2.2.2 编写维护文件makefile[ruby] view plain copy#makefile: 示例程序维护文件  all: ady  DYSRC = ady.c  DYTGT = $(DYSRC:.c=.o)  %.o:%.c      cc -c $?  #动态库示例  ady:$(DYTGT)      cc -rdynamic -s -o $@ $(DYTGT) -ldl  2.3 编译、运行测试程序#make#./ady可显式系统当前日期、时间。
0 0