静态库和动态库

目录

一、静态库

1、制作静态库

1. 头文件 (add.h)

2. 实现文件 (add.c)

3. 编译源文件为对象文件

4. 创建静态库

5. 使用静态库

6. 编译并链接测试程序

7. 运行测试程序

​编辑

2、静态库是什么?

3、为什么有库?

4、静态库编译

二、动态库

1、制作动态库

2、添加动态库

三、-static

四、第三方库

五、动态库在内存的管理


(对于一个新的认知,是不可能建立在抽象上的,所以必须具体。我会先带着你看现象,然后再去解释,这是什么,为什么,怎么办。)

本文章,将介绍:

什么是静态库?

动态库如何写静态库和动态库?

第三方库是什么?

怎么用调库?等

一、静态库

查找文件依赖的库:

ldd

Linux下,以.so结尾为动态库、.a为静态库

1、制作静态库

第一步,写一个.h的头文件,头文件内写有函数声明

第二步,写.c文件,.c文件内写有对应头文件中函数的实现

第三步,编译.c文件,得到.o文件

第四步,制作静态库,使用ar -rc命令(-rc:replace and create)

(.o 可重定位目标文件(目标文件)
 .h头文件是一个手册,提供函数声明,告诉用户怎么用
.o文件提供实现,只需提供main函数,调用实现的方法,再和.o文件链接就行了)

示例:(将file1.o file2.o两个目标文件,打包成为libmylib.a静态库)

ar -rc libmylib.a file1.o file2.o

为了制作一个简单的 ADD 静态库,下面提供了头文件和实现代码,以及如何创建静态库的步骤。

1. 头文件 (add.h)
// 函数声明
int add(int a, int b);

(为了简单,我们去掉条件编译)

2. 实现文件 (add.c)
// add.c
#include "add.h"

// 函数实现
int add(int a, int b) {
    return a + b;
}
3. 编译源文件为对象文件

首先,使用 gcc 编译源文件 add.c 为对象文件 add.o

gcc -c add.c
4. 创建静态库
ar -rc libadd.a add.o
5. 使用静态库

编写一个测试程序来使用这个静态库,例如 main.c

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

int main() {
    int result = add(3, 5);
    printf("Result of add(3, 5): %d\n", result);
    return 0;
}
6. 编译并链接测试程序

将测试程序 main.c 与静态库 libadd.a 链接:

gcc main.c -L. -ladd -o test_program
  • -L.:指定当前目录作为库文件的搜索路径。
  • -ladd:链接 libadd.a 库(lib 前缀和 .a 后缀可以省略)。
7. 运行测试程序

运行编译好的程序来验证静态库是否工作正常:

./test_program

2、静态库是什么?

所谓的库文件,本质就是把.o文件打包

3、为什么有库?

提高开发效率。

例如说,程序员的第一个代码:“Hello,World!”,向屏幕输出。你要做的就是,写上头文件,然后待用一个叫做printf的函数,然后对应格式写好,然后run即可。这个期间你做了什么?编译、运行、执行、打印、二进制、汇编等等所有的工作你什么都没有做,你就是一个计算机小白,啥也不会,你只是打了几个字,然后键盘按下Ctrl+F5,然后over。没了。你做的工作,只是打了几个字。打字,你告诉幼儿园小朋友,先按键盘的这个,再按键盘的哪个,最后按这个.......小孩都会编程。简直就是小孩玩泥巴。所以,这让我们站在巨人的肩膀上去看世界,改变世界。降低我们的学习成本。这就是为什么会有库的原因。

4、静态库编译

库一般以lib开头,后面的才是真正的名字,例如:linbc.so.6就是标准C语言的库,其实叫做c.so

不建议把静态库下载到我们的操作系统上
那么怎么办?
要使用-L(Link),-I(include)三个命令:

选项作用用法示例说明
-L指定库文件所在的目录gcc -o myprogram main.c -L/usr/local/lib -lmylib指定库文件的搜索路径,链接时查找 libmylib.a 或 libmylib.so
-I指定头文件的搜索目录gcc -o myprogram main.c -I/usr/local/include指定头文件的搜索路径,查找 main.c 中包含的头文件

头文件中:
“”双引号的意思:在用户自己写的头文件查找
<>:在系统头文件查找

系统中的库路径:头文件路径:usr/include、文件路径:/usr/lib64

示例:-L表示头文件路径、-I表示库文件路径

gcc -o myprogram main.c -L/usr/local/lib -lmylib -I/usr/local/include

二、动态库

1、制作动态库

以.so结尾

形成动态库:直接使用gcc(gcc在不使用static选项时,默认使用动态库)

gcc -shared -o libmylib.so file1.o file2.o

