轻松玩转Linux:静态库和动态库

本文详细解释了Linux中静态库和动态库的区别,包括创建步骤、使用方法、可执行文件大小、扩展性和依赖性,以及加载速度和制作复杂度。
摘要由CSDN通过智能技术生成

        库是指在我们的应用中,有一些公共代码是需要反复使用,就把这些代码编译为"库"文件;在链接步骤中,链接器将从库文件取得所需的代码,复制到生成的可执行文件中。

Linux中常见的库文件有两种,一种.a为后缀,为静态库,另一种以.so为后缀,为动态库

一、静态库

        可重定位目标文件以一种特定的方式打包成一个单独的文件,并且在链接生成可执行文件时,从这个单独的文件中“拷贝"它自己需要的内容到最终的可执行文件中。这个单独的文件,称为静态库。Linux中这类库的名字一般是libxxx.a。

1.创建步骤

将add.c sub.c创建成静态库文件:

  • 创建add.c sub.c
#add.c

int add (int a, int b) 
{
    return a + b;
}

#sub.c

int sub (int a, int b) 
{
    return a - b;
}
  • 对add.c sub.c编译成可重定位目标文件
gcc -c add.c -o add.o
gcc -c sub.c -o sub.o
  • 利用ar工具创建静态库: ar rcs lib 库名.a所有可重定位目标文件
#生成静态库
ar rcs libmath.a add.o sub.o 

2.静态库的使用

制作使用libmath.a静态库的程序

  • 创建main.c
#include<stdio.h>

int add(int a,int b);
int sub(int a,int b);

int main(int argc, char* argv[])
{
	int a=5,int b=3;
	printf("a+b=%d\n",add(a,b));
	printf("a-b=%d\n",sub(a,b));    
    return 0;
}
  • 编译main.c

编译时要将静态库libmath.a加上gcc选项:

  • l:指定库名(库的文件名为libxxx.a,库名为xxx)
  • L:指定库路径
  • static:使用静态链接
gcc -static main.c -l math -L ./
#注意:要先运行main.c后运行静态库文件

./a.out

特别注意,必须把-l math 放在后面。放在最后时它是这样的一个解析过程:

  • 链接器从左往右扫描可重定位目标文件和静态库
  • 扫描main.c时,发现两个未解析的符号add和sub,记住这两个未解析的符号
  • 扫描libmath.a,找到了前面未解析的符号,因此提取相关代码
  • 最终没有任何未解析的符号,编译链接完成

那如果将-l math放在前面,又是怎样的情况呢?

  • 链接器从左往右扫描可重定位目标文件和静态库
  • 扫描libmath.a,由于前面没有任何未解析的符号,因此不会提取任何代码
  • 扫描main.c,发现未解析的符号add和sub
  • 扫描结束,还有两个个未解析的符号,因此编译链接报错

生成可执行文件大小:

        生成的可执行文件大小为826k

        由于最终生成的可执行文件中已经包含了add和sub相关的二进制代码,因此这个可执行文件在一个没有libmath.a的Linux系统中也能正常运行。

二、动态库

        动态库和静态库类似,但是它并不在链接时将需要的二进制代码都“拷贝"到可执行文件中,而是仅仅“拷贝”一些重定位和符号表信息,这些信息可以在程序运行时完成真正的链接过程。Linux中这类库的名字一般是libxxx.so。(shared object)

1.创建步骤

//先编译成可重定位目标文件(生成与位置无关的代码-fPIC)
gcc -c add.c -o add.o -fPIC
gcc -c sub.c -o sub.o -fPIC
//使用gcc -shared 制作动态库
gcc -shared -o libmath.so add.o sub.o

-fPC作用:生成与位置无关的代码

2.动态库的使用

        通常我们编译的程序默认就是使用动态链接

gcc main.c -o main -l math -L ./

        通过动态库链接的程序只有8.5k.

        通过 ldd命令来观察可执行文件链接了哪些动态库:

        因为没有把 libmath.so 中的二进制代码“拷贝"可执行文件中,程序在其他没有上面的动态库时,将无法正常运行。

3.找不到动态库

        运行可以执行程序./main出错!!! ldd main --> "not found"

        链接器:工作于链接阶段,工作时需要-l和L

        动态链接器:工作于程序运行阶段,工作时需要提供动态库所在目录位置。

        原因:没有提供动态库的位置

解决方式:

  • 通过环境变量(临时生效): export LD_LIBRARY_PATH=动态库路径
  • 环境变量写入配置文件~/.bashrc(使用绝对路径),生效方法: .~/.bashrc或source ~/.bashrc 或 重启终端
  • 拷贝自定义动态库到lib(标准C库所在目录位置)(不推荐)

        【注】只是临时生效。关闭终端再重启时使用./main还会报错。如果想要一直生效需要写在配置文件中。

动态库绝对路径写到/etc/ld.so.conf配置文件中,生效方法: sudo ldconfig

三、静态库和动态库的区别

        静态库被使用目标代码最终和可执行文件在一起(它只会有自己用到的),而动态库与它相反,它的目标代码在运行加载时链接。正是由于这个区别,会导致下面所介绍的这些区别。

1.可执行文件大小

        静态链接的可执行文件要比动态链接的可执行文件要大得多,因为它将需要用到的代码从二进制文件中“拷贝”了一份,而动态库仅仅是复制了一些重定位和符号表信息。

2.扩展性与兼容性

        如果静态库中某个函数的实现变了,那么可执行文件必须重新编译,而对于动态链接生成的可执行文件,只需要更新动态库本身即可,不需要重新编译可执行文件。正因如此,使用动态库的程序方便升级和部署。

3.依赖原库文件

        静态链接的可执行文件不需要依赖其他的内容即可运行,而动态链接的可执行文件必须依赖动态库的存在。所以如果你在安装一些软件的时候,提示某个动态库不存在的时候也就不奇怪了。

即便如此,系统中一般存在一些大量公用的库,所以使用动态库并不会有什么问题。

4.加载速度

        由于静态库在链接时就和可执行文件在一块了,而动态库在加载或者运行时才链接,因此,对于同样的程序,静态链接的要比动态链接加载更快。所以选择静态库还是动态库是空间和时间的考量。但是通常来说,牺牲这点性能来换取程序在空间上的节省和部署的灵活性时值得的。

5.库的制作复杂度

        相对来讲,动态库的处理要比静态库要复杂,例如,如何在运行时确定地址?多个进程如何共享一个动态库?当然,这些我们不需要关注。另外动态库版本的管理也是一项技术活。

  • 30
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

了一li

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值