美文网首页
linux共享库

linux共享库

作者: lintong | 来源:发表于2015-03-02 16:18 被阅读245次

    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库

    相关文章

      网友评论

          本文标题:linux共享库

          本文链接:https://www.haomeiwen.com/subject/dthmxttx.html