目录
前提
见一见
其实我们用过库,例如c/c++的标准库,比如我们用c语言的函数和STL等都要有具体的实现(说白了我们只是调用接口,实现功能并不是我们写的),他们的具体实现其实是在库当中了;
![](https://i-blog.csdnimg.cn/direct/72eae7df09994ac6951de2abdd55b867.png)
认识
我们知道在linux系统中有动静态库两种:
在linux中动态库的后缀一般是.so(动态库)程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。 一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文 件的整个机器码
在linux中静态库的后缀一般是.a (静态库)程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静 态库
在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个 过程称为动态链接;
动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚 拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间。
而在windows中动静态库也有:
在Windows中动态库的后缀一般是.dll(动态库)
在Windows中静态库的后缀一般是.lib(静态库)
我们知道大部分的指令都是由c语言实现的,举例:可以看到c语言库
静态库
我们之前弄过stdio的模拟实现:
那么有如下情景:
老师让做大作业,不用形成可执行程序,写一套库(math库和stdio库)但是呢你的朋友不会写,这时候让你帮忙想让copy你的一份源代码,但是不能给因为会重复但是最后都是要形成.o文件进行链接形成可执行文件,那么我把我的所有源文件都变为.o文件
默认形成同名.o文件
不给你源代码就给你二进制文件
那么朋友不用写源代码,但是呢他只看到二进制文件不知道怎么用 ,那么将声明也添加上
但是呢又要问了,我该怎么使用呢? 首先要有一个main.c进行检测的文件
他只用写main.c就行不用管函数实现,只需调用就行 ,再进行编译就行
这时报错了 ,因为找不到调用的接口,这时不仅光编译main.c也要编译.o
这时运行可执行文件,并查看文件操作可以看到成功运行
所以对我们来讲不用给源代码,只需要给实现方法的.o文件和头文件;
1. 头文件是一个手册,提供函数的声明,告诉用户怎么使用而.o提供实现,我们只需补上一个main.c调用头文件的方法,然后和.o进行连接,就能形成可执行;
2. 库的存在是提高开发效率(无论静态库都是) ;
那么老师又让我俩写更多的方法实现,那么我写好后我不能一个一个的将.o复制到朋友的目录下,一方面不方便另一方面可能我在传给朋友的时候少传导致运行不了。那么我可以打包所有的.o文件给他但是可能解包出现问题;那么我可以用一个命令ar(ar是gnu归档工具,rc表示(replace and create) ),这个能直接用不用解包此时将打包的.o文件cp到他的目录下
但是此时他编译的时候还是不对 那么上次编译可以带.o编译,但是此时没有.o文件了那么怎么编译呢,带上libmyc.a即可
所谓的库文件就是把.o文件打包;编译器会自己找自己解跟自己没关系了
实际情况上:
用ar命令(rc是什么意思呢?实际上我们的库有大量的.o,rc就是不存在就是新建存在就更新在打包的文件中)将目标文件打包成一个静态库
我们使用的是c/c++的库,而gcc/g++默认识别c/c++库,libmyc.a-->别人写的库(第三方提供,不是系统自带)gcc/g++不认识,需要加 -l才可以;
那么静态库可以理解为.o打个包安装在系统里,但是不建议非官方的文件放在系统里;所以删掉即卸库
那么此时进行编译就不行了
如果我不想安装静态库,就想在当前环境下用:
那么此时库就在当前目录下,但是我们直接编译报错
为什么报错,因为你的头文件和库文件并没有直接在当前目录而是在mylib目录里。头文件和.a文件也是实实在在的文件,以前我们说编译的时候会进行头文件展开(其实就是把头文件拷贝到源文件里预处理),但是拷贝的前提是把头文件打开找到,他们也有自己的inode号
但是gcc默认在自己的include下找头文件,并不会在自己随便写的目录找 ,那么用-I(-l 指定库名)
虽然报错了但是还是好事不会报上面的错误了,说明已经把头文件找到了,但是链接报错了,那么可以在指定的路径下找库-L(-L 指定库路径)
此时还报错,但我告诉编译器我的库在哪里了。我是告诉编译器我的库在哪里了但是可能有很多库我只是告诉库在哪里但没告诉哪个库,那么可以用-l 就可以形成
为什么出现error还能编译成功因为我指定了-I头文件路径,在系统里找不到就在我指定的找;
所以如果不想安装到系统里可以使用:
-I(大写)指定用户自定义的头文件路径
-L(大写)指定用户自定义的库文件路径
-l(小写)执行确定的第三方库的名字
动态库
形成动态库也是需要形成.o的,不过跟静态库不同需要加-fPIC(产生位置无关码(position independent code))
动态库在日常使用非常频繁,所以编译器自己形成不用ar命令
生成动态库规则:
shared: 表示生成共享库格式
fPIC:产生位置无关码(position independent code)
库名规则:libxxx.so
-o
选项用于指定输出文件的名称
将动态库给mylib目录,那么此时既有静态库也有动态库
那么为什么再次登陆就会不管用呢?我们可以通过修改.bashrc文件让环境变量永久生效
动态VS静态
默认连接的是动态库;
如果你没有使用-static,并且只提供.a,只能静态连接当前的.a库,其他库正常动态链接;
-static的意义是什么呢?
必须强制的将我们的程序进行静态连接,这就要求我们连接的任何库都必须提供对应的静态库版本;
那么我要用别人的库,别人应该给我提供什么呢?
一批头文件+一批库文件(.so/.a)