静态库和动态库
1 扫盲
- 库是什么?
- 二进制的程序
- 为什么要使用库?
- 方便使用:
- 发布给使用者
- 保密
- 方便使用:
- 库有了如何使用?
- 要将生成的库给到使用者
- 需要将头文件给到使用者
2 静态库
-
命名规则
- Linux
- libxxx.a
- lib: 前缀
- .a: 后缀
- xxx: 名字, 由库的制作者定的
- libxxx.a
- windows
- libxx.lib
- Linux
-
静态库制作
. ├── add.c ├── div.c ├── include │ └── head.h ├── main.c ├── mult.c └── sub.c 1 directory, 6 files # 1. 将源文件生成 .o 文件 $ gcc -c sub.c add.c mult.c div.c -I ./include/ robin@OS:~/Linux/3Day/calc$ tree . ├── add.c ├── add.o ├── div.c ├── div.o ├── include │ └── head.h ├── main.c ├── mult.c ├── mult.o ├── sub.c └── sub.o 1 directory, 10 files # 2. 将.o 文件打包 生成 库文件 # 语法: ar rcs 生成的库的名字 *.o文件 $ ar rcs libcalc.a *.o robin@OS:~/Linux/3Day/calc$ ls add.c add.o div.c div.o include `libcalc.a` main.c mult.c mult.o sub.c sub.o # 发布 将 `libcalc.a` `head.h` 拷贝给使用者即可 -
静态库使用
. ├── include │ └── head.h `静态库对应的头文件` ├── libcalc.a `静态库` └── main.c `测试程序` 1 directory, 3 files # 编译测试程序 $ gcc main.c -o app -I include/ /tmp/cceWxYij.o: In function `main': main.c:(.text+0x38): undefined reference to `add' main.c:(.text+0x58): undefined reference to `subtract' main.c:(.text+0x78): undefined reference to `multiply' main.c:(.text+0x98): undefined reference to `divide' collect2: error: ld returned 1 exit status # 错误原因: 编译的时候找不到对应的库, 库中有函数定义(函数实现) # 指定自己编译的库需要使用的参数: -L: 指定库的路径 -l: 指定库的名字(掐头(lib) 去尾(.a)) $ gcc main.c -o app -I include/ -L ./ -l calc
3 动态库/共享库
共享 -> 共享内存中的库
-
命名规则
- linux:
- libxxx.so
- 前缀: lib
- 后缀: .so
- 库的名字: xxx, 制作库的人指定的
- libxxx.so
- windows:
- vs版
- libxxx.lib
- libxxx.dll
- 非vs版
- libxx.dll
- vs版
- linux:
-
动态库制作
. ├── add.c ├── div.c ├── include │ └── head.h ├── main.c ├── mult.c └── sub.c 1 directory, 6 files # 制作步骤: # 1. 将源文件生成 .o 文件 -fpic/fPIC $ gcc -c add.c div.c mult.c sub.c -fpic -I ./include/ # 2. 将 .o 文件 打包(gcc -shared)成 库文件 .so $ gcc -shared *.o -o libcalc.so obin@OS:~/Linux/3Day/calc$ tree . ├── add.c ├── add.o ├── div.c ├── div.o ├── include │ └── head.h ├── `libcalc.so` # 生成的动态库 ├── main.c ├── mult.c ├── mult.o ├── sub.c └── sub.o # 发布 将 `libcalc.so` 和 `head.h` 发布给使用者 -
动态库使用
. ├── include │ └── head.h ├── libcalc.so └── main.c $ gcc -I include/ main.c -L./ -lcalc -o app$ ./app ./app: error while loading shared libraries: libcalc.so: cannot open shared object file: No such file or directory # 使用命令检测可执行程序能不能加载到对应的动态库? ldd 可执行程序名 $ ldd app linux-vdso.so.1 => (0x00007ffde8d77000) libhello.so => `not found` libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f289bd43000) /lib64/ld-linux-x86-64.so.2 (0x00007f289c10d000) -
库的工作原理
/* 静态库: gcc main.c -o app -I include/ -L ./ -l calc - 在最终的链接阶段, 链接器会将静态库 calc 打包到可执行程序 app中 - 在可执行程序执行的时候, app中所有的代码会被加载到内存 */ /* 动态库: gcc -I include/ main.c -L./ -lcalc -o app - 在最终的链接阶段, 链接器不会将动态库 calc 打包到可执行程序 app中, 在上边的命令中只是检测动态库是否存在 - 在可执行程序执行的时候, app中所有的代码会被加载到内存, 不包括动态库代码 - 当库中的函数被调用的时候, 动态库被加载到内存(加载的时候需要知道动态库在什么位置) - 库的加载是由动态链接器加载的 */# 动态链接器是如何加载动态库的? 它先后搜索可执行程序文件的 `DT_RPATH段` —> 环境变量`LD_LIBRARY_PATH` —> `/etc/ld.so.cache`文件列表 —> `/lib/`, `/usr/lib`目录找到库文件后将其载入内存。 -
解决动态库找不到的问题
#1. 将动态库的路径放到环境变量 LD_LIBRARY_PATH 中 在终端执行下边的命令: (这是临时设置, 当前终端被关闭或切换到其他终端该设置就无效了) export LD_LIBRARY_PATH=/home/robin/test:$LD_LIBRARY_PATH 永久设置: 将上边的命令写入到配置文件中 - 用户级别: `~/.bashrc` - 系统级别: `/etc/profile` 配置完成之后, 需要让配置文件重新被加载 . == source . ~/.bashrc . /etc/profile #2. 将动态库的路径更新配置文件 /etc/ld.so.cache 中 - 将动态库的路径添加到配置文件 /etc/ld.so.conf - 将/etc/ld.so.conf中的信息更新/etc/ld.so.cache - sudo ldconf #3. 将动态库添加到对应的系统目录中 - /lib - /usr/lib
4 对比
-
静态库
-
优点:
-
- 静态库被打包到应用程序中加载速度快
- 发布程序无需提供静态库,移植方便
-
缺点:
-
- 销毁系统资源,浪费内存
- 更新、部署、发布麻烦。
-
-
动态库
-
优点:
-
- 可实现进程间资源共享
- 程序升级简单
- 程序猿可以控制何时加载动态库
-
缺点:
-
- 加载速度比静态库慢
- 发布程序需要提供依赖的动态库
-