linux共享库

linux环境下,库文件包含静态函数库和动态函数库两种:

静态函数库:

这类库的名字一般是libxxx.a;利用静态函数库编译成的文件比较大,因为整个函数库的所有数据都会被整合进目标代码中,他的优点就显而易见了,即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进可执行文件了。当然这也会成为他的缺点,因为如果静态函数库改变了,那么你的程序必须重新编译,而且体积也较大。

动态函数库:

这类库的名字一般是libxxx.so,动态库又称共享库;相对于静态函数库,动态函数库在编译的时候并没有被编译进目标代码中,你的程序执行到相关函数时才调用该函数库里的相应函数,因此动态函数库所产生的可执行文件比较小。由于函数库没有被整合进你的程序,而是程序运行时动态的申请并调用,所以程序的运行环境中必须提供相应的库。动态函数库的改变并不影响你的程序,所以动态函数库的升级比较方便。而且如果多个应用程序都要使用同一函数库,动态库就非常适合,可以减小应用程序的体积

在开发过程中引入库的作用主要包括:

1.函数模块的功能相同,实现代码也相同,通过对它们进行封装为库,方便模块之间的调用,避免代码重复
2.封装另外一个目的是针对接口编程,对实现代码进行保密,利于代码保护和代码升级

第一节:静态函数库

在linux中,静态函数库有固定的命名规则:lib+类库名称+.a。
把函数打包成.a静态库包括下面几个步骤:

1.程序实例:

/*************************************************************  
    FileName : myAddLib.h 
    FileFunc : 定义头文件    
    Version  : V0.1     
    Author   : Sunrier     
    Date     : 2012-04-28 
    Descp    : Linux下实现静态库     
*************************************************************/  
#ifndef   _MYADDLIB_H_      
#define   _MYADDLIB_H_   
  
#ifdef __cplusplus  
extern "C" {  
#endif  
  
int add(int ,int );  
  
#ifdef __cplusplus  
}  
#endif  
  
#endif   
/*************************************************************      
    FileName : myAddLib.c  
    FileFunc : 定义静态库实现文件    
    Version  : V0.1      
    Author   : Sunrier      
    Date     : 2012-04-28  
    Descp    : Linux下实现静态库     
*************************************************************/    
#include <stdio.h>    
int add(int iArg1,int iArg2)    
{    
        printf("iArg1= %d , iAgr2= %d \n",iArg1,iArg2);    
        return (iArg1+iArg2);    
}    

2.制作静态库文件

1.编译并生成目标文件:gcc -c myAddLib.c -o myAddLib.o
2.生成归档文件:ar -rc libmyAddlib.a myAddLib.o

gcc -o myAddLib.o -c myAddLib.c 

把源程序文件编译成*.o。-c :只编译并生成目标文件。

ar -rc libmyAddLib.a myAddLib.o 

执行完后会生成一个libmyAddLib.a 文件
-c create的意思
-r replace的意思,表示当插入的模块名已经在库中存在,则替换同名的模块.如果若干模块中有一个模块在库中不存在,ar显示一个错误消息,并不替换其他同名模块.默认的情况下,新的成员增加在库的结尾处,可以使用其他任选项来改变增加的位置。

3.使用静态库文件

/*************************************************************     
    FileName : testAddLib.c 
    FileFunc : 测试静态库文件   
    Version  : V0.1     
    Author   : Sunrier     
    Date     : 2012-04-28 
    Descp    : Linux下实现静态库   
*************************************************************/  
#include <stdio.h>  
#include "myAddLib.h"  
  
int main(int argc,char *argv[])  
{  
        int iNumber1,iNumber2,iSum = 0;  
        iNumber1 = 10;  
        iNumber2 = 20;  
        iSum = add(iNumber1,iNumber2);  
        printf("iSum=%d\n".iSum);  
        printf("Hello Sunrier!\n");  
        return 0;  
}  

编译:gcc -o testAddLib testAddLib.c -L. -lmyAddLib
-L指定库路径,-lmyAddLib指定库的名称,不包含lib.a两部分。

第二节:动态函数库

动态函数库又叫共享库(share lib)。它是在运行时,由系统的动态函
数库"lib/ld.so"负责动态加载。
动态函数库也有自己的命名规则:lib+动态库名称+.so+.+版本号;比如libC++.so.6。
动态函数库有两种使用方式:动态链接(隐式调用)和动态调用(显式调用,利用lib/ld.so提供的函数,利用函数指针,动态调用一个类库中包含的函数,不需要知道动态库的头文件)。

隐式调用和显示调用:

隐式调用使用方便简单, 但其和静态库相似, 在编译期就和程序绑定了,灵活性差, 并且其生存期和进程一样, 进程开始, 调用开始, 进程结束, 动态库才卸载. 另外还需要将整个动态库全部加进内存.
显式调用使用起来比较复杂, 但是却可以在运行期间选择所需要调用的动态链接库, 并且可以控制动态库生存期, 需要加载时候再加载, 用完了就可以卸掉, 而且不用将整个动态库都放进内存, 只要加载要用到的函数即可.

隐式调用:

编写动态库文件

/*************************************************************  
    FileName : myAddLib.h 
    FileFunc : 定义头文件    
    Version  : V0.1     
    Author   : Sunrier     
    Date     : 2012-05-02 
    Descp    : Linux下实现动态库     
*************************************************************/  
#ifndef   _MYADDLIB_H_      
#define   _MYADDLIB_H_   
  
#ifdef __cplusplus  
extern "C" {  
#endif  

int add(int ,int );  

#ifdef __cplusplus  
}  
#endif  
  
