动态库相关
在实习期间做的事情是对组内项目编译的辅助工具编写,期间涉及到很多关于动态库相关的一些内容,现在将动态库相关的一些知识来整理和重新学习一下,目前只考虑Linux环境
什么是动态库
说动态库之前要来看一下什么是"库",库是一系列可复用,成熟的,已经写好的代码,动态库是使用非常多的一种技术,动态库在程序运行的时候被载入(静态库是编译时),不同的程序调用相同的库的时候,内存中只存在一方该shared库的实例,相对于静态库来讲,动态库节约了空间资源,也使得部署的服务或应用在更新的时候变得十分轻量化(最开始下载游戏可能需要下载好几个G,但是玩了一段时间发现要更新下载的内容就十分少量,这就是应用了动态库的技术使得用户得到了更好的体验)
创建动态库的方法(Linux)
在Linux下gcc编译的执行文件默认的ELF格式,不需要初始化入口,也不需要对函数进行特别的声明,直接编写即可,十分方便。
例子:
//math.h
1 #ifndef __MATH_H__
2 #define __MATH_H__
3
4 void Add(int x, int y);
5
6 void Sub(int x, int y);
7
8 void Mul(int x, int y);
9
10 void Div(int x, int y);
11 #endif
//math.cc
1 #include <iostream>
2 #include "math.h"
3
4 void Add(int x, int y)
5 {
6 std::cout<<x<<" + "<<y<<" = "<<x+y<<std::endl;
7 return;
8 }
9
10 void Sub(int x, int y)
11 {
12 std::cout<<x<<" - "<<y<<" = "<<x-y<<std::endl;
13 return;
14 }
15
16 void Mul(int x, int y)
17 {
18 std::cout<<x<<" * "<<y<<" = "<<x*y<<std::endl;
19 return;
20 }
21
22 void Div(int x, int y)
23 {
24 if(y == 0)
25 return;
26 else
27 {
28 std::cout<<x<<" / "<<y<<" = "<<x/y<<std::endl;
29 }
30 }
对要生成的动态库进行编译,用g++ -fPIC -shared 编译
[root@localhost MathLib]# g++ -fPIC -shared -o libmath.so math.cc
[root@localhost MathLib]# ls
libmath.so math.cc math.h
生成了动态库libmath.so文件。
如何使用动态库
直接引用动态库的头文件,在编译的时候加上 -L指定动态库的路径,-l指定动态库的文件名
实例程序:
1 #include "MathLib/math.h"
2
3 int main()
4 {
5 Add(1, 2);
6 Sub(2, 1);
7 Mul(2, 2);
8 Div(2, 1);
9 return 0;
10 }
编译:
[root@localhost test_for_lib]# g++ test.cc -L./MathLib -lmath
[root@localhost test_for_lib]# ls
a.out MathLib test.cc
其中要注意的地方就是对于.so文件在 -l的时候,要省略前边的lib和后边的.so字段,比如库名为 libmath.so 就写 -lmath就ok了。
运行程序:
[root@localhost test_for_lib]# ./a.out
./a.out: error while loading shared libraries: libmath.so: cannot open shared object file: No such file or directory
直接运行./a.out会报错,因为系统在加载代码的时候能知道所依赖的库的名字,但是还需要知道绝对路径,这时候就需要 系统动态载入器(dynamic linker/loader),对于elf格式的可执行程序,是由ld-linux.so*来完成的,他先搜索elf文件的DR_RPATH段一环境变量LD_LIBRARY_PATH-/etc/ld.so.cache文件列表-/lib/ 或者 /usr/lib/ 下来找到库文件将其载入内存,所以当库安装在/usr/lib/ 或者 /lib/目录下的时候ld默认能直接找到,不需要做其他的操作,若是将其安装到其他的目录地下需要编辑 /etc/ld.so.conf 文件 include 库的绝对路径(到目录层面即可),再运行 ldconfig 来重建 /etc/ld.so.cache文件即可运行起来了
[root@localhost test_for_lib]# ldconfig
[root@localhost test_for_lib]# ./a.out
1 + 2 = 3
2 - 1 = 1
2 * 2 = 4
2 / 1 = 2
这样就完成了一个简单的动态库的编写与使用过程