linux库:静态库和动态库

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

静态函数库: 
  这类库的名字一般是libxxx.a;利用静态函数库编译成的文件比较大,因为整个函数库的所有数据都会被整合进目标代码中,他的优点就显而易见了,即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进可执行文件了。当然这也会成为他的缺点,因为如果静态函数库改变了,那么你的程序必须重新编译,而且体积也较大。
动态函数库: 
  这类库的名字一般是libxxx.so,动态库又称共享库;相对于静态函数库,动态函数库在编译的时候并没有被编译进目标代码中,你的程序执行到相关函数时才调用该函数库里的相应函数,因此动态函数库所产生的可执行文件比较小。由于函数库没有被整合进你的程序,而是程序运行时动态的申请并调用,所以程序的运行环境中必须提供相应的库。动态函数库的改变并不影响你的程序,所以动态函数库的升级比较方便。而且如果多个应用程序都要使用同一函数库,动态库就非常适合,可以减小应用程序的体积。


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

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

第一节:静态函数库

在linux中,静态函数库有固定的命名规则:lib+类库名称+.a。

把函数打包成.a静态库包括下面几个步骤:

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

程序实例:

/*************************************************************    
    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


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;
}

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

3)执行可执行文件 
这个时候有好几种方法可以让他成功运行: 
最直接最简单的方法就是把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库

隐式调用和显示调用:

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

参考博客:http://blog.csdn.net/sunrier/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值