Linux学习之旅(13)-----静态库和动态库

库的简介

库函数是将函数放到库中,供别人使用的一种方式。一般库中存放的代码都是经过优化稳定性很好的代码。这样做的目的是为了让程序员减少编写代码的时间,从而将时间用于如何取解决问题而不是如何编写代码。库分为两种:(1)静态库、(2)动态库。

静态库.a(win系统下为.lib)和动态库.so(win系统下为.dll)。根据在链接阶段如何处理库,将库分为静态库和动态库。

静态库:指在程序编译时将库同时编译进目标代码中,一旦编译完成,如何改静态库是否还存在程序都可以执行。即如果在链接时以静态链接的方式处理库,那么程序编译完成后将不再需要静态库。因为需要将库编译入代码中,所以这种方式生成的文件还会比较大。

静态库的特点:

(1)静态库对函数库的链接是在编译时完成的。

(2)编译完成后就不需要静态库了。

(3)生成的文件体积大。

(4)更新困难。因为静态库时直接编译进入程序的,所以当库的发生变化时,就需要将程序重新编译。

动态库:指在程序编译链接时将库以动态链接的方式处理,这样处理的库不会被链接到代码中,而时会生成一个动态库表,当程序需要执行时,从表中找到对应的库,然后继续执行。这样生成的文件会比较小。

动态库特点:

(1)将一些库函数的链接载入推迟到了程序运行时期。

(2)可以是实现进程间资源的共享。

(3)更新简单。只要函数的接口不发生变化,无论函数的内容如何变化都不会影响动态库的使用。

Linux系统下静态库和动态库的制作

(1)“素材”准备

编写一个简单的小程序,实现整数的加、减、乘、除。将四个函数功能分别写入4个文件中,将函数的声明写在calc.h中。主函数写在main.c中。

//main.c
#include <stdio.h>
#include "calc.h"
int main()
{
    printf("加法:%d\n",add(5,5));
    printf("减法:%d\n",sub(5,5));
    printf("乘法:%d\n",mul(5,5));
    printf("除法:%d\n",div(5,5));
    return 0;
}

//add.c
#include "calc.h"
int add(int m,int n)
{
    return m+n;
}

//div.c
#include "calc.h"
int div(int m,int n)
{
    return m/n;
}

//mul.c
#include "calc.h"
int mul(int m,int n)
{
    return m*n;
}

//sub.c
#include "calc.h"
int sub(int m,int n)
{
    return m-n;
}

//calc.h
int add(int m,int n);
int sub(int m,int n);
int mul(int m,int n);
int div(int m,int n);

(2)静态库的制作

将需要使用的.c/.cpp文件编译生成.o文件。

gcc -c -fPIC *.c    //*通配符,即所以以.c结尾的文件
 

参数说明:

-fPIC:生的.o文件时和位置无关的(地址采用偏移量)。

将.o文件打包问库文件。

ar rcs libcalc.a *.o

libcalc为生成库的名字。一般静态库的命名是以li开头.a结尾的。

我们新建一个目录将所以的库文件放入改目录。

静态库的使用

gcc -Icalc main.c lib/libcalc.a -o sCalc

(3)动态库的制作

步骤是一样的都需要将.c文件编译生成.o文件。然后将.o文件打包。

gcc -shared -Wl,-soname,libcalc.so.1 -o libcalc.so.1.10 *o

一般动态库的命名为lib起头.so结尾。后面的数字一会解释。

将生成的文件移动lib目录中。

为libcalc.so.1.10生成一个名为libcalc.so的符号链接。

ln -s libcalc.so.1.10 libcalc.so

编译动态库

gcc -Icalc main.c lib/libcalc.so -o tCalc

将库文件的目录加入/etc/ld.so.conf,让系统可以知道在什么地方可以找到动态库。

ldconfig -v   //更新配置文件

之后就可以使用刚才生成的文件了。

文件目录树

动态库命名时的后面数字(版本号)

一般动态库会有三个名字分别是realname(真实姓名)、soname(库姓名)、linkername(链接姓名)。

那一个库为什么要起三个姓名那?

一般库的命名需要遵循一下的规则:即将库名命名为libname.so.x.y.z的格式。最前面使用前缀”lib”,中间是库的名字和后缀”.so”,最后三个数字是版本号。x是主版本号(Major Version Number),y是次版本号(Minor Version Number),z是发布版本号(Release Version Number)。

在程序执行时一般记录的是soname,通过soname去找真正的库函数。通过上面说明,我们可以得知soname记录的库函数的主版本。即如果库函数的主版本不变,无论次版本如何变那么程序都时可以执行(要符合规则的变,不能乱变)。如果一旦主版本号发生变化,那么程序就不能运行了。举个列子:

你的程序在编译时使用的动态库。版本为1.10,那么如果其他人的电脑上安装的版本时1.20,1.30,这样以1开头的版本,那么这个程序在这些电脑上都是可以运行的,但如果有个人安装了2.10版本,那么程序在他的电脑上就不能运行。

既然是这样,那要soname和realname不就可以了吗,为社么还要linkername那?

linkername主要是为了适应makefiles(管理代码的),通常为多人共用的。这样可能每个人的库的版本都不太一样,那么就产生了麻烦,所以就产生了linkername,消除这样的麻烦。

需要明白的是无论怎样命名最后执行的都是reaname文件。linkername和soname都是其的软链接。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值