linux下静态库与动态库的生成与应用,详解


摘要:在做项目的过程中,我们不需要再对已经做过的功能再次编写,可以直接拿来用。或者说多团队协作开发项目的时候,团队A只需要团队B所提供的功能,而不需要知道团队B如何实现的,类似面向对象的意思。团队B所写的代码就是制作库的过程,而团队A就是消费库的角色。
本文主要讲解下linux下,运用gcc来制作静态库和动态库。

1.静态库与动态库概念

1.静态库概念

我们将某些功能封装成库,供用户静态调用的,这就是静态库。linux下的命名规则为:

libxxx.a

lib为静态库的开头,xxx为库的名字,并且以 .a 结尾

为什么叫静态库呢,其实就是用户静态调用,也就是直接调用的意思。我们在代码编译的时候,直接将静态库编译到我们的程序中,直接调用,这就是静态库。

2.动态库概念

我们将某些功能封装成库,供用户动态调用,这就是动态库,linux下的命名规则为:

libxxx.so

lib为动态库的开头,xxx为库的名字,并且以.so结尾。和静态库的差别是结尾。

为什么叫动态库呢,其实就是用户动态调用的意思,我们在编译的时候不会加载动态库,而是在运行的时候才会去加载库,这就叫动态库,也叫共享库。

不管是静态库还是动态库,其实就是我们调用程序的一种方式,是在编译的时候就加载,还是在运行的时候加载。

2.库的制作与应用

这里举个例子来说明怎么制作和应用静态库以及动态库
首先我们写了3个.c文件来分别表示3种功能,

长方形的周长

//rectangle_circu.c
#include "head.h"

int rectangle_circu(int length, int width)
{
    return (length * 2 + width * 2);
}

三角形的周长

//triangle_circu.c
#include "head.h"

int triangle_circu(int a, int b, int c)
{
    return (a + b + c);
}

圆形的周长。

//circle_circu.c
#include "head.h"

int circle_circu(int radius)
{
    return (2 * 3.14 * radius);
}

h文件

//head.h
#ifndef __HEAD_H__
#define __HEAD_H__

int triangle_circu(int a, int b, int c);
int rectangle_circu(int length, int width);
int circle_circu(int radius);

#endif

我在制作的过程中,是分别将这4个文件放在不同的2个文件夹下面的。如下图

在这里插入图片描述

1.静态库的制作与应用

在制作静态库之前需要了解gcc,这里就默认都了解gcc了。

1. 制作静态库的命令
在src文件夹下生产.o文件。先cd到src文件夹下。

gcc -I ../include *.c -c

这里解释下命令: -I表示包含的头文件路径。-c表示生产.o文件。

整个命令的意思是,在上一个目录下的include文件夹下去寻找.h文件,并将本路径下的所有.c文件生成对应的.o文件
执行了这个命令后,就会在src文件下多出几个.o文件
在这里插入图片描述
有了.o文件后,就可以对.o文件进行打包生成我们的静态库了。

2. 打包静态库
这里用到了打包用的命令是ar.
我们进入到src目录下

ar rcs libMycircu.a *.o

使用这条命令就可以生成我们的静态库libMycircu.a了。

查看src目录下,会多一个文件
在这里插入图片描述
为了方便应用与发布静态库,我们将库移动放到特定的专门的lib文件夹下面。
移动到和src同级的lib文件夹下面。

3.静态库的应用
我们写个函数来调用这个静态库
这里写一个main.c来调用我们静态库里面的内容。

//main.c
#include <stdio.h>
#include "head.h"

int main()
{
    int length = 5;
    int width = 4;
    //长方形的周长
    int len = rectangle_circu(length, width);
    printf("长方形的周长为:%d\n", len);
    return 0;
}

写好调用函数以后,我们就来编译这个main.c,
这里可以有2中方式来编译,
第一种方法
用到的命令如下

gcc main.c -I include lib/libMycircu.a -o circu

在当前目录,生成了可执行文件circu,
我们来执行下

./circu

执行结果:
在这里插入图片描述

我们看到这是我们想要的结果。
静态库调用成功。

第二种方法
用到的命令如下:

gcc main.c -I include/ -L lib/ -l Mycircu -o circu 

