1. 认识静态库与动态库
- 静态库(.a):程序在编译链接的时候把库的代码链接到可实行文件中。程序运行的时候将不再需要静态库。
- 动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享利用库的代码。
- 一个动态库链接的可实行文件仅仅包含它用到的函数入口地点的一个表,而不是外部函数所在目标文件的整个呆板码。
- 在可实行文件开始运行从前,外部函数的呆板码由利用体系从磁盘上的该动态库中复制到内存中,这个过程称为动态链接(dynamic linking)。
- 动态库可以在多个程序间共享,所以动态链接使得可实行文件更小,节省了磁盘空间。利用体系接纳虚拟内存机制,允许物理内存中的一份动态库被 需要用到该库的所有历程 共用,节省了内存和磁盘空间。
本文测试准备代码:
- // ---------- add.h ----------
- #ifndef __ADD_H__
- #define __ADD_H__
- int add(int a, int b);
- #endif
- // ---------- add.c ----------
- #include "add.h"
- int add(int a, int b)
- {
- return a + b;
- }
- // ---------- sub.h ----------
- #ifndef __SUB_H__
- #define __SUB_H__
- int sub(int a, int b);
- #endif
- // ---------- sub.c ----------
- #include "sub.h"
- int sub(int a, int b)
- {
- return a - b;
- }
- // ---------- main.c ----------
- #include <stdio.h>
- #include "add.h"
- #include "sub.h"
- int main()
- {
- int a = 10;
- int b = 20;
- printf("add(%d, %d) = %d\n", a, b, add(a, b));
- a = 100;
- b = 20;
- printf("sub(%d, %d) = %d\n", a, b, sub(a, b));
- return 0;
- }
复制代码 2. 手动创建并测试静态库
2.1 生成静态库
我们先利用下令生成一个静态库,并测试是否可以利用:
- # 把上面的代码拿过来
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ ls -l
- total 20
- -rw-rw-r-- 1 ubuntu ubuntu 61 Apr 20 20:13 add.c
- -rw-rw-r-- 1 ubuntu ubuntu 65 Apr 20 20:13 add.h
- -rw-rw-r-- 1 ubuntu ubuntu 243 Apr 20 20:33 main.c
- -rw-rw-r-- 1 ubuntu ubuntu 61 Apr 20 20:15 sub.c
- -rw-rw-r-- 1 ubuntu ubuntu 65 Apr 20 20:14 sub.h
- # 生成 .o 文件,准备打包为静态库
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ gcc -c add.c -o add.o
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ gcc -c sub.c -o sub.o
- # 生成静态库
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ ar -rc libmymath.a add.o sub.o
- # ar 是 gnu 归档工具,常用于将目标文件打包为静态库
- # rc 表示(replace and create)
- # 查看静态库中的目录列表
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ ar -tv libmymath.a
- rw-r--r-- 0/0 1376 Jan 1 08:00 1970 add.o
- rw-r--r-- 0/0 1376 Jan 1 08:00 1970 sub.o
- # t:列出静态库中的文件
- # v:verbose 详细信息
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ gcc main.c -L. -lmymath
- # -L:指定库路径
- # -l:指定库名
- # 测试静态库
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ ls
- add.c add.h add.o a.out libmymath.a main.c sub.c sub.h sub.o
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ ./a.out
- add(10, 20) = 30
- sub(100, 20) = 80
- # 测试目标文件生成后,静态库删掉,程序照样可以运行
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ rm libmymath.a
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ ./a.out
- add(10, 20) = 30
- sub(100, 20) = 80
复制代码 2.2 打包静态库
如果想把这个静态库给别人利用,我们需要将 库(.a)和 头文件(.h)一起打包;如许别人在看到头文件的时候,就知道我们的库中封装了哪些方法。
利用 Makefile 进行自动化编译:
- # ---------- Makefile ----------
- libmymath.a:sub.o add.o
- ar -rc $@ $^
- %.o:%.c
- gcc -c $<
- .PHONY:clean
- clean:
- rm -rf *.o output libmymath.a
- # 将相关文件打包到 output 文件夹
- .PHONY:output
- output:
- mkdir output
- cp -rf *.h output
- cp libmymath.a output
复制代码- # ubuntu 20.04 实机演示
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ ls -l
- total 24
- -rw-rw-r-- 1 ubuntu ubuntu 61 Apr 20 20:13 add.c
- -rw-rw-r-- 1 ubuntu ubuntu 65 Apr 20 20:13 add.h
- -rw-rw-r-- 1 ubuntu ubuntu 243 Apr 20 20:33 main.c
- -rw-rw-r-- 1 ubuntu ubuntu 188 Apr 21 13:38 Makefile
- -rw-rw-r-- 1 ubuntu ubuntu 61 Apr 20 20:15 sub.c
- -rw-rw-r-- 1 ubuntu ubuntu 65 Apr 20 20:14 sub.h
- # 构建静态库
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ make
- gcc -c sub.c
- gcc -c add.c
- ar -rc libmymath.a sub.o add.o
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ ls -l
- total 36
- -rw-rw-r-- 1 ubuntu ubuntu 61 Apr 20 20:13 add.c
- -rw-rw-r-- 1 ubuntu ubuntu 65 Apr 20 20:13 add.h
- -rw-rw-r-- 1 ubuntu ubuntu 1376 Apr 21 13:43 add.o
- -rw-rw-r-- 1 ubuntu ubuntu 2960 Apr 21 13:43 libmymath.a
- -rw-rw-r-- 1 ubuntu ubuntu 243 Apr 20 20:33 main.c
- -rw-rw-r-- 1 ubuntu ubuntu 188 Apr 21 13:38 Makefile
- -rw-rw-r-- 1 ubuntu ubuntu 61 Apr 20 20:15 sub.c
- -rw-rw-r-- 1 ubuntu ubuntu 65 Apr 20 20:14 sub.h
- -rw-rw-r-- 1 ubuntu ubuntu 1376 Apr 21 13:43 sub.o
- # 打包
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ make output
- mkdir output
- cp -rf *.h output
- cp libmymath.a output
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ ls -l
- total 40
- -rw-rw-r-- 1 ubuntu ubuntu 61 Apr 20 20:13 add.c
- -rw-rw-r-- 1 ubuntu ubuntu 65 Apr 20 20:13 add.h
- -rw-rw-r-- 1 ubuntu ubuntu 1376 Apr 21 13:43 add.o
- -rw-rw-r-- 1 ubuntu ubuntu 2960 Apr 21 13:43 libmymath.a
- -rw-rw-r-- 1 ubuntu ubuntu 243 Apr 20 20:33 main.c
- -rw-rw-r-- 1 ubuntu ubuntu 188 Apr 21 13:38 Makefile
- drwxrwxr-x 2 ubuntu ubuntu 4096 Apr 21 13:43 output
- -rw-rw-r-- 1 ubuntu ubuntu 61 Apr 20 20:15 sub.c
- -rw-rw-r-- 1 ubuntu ubuntu 65 Apr 20 20:14 sub.h
- -rw-rw-r-- 1 ubuntu ubuntu 1376 Apr 21 13:43 sub.o
- # 查看 output
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ tree output/
- output/
- ├── add.h
- ├── libmymath.a
- └── sub.h
- 0 directories, 3 files
复制代码 2.3 利用静态库
我们已经将静态库以及相关头文件打包到了 output 文件夹,如今我们新建一个 TestStaticLib 文件夹进行测试:
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ mkdir TestStaticLib
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ ls -l
- total 44
- -rw-rw-r-- 1 ubuntu ubuntu 61 Apr 20 20:13 add.c
- -rw-rw-r-- 1 ubuntu ubuntu 65 Apr 20 20:13 add.h
- -rw-rw-r-- 1 ubuntu ubuntu 1376 Apr 21 13:43 add.o
- -rw-rw-r-- 1 ubuntu ubuntu 2960 Apr 21 13:43 libmymath.a
- -rw-rw-r-- 1 ubuntu ubuntu 243 Apr 20 20:33 main.c
- -rw-rw-r-- 1 ubuntu ubuntu 188 Apr 21 13:38 Makefile
- drwxrwxr-x 2 ubuntu ubuntu 4096 Apr 21 13:43 output
- -rw-rw-r-- 1 ubuntu ubuntu 61 Apr 20 20:15 sub.c
- -rw-rw-r-- 1 ubuntu ubuntu 65 Apr 20 20:14 sub.h
- -rw-rw-r-- 1 ubuntu ubuntu 1376 Apr 21 13:43 sub.o
- drwxrwxr-x 2 ubuntu ubuntu 4096 Apr 21 13:56 TestStaticLib
- # 将 output 移动到 TestStaticLib 文件夹,并改名为 StaticLib
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ mv output TestStaticLib/
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ cd TestStaticLib/
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20/TestStaticLib$ mv output StaticLib
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20/TestStaticLib$ ls
- StaticLib
复制代码 在 TestStaticLib 目录中新建测试文件:
- // ---------- test.c ----------
- #include <stdio.h>
- #include "add.h"
- #include "sub.h"
- int main()
- {
- int a = 10;
- int b = 20;
- printf("add(%d, %d) = %d\n", a, b, add(a, b));
- a = 100;
- b = 20;
- printf("sub(%d, %d) = %d\n", a, b, sub(a, b));
- return 0;
- }
复制代码 利用 Makefile 进行自动化编译:
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20/TestStaticLib$ ls
- StaticLib test.c
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20/TestStaticLib$ touch Makefile
- # 编写 Makefile
- ubuntu:~/Linux/test_4_20/TestStaticLib$ vim Makefile
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20/TestStaticLib$ cat Makefile
- test:test.c
- gcc -o $@ $^ -I ./StaticLib -L ./StaticLib -l mymath
- # -I:指定头文件所在目录
- # -L:指定静态库所在目录
- # -l:指定库名
- .PHONY:clean
- clean:
- rm -f test
复制代码 测试:
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20/TestStaticLib$ make
- gcc -o test test.c -I ./StaticLib -L ./StaticLib -l mymath
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20/TestStaticLib$ ls -l
- total 32
- -rw-rw-r-- 1 ubuntu ubuntu 99 Apr 21 14:21 Makefile
- drwxrwxr-x 2 ubuntu ubuntu 4096 Apr 21 13:43 StaticLib
- -rwxrwxr-x 1 ubuntu ubuntu 16816 Apr 21 14:21 test
- -rw-rw-r-- 1 ubuntu ubuntu 243 Apr 21 14:13 test.c
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20/TestStaticLib$ ./test
- add(10, 20) = 30
- sub(100, 20) = 80
复制代码 3. 库搜刮路径
- 从左到右搜刮 -L 指定的目录
- 由环境变量指定的目录(LIBRARY_PATH)
- 由体系指定的目录
- / user / lib
- / user / local / lib
下面测试利用动态库时,需要我们在库搜刮路径中手动添加动态库!
4. 手动创建并测试动态库
4.1 生成动态库
利用下令手动生成静态库:
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ ls
- add.c add.h main.c sub.c sub.h
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ gcc -fPIC -c sub.c add.c
- # fPIC:产生位置无关码(position independent code)
- # 编译产生的代码没有绝对位置,只有相对位置,从而可以在任意地方调用生成的动态库
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ ls
- add.c add.h add.o main.c sub.c sub.h sub.o
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ gcc -shared -o libmymath.so *.o
- # shared:表示生成共享库格式
- # 库名规则:lib*.so
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ ls
- add.c add.h add.o libmymath.so main.c sub.c sub.h sub.o
复制代码 4.2 打包动态库
将 动态库(.so)和 头文件(.h)打包到一个文件夹:
- # ---------- Makefile ----------
- libmymath.so:add.o sub.o
- gcc -shared -o $@ $^
- %.o:%.c
- gcc -fPIC -c $<
- .PHONY:clean
- clean:
- rm -rf libmymath.so *.o DynamicLib
- .PHONY:DynamicLib
- DynamicLib:
- mkdir DynamicLib
- cp *.h DynamicLib
- cp libmymath.so DynamicLib
复制代码- # ubuntu 20.04 实机演示
- # 构建动态库
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ ls
- add.c add.h main.c Makefile sub.c sub.h TestStaticLib
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ make
- gcc -fPIC -c add.c
- gcc -fPIC -c sub.c
- gcc -shared -o libmymath.so add.o sub.o
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ ls
- add.c add.o main.c sub.c sub.o
- add.h libmymath.so Makefile sub.h TestStaticLib
- # 打包
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ make DynamicLib
- mkdir DynamicLib
- cp *.h DynamicLib
- cp libmymath.so DynamicLib
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ ls
- add.c add.o libmymath.so Makefile sub.h TestStaticLib
- add.h DynamicLib main.c sub.c sub.o
- # 查看打包文件
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ tree DynamicLib/
- DynamicLib/
- ├── add.h
- ├── libmymath.so
- └── sub.h
- 0 directories, 3 files
复制代码 4.3 利用动态库
故技重施,创建 TestDynamicLib 文件夹进行测试:
- # 把上面的动态库拿过来,并创建 Makefile 和 test.c
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ tree TestDynamicLib/
- TestDynamicLib/
- ├── DynamicLib
- │ ├── add.h
- │ ├── libmymath.so
- │ └── sub.h
- ├── Makefile
- └── test.c
- # test.c 与静态库保持一致
- # Makefile
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ cat TestDynamicLib/Makefile
- test:test.c
- gcc -o $@ $^ -I ./DynamicLib -L ./DynamicLib -l mymath
- .PHONY:clean
- clean:
- rm -f test
复制代码 直接编译试试?
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20$ cd TestDynamicLib/
- # 编译
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20/TestDynamicLib$ make
- gcc -o test test.c -I ./DynamicLib -L ./DynamicLib -l mymath
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20/TestDynamicLib$ ls
- DynamicLib Makefile test test.c
- # 运行
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20/TestDynamicLib$ ./test
- ./test: error while loading shared libraries: libmymath.so: cannot open shared object file: No such file or directory
复制代码 发现报错了,体系找不到我们的动态库,为什么?
上面我们提到过库搜刮路径,我们只是在编译时指定了路径,只有编译器知道动态库的位置,编译完成后就没有人知道去那里找动态库了!所以可实行程序是找不到动态库的!
那为什么静态库没事呢?因为静态库是直接把库链接到可实行文件中,编译完成后把静态库删掉都不会影响可实行文件。
但动态库不一样,程序每次实行都要去磁盘上搜刮动态库的位置,然后链接,由于我们并没有指定动态库的位置,所以找不到!
如何办理?
一个比力简单且没有副作用的方法是修改 LD_LIBRARY_PATH 环境变量,因为我们只是想测试,并不想真的把这个动态库添加到体系中,而环境变量在我们关掉 xshell 后就会重置,所以我们选择这种方法进行测试:
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20/TestDynamicLib$ pwd
- /home/ubuntu/Linux/test_4_20/TestDynamicLib
- # 修改环境变量
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20/TestDynamicLib$ export LD_LIBRARY_PATH=/home/ubuntu/Linux/test_4_20/TestDynamicLib/DynamicLib
- # 查看环境变量
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20/TestDynamicLib$ echo $LD_LIBRARY_PATH
- /home/ubuntu/Linux/test_4_20/TestDynamicLib/DynamicLib
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20/TestDynamicLib$ ls
- DynamicLib Makefile test test.c
- # 执行测试程序
- ubuntu@VM-20-5-ubuntu:~/Linux/test_4_20/TestDynamicLib$ ./test
- add(10, 20) = 30
- sub(100, 20) = 80
- # 测试成功
复制代码 5. 动静态库优先级
- 如果我们同时提供动态库和静态库,gcc 默认利用的是动态库;
- 如果我们非要静态链接,我们必须利用 static 选项;
- 如果我们只提供静态库,那我们的可实行程序也没办法,只能对该库进行静态链接,但是程序不肯定团体是静态链接的。
- 如果我们只提供动态库,默认只能动态链接,如果非要静态链接,会发生链接报错!
END
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |