Linux中动态链接库总结

#参考:
#    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/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.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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值