#endif   
/*************************************************************     
    FileName : myAddLib.c 
    FileFunc : 定义动态库实现文件   
    Version  : V0.1     
    Author   : Sunrier     
    Date     : 2012-05-02 
    Descp    : Linux下实现动态库    
*************************************************************/  
#include <stdio.h>  
int add(int iArg1,int iArg2)  
{  
        printf("iArg1= %d , iAgr2= %d \n",iArg1,iArg2);  
        return (iArg1+iArg2);  
}  

制作库文件:

1.gcc -fipc myAddLib.c -o myAddLib.o
2.gcc -share -o libmyAddLib.so.1 myAddlib.o
或者 gcc -fipc -share -o libmyAddLib.so.1 myAddLib.c
其中-fipc用来产生和位置无关代码,-share用来生成动态共享库

隐式使用动态库文件
/*************************************************************     
    FileName : testAddLib.c 
    FileFunc : 测试动态库文件   
    Version  : V0.1     
    Author   : Sunrier     
    Date     : 2012-05-02 
    Descp    : Linux下实现动态库   
*************************************************************/  
#include <stdio.h>  
#include "myAddLib.h"  
  
int main(int argc,char *argv[])  
{  
        int iNumber1,iNumber2,iSum = 0;  
        iNumber1 = 10;  
        iNumber2 = 20;  
        iSum = add(iNumber1,iNumber2);  
        printf("iSum=%d\n",iSum);  
        printf("Hello Sunrier!\n");  
        return 0;  
}  
编译目标文件
gcc -o testAddLib testAddLib.c -L. -lmyAddLib

-L指定动态函数库的位置供查找,注意L后面还有'.',表示动态函数库在本目录下查找。此时还不能立即./testAddLib,因为在动态函数库使用时,会查找/usr/lib或/lib目录下的动态函数库,而此时我们生成的库不在里边。

执行可执行文件

这个时候有好几种方法可以让他成功运行:
最直接最简单的方法就是把libmyAddLib.so放到/usr/lib或/lib中去或者修改LD_LIBRARY_PATH环境变量文件。

假设libmyAddLib.so在/home/Sunrier/lib  
export LD_LIBRARY_PATH=/home/Sunrier/lib:$LD_LIBRARY_PATH  

另外还可以在/etc/ld.so.conf文件里加入我们生成的库的目录,然后/sbin/ldconfig。
/etc/ld.so.conf是非常重要的一个配置文件,里面存放的是链接器和加载器搜索共享库时要检查的目录,默认是从/usr/lib或/lib中读取的,所以想要顺利运行,我们也可以把我们库的目录加入到这个文件中并执行/sbin/ldconfig。

动态调用:

根据前面提到的生成头文件libmyAddLib.so文件。

/*************************************************************     
    FileName : testAddLib.c 
    FileFunc : 测试动态库文件   
    Version  : V0.1     
    Author   : Sunrier     
    Date     : 2012-05-03 
    Descp    : Linux下实现动态库   
*************************************************************/  
#include <stdio.h>  
#include <dlfcn.h>  
  
#define SOFILE "./libmyAddLib.so"  
  
int main(int argc,char *argv[])  
{  
        int iNumber1,iNumber2,iSum = 0;  
  
        void *hdl = NULL;//动态库句柄   
          hdl = dlopen(SOFILE,RTLD_LAZY);//打开动态链接库  
          if( NULL==hdl )  
        {  
             printf("No libmyAddLib.so file\n");  
             return 1;  
        }  
        /*函数指针*/  
        int(*add)(int,int);  
        add = dlsym(hdl,"add");//查找符号表,定位共享函数  
          char *error = dlerror();//检测错误  
          if( error )  
        {  
            printf("No function!\n");  
            return 1;  
        }  
        iNumber1 = 10;  
        iNumber2 = 20;  
        iSum = add(iNumber1,iNumber2);//调用此共享函数  
          //iSum = (*add)(iNumber1,iNumber2);//调用此共享函数  
          printf("iSum=%d\n",iSum);  
        printf("Hello Sunrier!\n");  
        dlclose(hdl);//关闭共享库  
          hdl =NULL;  
        return 0;  
}  

dlfcn.h包含了动态调用函数库的相关的函数。

void  *dlopen (const char *file, int arg );  
//打开一个动态库的文件,arg代表打开的方式  
/* 
RTLD_LAZY 
Relocations are performed at an implementation-dependent time. 
RTLD_NOW 
Relocations are performed when the object is loaded. 
RTLD_GLOBAL 
All symbols are available for relocation processing of other modules. 
RTLD_LOCAL 
All symbols are not made available for relocation processing by other modules.*/  

void *dlsym(void *handle, const char *name);  
  
void    *handle;  
int     *iptr, (*fptr)(int);  
  
/* open the needed object */  
handle = dlopen("/usr/home/me/libfoo.so.1", RTLD_LAZY);  
  
/* find the address of function and data objects */  
fptr = (int (*)(int))dlsym(handle, "my_function");  
iptr = (int *)dlsym(handle, "my_object");  
  
/* invoke function, passing value of integer as a parameter */  
(*fptr)(*iptr);  

char *dlerror(void);  
/*If successful, dlerror() returns a null-terminated character string. Otherwise, NULL is returned.*/  

int dlclose(void *handle);  
/*If the referenced object was successfully closed, dlclose() returns 0.   

If the object could not be closed, or if handle does not refer to an open object,   
dlclose() returns a non-zero value. More detailed diagnostic information will be available through dlerror().*/  
编译和生成目标文件:
#gcc testAddLib.c -o testAddLib -ldl

其中-ldl用于加载dl库

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,743评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,296评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,285评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,485评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,581评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,821评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,960评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,719评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,186评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,516评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,650评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,936评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,757评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,991评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,370评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,527评论 2 349

推荐阅读更多精彩内容