目录
之前在 Linux环境基础开发工具使用篇(二) gcc/g++ 与 make/makefile-CSDN博客 这篇博客中已经初步解释过动静态库了,下面的重点是如何制作动静态库以及使用动静态库包括动静态库更加深入的理解!
静态库
理解静态库
想形成一个库,库中不应该有main函数! 编译选项不需要带头文件,因为头文件在当前路径下,编译器默认就能找到!
下面以实现简单的加减计算器为例,讲解静态库!
下面是使用Makefile自动化构建代码!
我们可以选择把所有的源文件从头开始编译成可执行程序,但是在大型项目中我们更倾向的是先把所有的源文件编译形成.o目标文件,然后将.o目标文件与.h头文件打包形成库,使用库的人只需要完成main函数, 然后进行将多个.o文件进行链接即可!这样做的原因就是在多文件项目中,形成不同的可执行程序是依赖不同的源文件的,所以只需要把.o文件组合式链接即可!
制作静态库
只需要将所有的.o文件打包即可!
使用静态库
gcc TestMain.c -lmymath -L.
gcc默认是动态链接的,但你的部分库是静态的,gcc只能把这些库静态链接,其他库依旧是动态链接,如果加了-static选项,就必须静态链接,没有静态库就会报错!
我们最终希望给用户提供的库和头文件要放在指定的目录下,按目录结构组织好交给用户!
程序员发布库:
用户使用库:
用户先从网上把库下载下来,然后解压!
然后就是将库安装到自己系统当中,安装本质就是把头文件和库文件拷贝到系统默认搜索路径下!
系统搜索头文件默认在/usr/include目录下,搜索库文件默认在/usr/lib64目录下!安装一会在讲解动态库的时候演示一下,此处我们可以给gcc带相应的选项进行链接库!
gcc TestMain.c -I mymath_lib/include -lmymath -L mymath_lib/lib
-I 指定是头文件搜索路径,-i 指定的是链接的库名称,-L指定的是库文件的默认搜索路径
如果已经把库安装到系统中了, -I选项和-L选项就可以不用带了!
动态库
动态库是比静态库更加重要的,形成动态库使用的仍然是gcc命令,而静态库是ar命令!
制作动态库
使用动态库
形成可执行程序之后,我们直接运行a.out 竟然报错了,那是因为我们要动态链接,gcc所带的选项只是告诉了gcc去哪里找头文件和库文件,但是./a.out运行程序之后系统也要能找到我们的头文件和库文件(因为是动态链接的,可执行程序文件和头/库文件是分离的), 而系统默认只会在当前目录下和系统默认路径下(/usr/include与 /usr/lib64)搜索,而我们的库文件和头文件不在这两个地方,因此报错了!
方法一:将头文件和库文件安装到系统中
方法二: 软链接文件
1.在当前目录下建立软链接文件
2.将软链接文件安装到系统中
方法三: 使用环境变量,让系统找到自己的动态库
系统中存在一个环境变量,LD_LIBRARY_PATH,在动态库加载的时候,系统也会去这个环境变量中查看动态库所在的路径了,因此我们只需要把我们的动态库所在路径添加到该环境变量中即可
当然这个是内存级的操作,想要环境变量长久生效,需要更改配置文件,详见博客 进程优先级与环境变量
方法四: 直接更改系统关于动态库的配置文件
/etc/ld.so.conf.d/ 该目录下有若干配置文件,都是管理系统动态库加载的配置文件!
所以我们也可以自己创建1个配置文件,把要使用的动态库的路径填进去就可以了!
动态库的加载
静态库不存在加载问题,因为在程序翻译的"链接"过程中,静态库的代码已经被拷贝到了可执行程序的代码区了,库代码就变成了我们自己的可执行程序的一部分了,我们自己的可执行程序如何加载,静态库就如何加载!
可执行程序是有格式的,Linux下,通常是ELF格式!比如形成可执行程序时就已经有了数据区,代码区等等,还有一张符号表,存放了程序中的库函数和该函数在内存中的地址!由于是动态链接的,因此不止我们的可执行程序要加载到内存中,依赖的动态库也要加载到内存中!
程序没有被加载到内存前,程序内部是有地址的!而编译形成二进制文件之后,编译形成二进制之后,变量名和函数名都变成地址了!而变量名和函数名都是给人看的!
此处就涉及到编址的问题,对代码的编址基本遵守虚拟地址空间的规则!所以虚拟地址空间,不仅是OS中的概念,编译器编译的时候,也要按照这样的规则编译形成可执行程序,这样才能在加载的时候,进行从磁盘文件到内存进行映射!
编址方式分为绝对编址和相对编址~
绝对编址容易受起始地址的影响!而相对编址不会受其起始地址的影响!这个不难理解,你是一名学霸,你的考试成绩很稳定,每次都离满分差2分,如果采用绝对方式,满分是100分,你就是98分,而当满分变成了120分,你就是118分了; 而采用相对编址,你的成绩"不变", 总是离满分差10分!这就是绝对编址与相对编址的区别!
在制作动态库的Makefile文件中,我们在编译源文件形成目标文件时,gcc选项带了-fPIC选项,含义是位置无关码!
再次理解程序的的加载以及cpu读取代码的过程!