Ubuntu下有两种库:动态库和静态库(共享库)
库的本质是可执行的二进制码,库的作用就是复用。静态库在链接期间把库文件加到主程序中,而动态库则是运行时再加载进去。
二者的不同点在于代码被载入的时刻不同。
静态库的代码在编译过程中已经被载入可执行程序,因此体积比较大。
动态库(共享库)的代码在可执行程序运行时才载入内存,在编译过程中仅简单的引用,因此代码体积比较小。
不同的应用程序如果调用相同的库,那么在内存中只需要有一份该动态库(共享库)的实例。
静态库和动态库的最大区别,静态情况下,把库直接加载到程序中,而动态库链接的时候,它只是保留接口,将动态库与程序代码独立,这样就可以提高代码的可复用度,和降低程序的耦合度。
静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。
动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。
1、gcc工作流程
2、gcc常用参数
-E 预处理,不会编译、汇编和链接
-S 编译,不会汇编和链接
-c 编译和汇编,但不会链接
-o 输出可执行文件
静态库
1、静态库的命名格式
lib + 库的名字 + .a
例:libMyTest.a (MyTest为静态库的名字)
链接期间会把库文件一起打包至可执行文件;生成可执行文件后,可以脱离环境执行;一起打包造成资源浪费
2、静态库作用分析
在项目开发过程中,经常出现优秀代码重用现象,又或者提供给第三方功能模块却又不想让其看到源代码,这些时候,通常的做法是将代码封装成库或者框架,生成的静态库要和头文件同时发布。
优点:寻址方便,速度快
库在链接时被打包到可执行文件中,直接发布可执行程序即可以使用
缺点:静态库的代码被加载到可执行程序中,因此体积过大
如果静态库的函数发生改变,必须重新编译可执行程序
3、静态库的制作与使用
测试代码的目录结构如上图所示,include中存放的是头文件,libs中存放的是静态(动态)库,res中存放的是源代码,main.c是发布代码。
第一步:把res目录下的.c文件生成.o文件:
gcc *.c -c
第二步:把.o打包成静态库,并移动到libs目录:
ar rcs libMyTest.a *.o 将所有.o文件打包为静态库,r将文件插入静态库中,c创建静态库,不管库是否存在,s写入一个目标文件索引到库中,或者更新一个存在的目标文件索引。
mv libMyTest.a ../lib 将静态库文件放置lib文件夹下
nm libMyTest.a 查看库中包含的函数等信息
第三步:在主目录下链接生成可执行文件
gcc main.c -Iinclude -Llibs -lMyTest -o app
该可执行文件是可以脱离环境执行的,把其移到桌面,执行正常。
动态库(共享库)
1、动态库的命名格式
lib + 库的名字 + .so
例:libMyTest.so (MyTest为动态库的名字)
2、动态库作用分析
共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小。
优点:
节省内存
易于更新,不用重新编译可执行程序,运行时自动加载
缺点:
延时绑定,速度略慢
动态库存在是为了解决静态库的某些问题:静态库和主程序一起打包成可执行文件,造成程序包变大;静态库在更新时,需要重新编译生成可执行文件,而动态库是程序运行时加载的,只需把动态库修改则可。
3、动态库的制作与使用
测试代码的目录结构与静态库相同。
第一步:在res目录下,生成和位置无关的代码:
gcc -fPIC *.c -c 参数-fPIC表示生成与位置无关代码
第二步:创建动态库
gcc -shared -o libadd.so *.o 参数:-shared 制作动态库 -o:重命名生成的新文件
mv libMyTest.so ../lib
第三步:使用动态库,在主目录下生成可执行文件:
gcc main.c -Iinclude -Llibs -ladd -o app
尝试执行该文件,发现找不到.so
证明动态库和静态库的链接是不一样的。那么如何运行该程序呢?
使用命令ldd app可以查看当前的链接库情况;
链接动态库有4种方法:
第一种方法:
把动态库路径加到环境变量:添加完后,执行成功
export LD_LIBRARY_PATH=//动态库的绝对路径(只能起到临时作用,关闭终端后失效)
LD_LIBRARY_PATH : 指定查找共享库(动态链接库)时除了默认路径之外的其他路径,该路径在默认路径之前查找
第二种方法:
打开home目录下的.bashrc文件,将上述命令写入,即上面所说的动态库的绝对路径,保存后重启终端生效(永久)
第三种方法:
直接将动态库拷贝到user/lib的系统目录下(强烈不推荐!!)
第四种方法:
配置动态库链接器的配置文件:
将libmytest.so所在绝对路径追加入到/etc/ld.so.conf文件,使用sudo ldconfig -v 更新。