动静态库
- 一,什么是库
- 二,静态库的制作
- 静态库原理
- 三,动态库的制作
- 四,动态库的配置
- 五,动态库的加载
一,什么是库
🚀库这个东西我们一直在使用,举个简单了例子,无论你是用C的printf还是C++的cout的输出语句,这些函数的实现都不是你完成的,你都是调用了C/C++的标准库的,所以库这个东西我们使用的非常普遍。
🚀我们频繁的使用库就是为了提高我们的开发效率,假设每次的printf都要你自己实现,那可想而知效率肯定不如直接调用库的实现的效率高。
🚀头文件和库是配合使用的,我们要用printf那么就要包stdio.h这个头文件,在编译预处理的阶段头文件会在.c文件中展开,而库是在链接的时候与我们的文件链接在一起的。
🚀理解两种现象:
- 自动提醒功能
现在绝大多数的开发环境都带有自动提醒的功能,编译器是如何实现这一功能的呢?其实很简单,就是编译器根据用户的输入不断的在头文件中查找,将找到的信息通过下拉框的方式展现给用户,这是依赖于头文件的,如果你没有包头文件的话,是不会有自动提醒功能的。
- 提示语法错误
其实就是在我们编写代码的时候,编译器不断的在给我们的代码做编译工作,不断的进行语法检查,让后将错误显示出来。
🚀在Linux下动态库是.so 静态库是.a ,在Windows下动态库是.dll,静态库是.lib。
二,静态库的制作
🚀对于C/C++来说,通常将自己写的东西分享给别人的时候,一般是给源代码或者是打成库。
//myadd.h
#pragma once
int myadd(int x,int y);
//mysub.h
#pragma once
int mysub(int x,int y);
//mysub.c
#include "mysub.h"
int mysub(int x,int y)
{
return x - y;
}
//myadd.c
#include "myadd.h"
int myadd(int x,int y)
{
return x + y;
}
🚀我们自己要制作一个math库,里面有加法和减法两种功能,将这个库分享给其他人使用。
🚀制作静态库的步骤:
1,将.c文件编译成.o文件
gcc -c
2,将.o文件打成静态库
ar -rc libmymath.a *.o //把所有的.o文件打成一个静态库
注意: 对于库来说lib是它的前缀,如果是静态库那么后缀为.a,如果是动态库那么后缀是.so。
3,将头文件和库文件打包发给其他用户(通常是将库文件放在一个目录下,头文件放在一个目录下)
4,其他用户收到库后先解压,然后使用库即可。
#include <stdio.h>
#include "myadd.h"
#include "mysub.h"
int main()
{
int a = 10;
int b = 5;
printf("%d + %d = %d\n",a,b,myadd(a,b));
printf("%d - %d = %d\n",a,b,mysub(a,b));
return 0;
}
gcc -o mytest main.c -I include -L lib -l mymath
//-I :告诉编译器我们头文件的路径
//-L :告诉编译器我们库文件的路径
//-l :告诉编译器我们链接的库的名字
静态库原理
🚀我们的源文件在连接库文件的时候,对于静待库而言,是将用到的库中的方法的代码直接拷贝到自己的文件当中,形成可执行程序。依赖于静态库形成的可执行程序,即使静态库被删除程序依然可以跑,因为已经将库中的代码拷贝到自己的文件中了。
三,动态库的制作
🚀其实静态库的使用不多,通常情况下都是使用动态库,因为静态库是将库中的代码拷贝到自己文件中,这无疑增大了文件的体积。在Linux下默认都是连接动态库。
🚀将上面的代码打成动态库
1,生成的.o文件是与位置无关码
gcc -fPIC -c
2,将.o文件打成动态库
gcc -shared -o libmymath.so *.o
3,将库文件和头文件打包
4,其他用户解压,使用库
gcc -o mytest main.c -L lib -I include -l mymath
虽然形成了可执行程序,但是在./运行该程序的时候会发现运行不了,这是什么原因呢?
是这样的,我们在gcc的时候告诉编译器了头文件路径,库文件路径,库文件名称,但是运行的时候操作系统并不知道动态库所在的位置,所以我们要对动态库做配置。
注: 因为编译器对库的默认搜索路径是/lib64,对头文件默认搜索路径是/usr/include,如果使用gcc不想添加-I -L 选项时,可以将头文件和库文件移动到相关默认搜索路径下即可。
四,动态库的配置
🚀配置环境变量LD_LIBRARY_PATH,在这个环境变量中添加动态库的路径即可。
但是环境变量是内存级的,每次启动机器环境变量都会从相关的配置文件中加载,所以你再重启机器的时候又会发现可执行程序运行不了了。
🚀将第三方库挪动到/lib64目录下,这是操作系统的默认搜索路径。
🚀在/etc/ld.so.conf.d/目录下添加配置文件。文件的内容就是动态库的路径。
运行的时候还是不行,这是因为配置文件没有生效。
ldconfig //使配置文件生效
五,动态库的加载
🚀动态库又称为共享库,可以被多个进程所共享,那么是如何做到的呢?
首先说明,动态库与静态库连接方式不同,静态库是把所用到的库中的方法拷贝到自己的文件中,而动态库是把所用到的方法的地址拷贝到相应的位置。
程序运行起来变成一个进程,当他调用动态库中的方法时,此时动态库会被从磁盘加载到物理内存上,之所以称之为共享库是因为物理内存上只存在一份,而用到的进程会通过页表将物理内存上的动态库映射到自己的进程地址空间上,这时就会出现问题,如果动态库中的编码是绝对编码,这就对动态库映射到地址空间的位置是固定的,这几乎是不可能的,所以我们在打动态库的时候,形成的是与位置无关码,说白了就是形成的是相对地址,这样无论动态库被加载到地址空间的哪个位置,只要我们知道它的首地址和偏移量就能找到对应方法的地址。