Skip to content

动态库与静态库

C++的库又被分为两种,静态库,动态库。动态库在C++程序中是经常使用的,一定要理解动态库的工作原理并且会制作它。静态库的使用频率要比动态库低一些,但工作原理和制作流程还是要尽量掌握的。

库的作用

很多时候,一套源代码是非常宝贵的,我们并不想让他人知道实现部分。

可以只给他人提供一个头文件,也就是调用接口。而将实现部分(也就是对应的cpp文件)编译为二进制文件(二进制文件人类无法阅读),实现部分在被编译为二进制文件后,就被称为库。

如果不想让别人修改已经写好的代码,就可以给他人提供已经编译好的库,这样既加快了程序的编译或执行速度,又防止他人修改代码。

C++动态库

cout是ostream类的对象,ostream类的声明部分在iostream中,那ostream的实现部分在哪里呢? 答案是,在C++动态库中。至于动态库究竟是什么,我们实际看一下。

bash
# 编译test
g++ main.cpp add.cpp sub.cpp -o test 
# 查看可执行文件所需要的动态链接库
ldd test # 输出libstdc++.so.6 => /lib/x86-64-linux-gnu/libstdc++.so.6
# 查看链接
ls -l libstdc++.so.6 # 输出libstdc++.so.6 => libstdc++.so.6.0.28

看到libstdc++.so.6是个软链接 这个软链接指向的才是cpp真正的动态运行库 如果我们要升级cpp版本 我们只需要下载好最新版本的动态运行库 让这个指向新的动态运行库就可以了

动态库

动态库是程序执行时才会连接的库,也就是说,程序如果缺乏动态库,那么仍然是可以编译的,只不过在执行时会出现找不到定义的错误。

每个进程都有动态库链接区,这个区就是存储程序在编译时链接的动态库的。

动态库制作

PIC是 Position Independent Code 的缩写,表示要生成位置无关的代码,这是动态库需要的特性

-shared告诉g++生成动态库而不是可执行文件。

bash
g++  -fPIC  -shared  fileName.cpp  -o libFileName.so
g++  main.cpp  -L ./  -l sub -o test

动态库使用

动态库的设计理念这样就是将动态库集中在几个目录中,这样方便管理。

比如C++程序常用的io库,stl库就作为动态库存放在固定目录中。

如果通过-L来指定目录,那么容易导致库的存储混乱,带来各种麻烦,比如程序的部署就是个大问题。

于是,进程在加载动态库时,会按照优先级从高到低的顺序在以下路径依次寻找,找不到就报错了。

我们需要把动态库拷贝到那些路径可以找到的地方。

1.在生成可执行文件时指定动态库的存放路径

bash
g++ main.cpp sub.cpp -L ./ -ladd -Wl,-rapt=./ -o test

一般不推荐使用,容易导致动态库的存放混乱。知道有这么个方法就可以了。

2.修改环境变量:

bash
export LD_LIBRARY_PATH = $LD_LIBRARY_PATH:libPath

这种方法最简单,但只可以作为临时的设置方式。如果修改配置文件使其长期生效当然可以,但这种修改配置文件的方式不推荐,如果大家有兴趣,可以百度一下,非常简单。

3.在/lib,/usr/lib目录中查找动态库。

  • 我们直接将动态库复制到这两个目录中当然是可以的。
  • 但是/lib目录下存放的动态库大都是系统级别的,比如C++标准库
  • 我们自己的动态库一般不会直接拷贝到/lib目录中。

4.在/etc/ld.so.config文件中添加动态库路径

  • sudo vim /etc/ld.so.conf
  • 在文件最后行添加路径
  • 保存并退出文件后再 sudo ldconfig
  • 在做项目时,可以在/usr/local下创建一个目录。
  • 然后将这个目录添加到/etc/ld.so.config文件中。

这四种方法:3用的最少,1偶尔会用,2,4用的都比较普遍。短期内设置路径就用2,长期设置路径,就用4。

静态库

静态库是在程序编译时就会被整合进最终可执行文件的库。程序如果缺乏静态库,那么根本无法编译,在编译期就会报错。

静态库制作

bash
# 静态库的制作:
g++ -c *.cpp # 将.cpp 文件生成对应的.o文件。
ar  rcs libxxx.a  *.o # 使用ar工具将多个.o文件生成一个静态库,

ar工具是什么,rcs参数什么意思都不用管,这么记住就可以了。

静态库使用

静态库虽然使用频率和动态库比要低一些,但仍然是最好要掌握的,

bash
g++ main.cpp -L./ -lxxx -o test

这样最终可执行程序就制作完毕了,因为静态库直接被编译在最终可执行程序中,所以不需要考虑链接路径的问题。

静态库与动态库

使用静态库得到的程序体积要比动态库大很多

  • 静态库是在编译期被整合进可执行程序的,每有一个地方调用静态库,就要将静态库整合进去,所以如果这个库被频繁调用的话,会导致整个可执行文件大的离谱。
  • 动态库只有在可执行文件执行时才会被加载,也就是说动态库只加载了一次。

使用动态库的程序在启动时要比静态库慢一些

  • 动态库在执行时才会加载,而静态库在编译时就加载了,所以使用动态库自然会慢一些。

总结:一般我们都使用动态库,比如C++运行库,当然,如果有些程序被加载的次数很少,且比较追求启动时的效率,也可以使用静态库。