命令解析:
-I 表示包含的头文件, -L表示静态库的位置,-l表示库的名字,注意库的名字(libMycircu.a)是去掉了头(lib)和尾(.a)的。
同样我们可以得到可执行文件,如第一种方法一样,执行结果也一样。这里就不在赘述。

2.动态库的制作与应用

制作动态库的步骤
1.生成和位置无关的代码
什么叫和位置无关的代码,其实就是说在加载的时候是以绝对地址,还是相对地址来加载的。我们静态库是在编译的时候就加载到程序中的,用的是绝对地址。而我们动态库是在程序运行的时候才加载的,用的就是相对地址。

怎么生成和位置无关的代码呢。
其实也是生成.o。只是和静态库的方法不一样。
我们先cd到src目录下。
用的命令如下:

gcc -fPIC -c *.c -I ../include/

执行这条命令以后,就会生成相应的.o文件,
在这里插入图片描述
2.打包
这里打包用的命令如下:

gcc -shared -o libMycircu.so *.o -I ../include/

用这个命令就打包了我们的动态库libMycricu.so
在这里插入图片描述
为了方便应用与发布动态库,我们将库移动放到特定的专门的lib文件夹下面。
移动到和src同级的lib文件夹下面。
3.如何使用动态库
同样这里可以有2中方式来编译,
第一种方法
用到的命令如下

gcc main.c lib/libMycircu.so -o circu -I include/

在当前目录,生成了可执行文件circu,
我们来执行下

./circu

执行结果:
在这里插入图片描述
第二种方法
用到的命令如下:

gcc main.c -I include/ -L lib/ -l Mycircu -o circu 

命令解析:
-I 表示包含的头文件, -L表示静态库的位置,-l表示库的名字,注意库的名字(libMycircu.so)是去掉了头(lib)和尾(.so)的。

执行生产的可执行文件Mycircu:
在这里插入图片描述
我们发现可执行文件出错了!!
这是为什么呢?
我们用ldd命令来查看生产的可执行文件需要连接的动态库,
在这里插入图片描述
发现问题了,原来是可执行文件链接不到我们自己制作的动态库!!

怎么才能链接到自己的动态库呢。
这里提供两种方法。

1.可以将我们自己制作的库临时加载到环境变量中;
系统为动态库提供了一个环境变量:LD_LIBRARY_PATH.
LD_LIBRARY_PATH主要的作用就是指定查找的动态库。
用如下命令指定动态库:

export LD_LIBRARY_PATH=~/hellomyself/lib_test/lib/libMycircu.so

运行上面的指令后,我们可以用ldd来查看可执行文件的库连接。
在这里插入图片描述
链接成功啦!
可以执行程序了:
在这里插入图片描述
这样加载只在当次有效,如果关掉终端就又得手动把动态库加载到环境变量中。

2.将我们制作的库,永久的加到系统配置文件中。
linux系统中提供了一个专门为动态库加载的配置文件,位置在/etc/ld.so.conf
打开这个文件,

sudo vi /etc/ld.so.conf`

然后在末尾加上我们自己的动态库的路径,
如下图:
在这里插入图片描述
然后更新这个文件:

sudo ldconfig -v

再次查看可执行文件的链接库:
在这里插入图片描述
我们自己的库已经链接成功啦!
这些可以执行可执行文件了:
在这里插入图片描述
执行结果符合预期,并且和静态库一致。

功成!

3.动态库与静态库的优缺点

1.静态库

优点:
1.由于静态库是在编译的时候就加载到可执行程序里面的,所以发布的时候不需要提供静态库;
2.由于静态库是在编译的时候就加载到可执行程序里面的,执行比较快。

缺点:
1.如果静态库修改了,就得重新编译可执行程序;
2.体积比较大。

1.动态库

优点:
1.由于动态库是执行的时候才去加载,所以可执行程序,体积小;
2.当动态库更新后(接口不变的更新),不用重新编译可执行程序,直接替换动态库即可。

缺点:
1.发布可执行程序的时候,需要将动态库一并给到用户;
2.由于程序是动态加载的,所以会相对静态库来说,加载会相对教慢。

这是简单的在linux下制作静态库和动态库的过程,已经优缺点。当然这里面还设置到很多程序内存分布的知识,后面可以专门拿来分析。

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值