参考学习:Linux下的各种文件 、动态库基本原理和使用方法,-fPIC选项的来龙去脉 、Linux静态库和动态库分析
文章写作参考:Linux共享库、静态库、动态库详解 - sunsky303 - 博客园 (cnblogs.com)
一.Linux共享库、静态库、动态库详解
使用GNU的工具我们如何在Linux下创建自己的程序函数库?一个“程序函数库”简单的说就是一个文件包含了一些编译好的代码和数据,这些编译好的代码和数据可以在事后供其他的程序使用。程序函数库可以使整个程序更加模块化,更容易重新编译,而且更方便升级。
程序函数库可分为3种类型:静态函数库(static libraries)、共享函数库(shared libraries)、动态加载函数库(dynamically loaded libraries):
1、静态函数库,是在程序执行(编译)前就加入到目标程序中去了 。
- 优点:
- 静态库被打包到应用程序中加载速度快;
- 发布程序无需提供静态库,因为已经在app中,移植方便。
- 缺点:
- 连接是完整地拷贝至可执行文件中,被多次使用就有多份冗余拷贝;
- 更新、部署、发布麻烦。
2、动态函数库同共享函数库是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小(在Linux上叫共享对象库, 文件后缀是.so
,Windows上叫动态加载函数库, 文件后缀是.dll
)。
- 优点:
- 链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序可以共用,节省内存;
- 程序升级简单,因为app里面没有库的源代码,升级之后只要库的名字不变,函数名以及参数不变,只是实现做了优化,就能加载成功。
- 缺点:
- 加载速度比静态库慢;
- 发布程序需要提供依赖的动态库。
Linux中命名系统中共享库的规则
二.静态库的制作和使用
-
命名规则
静态库文件名的命名方式是
libxxx.a
,库名前加lib
,后缀用.a
,xxx
为静态库名。 -
制作步骤
原材料:源代码
.c
或者.cpp
。- 将
.c
文件生成.o
:gcc a.c b.c -c
。 - 将.o 打包:
ar rcs
静态库的名字 原材料 ->ar rcs libtest.a a.o b.o
。
- 将
-
静态库的使用
gcc test.c -ltest -L ./ -o main
-l
(小写的L):指定要用的静态库,库名要看头去尾(即要去掉lib
和后缀.a
)。-L
(大写的L):告诉gcc
编译器从-L
指定的路径去找静态库,如果没有指定,则默认从/usr/lib
或/usr/local/lib
去找 ,这里有指定./
,-L ./
的意思就是从当前路径去找。-o
(小写的O):指定生成的可执行文件。- 运行:直接像我们平时运行一样
./main
。
三.动态库的制作和使用
-
命名规则
动态库的命名方式与静态库类似,前缀相同,为
lib
,后缀变为.so
。所以为libxxxx.so
。 -
制作步骤
-
将源文件生成
.o
,需要加一个参数fpic
:gcc a.c b.c -c -fpic(fPIC)
-
打包:
gcc -shared a.o b.o -o libxxx.so
-
一般直接:
gcc -fPIC -shared -o libxxx.so xxx.c
创建符号链接:
ln -s libxxx.so.1.0 libxxx.so.1
-
**注意:**这里的
-fPIC
中的PIC
是大写,也有小写的-fpic
(产生的代码相对较小,而且较快),在有些平台使用小写的-fpic
选项有一些限制,而大写的-fPIC
没有这个问题。绝大多数情况使用-fPIC
。 -
关于PIC的理解:地址无关代码(Position Independent Code, PIC)
模块间的函数调用、跳转和数据访问目的地址要等到装载时才能确定,ELF文件的做法是在数据段里面建一个指向这些模块间全局变量的指针数组,也被称为全局偏移表(Global Offset Table, GOT),当代码需要引用模块间全局变量时,可以通过GOT中的表项间接的引用。由于GOT是存放在数据段中,所以动态库在装载时可以被修改,每个进程都有独立的副本,相互之间不受影响。在编译时可以确定GOT相对于当前指令的偏移,编译器决定GOT内的每一项(4个字节为一项,一个指针)对应于哪一个全局变量名称,也就GOT给出了需要重定位的全局变量有哪些,以及该全局变量相对于GOT的位置。动态链接器在装载模块时会查找每个变量所在地址,然后填充GOT中的各个项,确保GOT中每个指针所指向的地址是正确的。
参考:动态库基本原理和使用方法,-fPIC选项的来龙去脉
-
-
-
库的使用
gcc main.c -L ./ -ltest -o mainPro
如果直接运行
./mainPro
会提示No such file or directory
,需要进行环境变量的设置。-
使用环境变量
-
临时设置:在终端进行:
export LD_LIBRARY_PATH=动态库的路径:$LD_LIBRARY_PATH
-
永久设置:
用户级别:
~/.bashrc
,配置完成之后,重启终端或者source ~/.bashrc
系统级别:
/etc/profile
,配置完成之后,重启计算机或者source /etc/profile
-
-
把库拷贝到
/usr/local/lib
目录下。 -
修改
/etc/ld.so.conf
文件,把库所在的路径加到文件末尾,并执行ldconfig
刷新。这样,加入的目录下的所有库文件都可见。
-
local/lib`目录下。
- 修改
/etc/ld.so.conf
文件,把库所在的路径加到文件末尾,并执行ldconfig
刷新。这样,加入的目录下的所有库文件都可见。