动态库:因为动态库要在程序运行的时候,找到动态库加载并运行
为什么静态库没有这个问题呢?
这是因为静态库在编译期间,已经将库的代码拷贝到我们的可执行程序内部
运行和加载,就和库没有关系了

当我们自己写了一个动态库时,
我们告诉gcc编译器动态库的文件路径
于是,形成了可执行程序
但是,运行可执行程序却出问题
会显示,找不到动态库
这是为什么?
因为,可执行程序的执行,是由操作系统完成
你并没有将动态库的文件路径位置告诉操作系统
所以,当操作系统运行可执行程序时
找不到动态库,那怎么办呢?

2、添加动态库

方法说明示例命令/步骤
1. 将动态库复制到系统目录将动态库文件复制到系统的动态库目录,如 /usr/lib 或 /usr/local/libsudo cp libmylib.so /usr/local/lib
2. 建立软链接在系统动态库目录中创建库文件的软链接。sudo ln -s /usr/local/lib/libmylib.so /usr/lib/libmylib.so
3. 使用 LD_LIBRARY_PATH临时添加动态库路径到环境变量 LD_LIBRARY_PATHexport LD_LIBRARY_PATH=/path/to/library:$LD_LIBRARY_PATH
4. 永久添加到 .bashrc将 LD_LIBRARY_PATH 设置添加到用户的 .bashrc 文件中(不推荐)。echo export LD_LIBRARY_PATH=/path/to/library:$LD_LIBRARY_PATH' >> ~/.bashrc<br>source ~/.bashrc
5. 更新 /etc/ld.so.conf.d在 /etc/ld.so.conf.d 目录下创建配置文件并使用 ldconfig 更新库缓存。echo '/path/to/library'

1、将动态库cp到系统的动态库中
2、建立软链接
3、LD_LIBRARY_PAYH,环境变量方式添加
library:库
4、永久添加:到~家目录的.bashrc文件中添加(不推荐)
5、/etc/ld.so.conf.d 新增动态库搜索的配置文件,ldconfig命令生效

三、-static

当文件编译时,默认链接的是动态库;如果没有使用-static,并且只提供.a,只能静态链接当前的.a库,其他的库正常动态链接
-static的意义是什么?必须强制进行静态链接
这需要保证必须提供对应的静态库

四、第三方库

第三方库,其实就是别人写的库。根据上述的了解,大家应该可以自行掌握第三方库了。

如果用第三方库:用头文件+库文件
推荐第三方库:ncurses(超详细) ncurses 库使用介绍: 实现终端 GUI - 四季夏目天下第一 - 博客园 (cnblogs.com)

五、动态库在内存的管理

动态库加载:可执行程序 和 地址空间
动态库在加载后要映射到当前进程的地址空间中的堆、栈之间的共享区
动态库首先会加载到内存中
然后,哪一个进程用到动态库
就会在页表形成和动态库地址的映射
映射的一端是介于堆和栈之间的共享区
另一端是动态库的内存地址

而动态库在内存中只需要加载一份
当其他进程也用到该动态库时
这个就会相应的,通过页表,加载动态库内存地址和进程的共享区之间的映射
以此类推,再多的进程也是如此
因此,动态库也叫做共享库

我们的可执行程序,编译成功,没有加载运行,二进制代码有“地址”吗?
有地址
可执行和程序编译之后,会变成很多汇编语句,每条汇编语句都会有他自己的地址

反汇编命令:objdump -d binary_file


如何编制?
全0到全F编址,叫做平坦模式
于是,可执行文件记录了所有的代码的地址信息
这些地址叫做逻辑地址,其实也等价于虚拟地址
同时,也就有了各个数据段的开始位置和结束位置
于是,当运行程序,创建程序时
可执行文件内的所编译的数据就可以用来初始化进程的属性结构体mm_struct
同时,可执行文件的虚拟地址和和物理地址也建立起映射关系

虚拟地址空间,不仅仅是操作系统独有
虚拟地址空间是一个标准
这个标准加载器、编译器也要遵守

在CPU内,有一个PC寄存器
PC指向正在执行指令的下一条指令
PC指向哪个位置,CPU就执行那里的代码
当CPU开始执行代码时
PC会指向可执行文件的虚拟地址
再通过虚拟地址找到对应物理地址
于是,整个程序就这样运转起来

库加载到内存任意位置都可以正常运行
因为库内部的各个函数部分,是偏移量
偏移量不变,所以加上库的起始地址就可以访问对应函数
所以,库加载到不同的内存位置,本质是改变库的起始位置

所以本质上,库函数调用,其实也是在我的地址空间内来回跳转

操作系统内会有很多被加载的库
所以需要管理
怎么管理?
先描述、再组织
库也是文件
也要创建结构体管理
所以,会有一个维护库结构体的链表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

二十5画生

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

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

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

打赏作者

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

抵扣说明:

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

余额充值