Linux静态库和共享库

Linux静态库和共享库


linux库学习笔记

一、什么是库

本质上来说库是一种可执行的二进制形式代码,可以被操作系统载入内存执行。由于windows和linux的本质不同,因此二者库的二进制是不兼容的,本文主要是针对linux系统下的库进行说明的。

二、库的种类

linux下的库有两种:静态库和共享库(动态库)。二者的不同点在于代码被载入的时刻不同。

•      静态库:在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库,因此体积较大。

•      共享库:在程序编译时并不会被连接到目标代码中,只是在生成的可执行程序中简单指定需要使用的库函数信息,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在,因此代码体积较小。

三、库文件的命名规则

•      静态库: libxxxx.a,其中xxxx是该lib的名称

•      共享库: libxxxx.so.major.minor,xxxx是该lib的名称,major是主版本号,minor是副版本号

四、库存在的意义

库是别人写好的现有的,成熟的,可以复用的代码,你可以使用但要记得遵守许可协议。

现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。

封装

版本管理

共享库的好处是,不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。

五、库的创建与使用

    静态库的创建

Step1.由源文件编译生成一堆.o,每个.o里都包含这个编译单元的符号表

Step2.ar命令将很多.o转换成静态库,如

#ar crs libhello.a hello.o

    共享库的创建

Step1.由源文件编译生成一堆.o,每个.o里都包含这个编译单元的符号表

Step2. 由编译器加特定参数编译生成共享库,如

# gcc-shared -fPCI -o libhello.so hello.o

       库的使用

#gcc-o hello main.c -L. –lhello

五、动态库加载的问题

1.    拷贝动态库文件到/lib或/usr/lib去

2.    改变环境变量LD_LIBRARY_PATH

命令:#export LD_LIBRARY_PATH=/home/xxx/lib/

3.    在/etc/ld.so.conf添加库的路径,然后执行ldconfig命令生效

4.    在编译时指定库的搜索路径,-Wl,-rpath=/home/xxx/lib(应该是库在系统中的绝对路径)

5.    动态加载库

六、动态加载库接口

1.    dlopen

函数原型:void*dlopen(constchar *libname,int flag);

功能描述:dlopen必须在dlerror,dlsym和dlclose之前调用,表示要将库装载到内存,准备使用。

如果要装载的库依赖于其它库,必须首先装载依赖库。如果dlopen操作失败,返回NULL值;如果库已经被装载过,则dlopen会返回同样的句柄。

Libname:一般是库的全路径,这样dlopen会直接装载该文件;如果只是指定了库名称,在dlopen会按照下面的机制去搜寻:

a.    根据环境变量LD_LIBRARY_PATH查找

b.    根据/etc/ld.so.cache查找

c.    查找依次在/lib和/usr/lib目录查找。

Flag:表示处理未定义函数的方式,可以使用RTLD_LAZY或RTLD_NOW。

RTLD_LAZY:表示暂时不去处理未定义函数,先把库装载到内存,等用到没定义的函数再说;

RTLD_NOW:表示马上检查是否存在未定义的函数,若存在,则dlopen以失败告终。

2.    dlerror

函数原型:char*dlerror(void);

功能描述:dlerror可以获得最近一次dlopen,dlsym或dlclose操作的错误信息,返回NULL表示无错误。dlerror在返回错误信息的同时,也会清除错误信息。

3.    dlsym

函数原型:void*dlsym(void*handle,const char *symbol);

功能描述:在dlopen之后,库被装载到内存。dlsym可以获得指定函数(symbol)在内存中的位置(指针)。如果找不到指定函数,则dlsym会返回NULL值。但判断函数是否存在最好的方法是使用dlerror函数,

4.    dlclose

函数原型:int dlclose(void*);

功能描述:将已经装载的库句柄减一,如果句柄减至零,则该库会被卸载。如果存在析构函数,则在dlclose之后,析构函数会被调用。

七、与库相关的常用命令

1.    nm:用来列出目标文件的符号清单。

2.    ldd:显示可执行模块的dependency。

八、实例测试

①    编写源文件

hello.c

#include<stdio.h>

void sayhello() 

{

    printf("hello world \n");                                                                                                  

}

libtest.c

#include<stdio.h>                                                                                                            

int main(){

    sayhello();

    return 0;

}

②    编译生成目标文件(.o)

使用命令:$gcc –c -fPIC hello.c

$gcc –c -fPIC libtest.c

③    库文件生成与使用

1.    静态库

使用命令:$ar –crs libhelloa.a hello.o

2.    共享库

使用命令:$gcc -fPIC -shared -o libhellos.so hello.o

3.    编译目标文件

使用命令(使用静态库):$ gcc -o libtesta libtest.o -L. –lhelloa

使用命令(使用共享库):$ gcc -L. -lhello -Wl,-rpath=./ -o libtestslibtest.o

④    結果

$./libtesta

$ helloworld

$./libtests

$ helloworld

使用命令ldd查看依赖,结果如下:


动态加载库实例

①    编写源文件

dlibtest.c

#include<stdio.h>

#include<dlfcn.h>

int main(int argc,char **argv){                                                                                                 

       void *handle;

       int (*func)(void);

       handle=dlopen("./libhellos.so",RTLD_LAZY);

       if(!handle){

              printf("load lib error\n");

              return 1;

       }

       func = (int (*)(void))dlsym(handle, "sayhello");

       if (func == NULL)

       {

              printf("Load symbol myfunction fail, %s\n", dlerror());

              return 2;

       }

       func();

       dlfclose(handle);

       return 0;

}

②    编译

使用命令:$ gcc-o dlibtest dlibtest.c -ldl

③    結果

$./dlibtest

$ helloworld


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值