通过本文的学习,了解gcc创建静态库、动态库的详细过程。
前言
一、浅谈静态库和动态库
1、什么是静态库
2、什么是动态库
3、二者的区别
二、用 gcc 生成 .a 静态库和 .so 动态库
1、编辑生成例子程序 hello.h、hello.c 和 main.c
2 输入代码
3、将 hello.c 编译成.o 文件
4、由.o文件创建静态库
5、在程序中使用静态库
6、由.o文件创建动态库文件
7、在程序中使用动态库
8、拓展:当静态库和动态库同名时,gcc 命令会使用哪个库文件呢?
三、实例演训
1、作业要求
2、实操过程
2.1、编辑主程序文件和子程序文件
2.2、将.c文件编译成.o文件
2.3、将目标文件用 ar工具生成 .a 静态库文件,
2.4、将目标文件用 ar工具生成 .so 动态库文件,
2.5、静态库与动态库文件大小比较
总结
一、静态库和动态库
1.库的含义
库就是已经写好的,成熟的,可以直接使用的代码,通常情况下,将已经写好的一些公用函数制作成函数库,提供给使用者和其他程序反复使用。
从本质上来说,库是一种可执行代码的二进制形式,可被操作系统载入内存执行。
库分为静态库和动态库两种。
2.静态库(.a)
静态库:在链接步骤中,连接器将从库文件取得所需的代码,复制到生成的可执行文件中的这种库。
静态库的特点是可执行文件中包含了库代码的一份完整拷贝, 使得程序在运行时与函数库再无联系,移植方便。
静态库的缺点是被多次使用就会有多份冗余拷贝,使得空间和资源被浪费。并且,即使仅当静态库的某一小部分获得了更新,那么所有的程序都会被重新下载。
3.动态库(.so)
动态库:在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。
动态库的优点是解决了静态库对空间和资源造成的浪费,也使得当库更新时,用户仅需更新改动的部分。
4.静态库和动态库的区别
静态库在程序的链接阶段被复制到了程序中,和程序运行的时候没有关系。
动态库在链接阶段没有被复制到程序中,而是程序在运行时由系统动态加载到内存中供程序调用。使用动态库的优点是系统只需载入一次动态库,不同的程序可以得到内存中相同的动态库的副本,因此节省了很多内存。
二、 用 gcc 生成 .a 静态库和 .so 动态库
(1)创建三个文件hello.h、hello.c、main.c
(2)输入代码
hello.h
hello.c
main.h
(注:
hello.c是函数库的源程序,其中包含公用函数 hello,该函数将在屏幕上输出"HelloXXX!"。hello.h为该函数库的头文件。main.c为测试库文件的主程序,
在主程序中调用了公用函数 hello。)
(3)将hello.c编译成.o文件
无论静态库,还是动态库,都是由.o 文件创建的,因此需先将源程序hello.c通过gcc先编译成 .o文件
(4)由 .o文件创建静态库
(5)在程序中使用静态库
(6)验证静态库是否生成成功
(1)、打开文件
(2)、删除静态库文件试试公用函数 hello 是否真的连接到
7、由.o 文件创建动态库文件
动态库文件名命名规范和静态库文件名命名规范类似,也是在动态库名增加前缀 lib,但其 文件扩展名为.so
(1)、构建动态库并观察
创建动态库的工具:gcc
动态库文件命名规范:以lib作为前缀,是.so文件
shared:表示指定生成动态链接库,不可省略
-fPIC:表示编译为位置独立的代码,不可省略;命令中的-o一定不能够被省略
-shared:该选项指定生成动态连接库
-fPIC:表示编译为位置独立的代码
生成一个 .so的文件
(8)在程序中使用动态库
(1)、输入命令gcc main.c libmyhello.so -o hello 或 gcc -o hello main.c -L. -lmyhello
发现在显示文件时没有问题,但在./hello 会提示出错,因为虽然连接时用的是当前目录的动态库,但是运行时,是到 /usr/lib 中找库文件的,将文件 libmyhello.so 复制到目录/usr/lib 中就 OK 了
发现无权限,此时我们可以用sudo命令解决
8、拓展:当静态库和动态库同名时,gcc 命令会使用哪个库文件呢?
- 先删除除.c 和.h 外的所有文件,恢复成刚刚编辑完举例程序状态:
- 并运用“ls”命令进行查看:
rm -f hello hello.o /usr/lib/libmyhello.so
ls
(2)、再来创建静态库文件 libmyhello.a 和动态库文件 libmyhello.so
gcc -c hello.c
ar -cr libmyhello.a hello.o
gcc -shared -fPIC -o libmyhello.so hello.o
ls
(3)、运行 gcc 命令来使用函数库 myhello 生成目 标文件 hello,并运行程序 hello
gcc -o hello main.c -L. -lmyhello
三、作业实操一
1、构建新文件夹,编写程序
A1.c
A2.c
A.h
test.c
程序构建结果:
2、静态库.a 文件的生成与使用
(1)、生成目标文件
gcc -c A1.c A2.c
操作结果:
(2)、生成静态库.a 文件
ar crv libafile.a A1.o A2.o
代码运行结果:
3)、使用.a 库文件,创建可执行程序
若采用此种方式,需保证生成的.a 文件与.c 文件保 存在同一目录下,即都在当前目录下
gcc -o test test.c libafile.a
./test
代码运行结果:
3、共享库.so 文件的生成与使用
(1)、生成目标文件(xxx.o)
此处生成.o 文件必须添加"-fpic"(小模式,代码少),否则在生成.so 文件时会出错
(2)、生成共享库.so 文件
gcc -shared *.o -o libsofile.s
代码运行结果:
(3)、使用.so 库文件,创建可执行程序
代码运行结果:
发现出现错误,原因是之前运行代码时,输入错误,改正过后的结果为:
出现新的错误,通过ldd test,来查看链接问题
发现确实是找不到对应的.so 文件。
解决办法:这是由于 linux 自身系统设定的相应的设置的原因,即其只在/lib and /usr/lib 下搜索对应 的.so 文件,故需将对应 so 文件拷贝到对应路径。
sudo cp libsofile.so /usr/lib
解决问题过后代码运行结果:
1、程序编写
程序一:lcx.c
程序二:lcy.c
程序三:lc.h
程序四:main.c
代码运行结果:
2、用gcc分别编译为3个.o 目标文件
gcc -c lcx.c lcy.c main.c
3、将目标文件生成静态.a文件
ar crv liblc.a lcx.o lcy.o
gcc -o main main.o liblc.a
注:在进行文件链接时,务必要注意需要用之前生成的.o文件,不然的话会报错
4、观察文件大小
在linux下使用“ls -l”或者“ls -al”或者“ll”命令查看文件及目录详情
观察结果:
5、将目标文件生成动态库.so文件并与main函数链接
gcc -shared -fPIC -o liblc.so lcx.o lcy.o
gcc -o main main.o liblc.so
运行结果:
6、记录大小并与静态库对比
将二者进行对比,发现静态库较动态库而言,占用空间更少。
四、实验总结
通过上述的三个程序基于Ubuntu中gcc生成静态库和动态库的练习,让我进一步的明白了静态库与动态库二者之间的差别,同时我也基本上能够熟练的生成静态库和动态库。其中,在本次实验过程中我遇到了许多问题,但通过自己不断的查阅资料以及向网上前辈的借鉴,我接触并学会了许多关于linux的代码操作。同时,本次试验过后,我明白了可执行文件是通过编译链接获取得到的,利用gcc等相关工具将源码编译得到.o文件,然后就是将.o文件链接得到可执行文件。同时也期待大家能够积极留言,指出我存在的问题,谢谢!