在 Linux 开发时,我们经常会看到一些形如 xxx.so 的名称出现,其中 so 是 Shared Object 的缩写,即可以共享的目标文件,也就是我们所称为的动态链接库,和在 Windows 下大家玩游戏时遇到的 xxx.dll 错误中的文件是一个类型的。

面试中经常会问到以下问题:
  • 怎么创建一个动态库?
  • 动态库文件的后缀名是什么?
  • 怎么使用一个动态库?
  • 动态库的命名规范?
  • 系统默认的动态库的查找路径?
  • 动态库显示连接所使用的系统库是什么?

一、什么是库

库是写好的现有的,成熟的,可以复用的代码。现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。
库有两种:
静态库(.a、.lib)
动态库(.so、.dll)
在一个程序的编译过程中,分为以下几个步骤:预处理,编译,汇编,链接。本文中讨论的链接库就是针对最后一个步骤「链接」而言的。

动态库和静态库的区别

左图为静态链接库,右图为动态链接库

对于静态链接库而言在链接阶段,会将汇编生成的「目标文件.o」与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接:
  • 静态链接库对函数库的链接是放在编译时期完成的。程序在运行时与函数库就没有了任何的联系。
  • 它比较浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。
  • 静态库对程序的更新和发布也会带来麻烦。如果静态库更新了,所有使用它的应用程序都需要重新编译、部署、发布给用户。
静态链接可以理解为最后生成了一个「单文件免安装绿色版」的程序,优点在于移植的时候只需要移动这一个文件,缺点在于文件体积非常大,为了解决这样的问题,就有了动态链接库。动态链接库在程序编译时并不会被连接到目标代码中,而是在程序运行时才被载入。
  • 不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,可以实现进程之间的资源共享。(因此动态库也称为共享库)规避了空间浪费问题。
  • 动态库在程序运行时才被载入,也解决了静态库对程序的更新、部署和发布带来的麻烦。用户只需要更新动态库即可将一些程序升级变得简单,增量更新。
动态库连接到系统空间,如果多个程序连接了同一个库,那么只需要一份,优点在于编译程序的时候不会将对应的库文件全部打包在生成的程序中,而是保留了到对应库的链接,缺点就是移植的时候如果只移动了对应的程序没有安装相关的库的话,就会看到类似以下喜闻乐见的结果了。

在 Linux 下一个动态库有y三个不同名字的文件组成:

  • soname 文件
    lib + 链接库名字 + .so + .版本号
  • real name 文件
    lib + 链接库名字 + .so + .版本号.次版本号.发行号
  • linker name 文件
    lib + 链接库名字 + .so

二、创建一个动态库

有了上面关于库的一些基础知识之后,我们可以开始尝试创建一个动态库来供程序使用了。

比如我们有一个求最大值的函数 max(int a,int b,int c) ,放在文件 max.c 中文件内容如下:

int max(int a, int b, int c)
{int max = ( a < b ) ? b : a;return ( ( max < c ) ? c : max );
}

可以通过:

gcc -fPIC -shared -o libmax.so max.c
  • 将其编译为共享库,-fPIC 是编译选项,PIC 是 Position Independent Code 的缩写,表示要生成位置无关的代码,这是动态库需要的特性;
  • -shared 是链接选项,告诉gcc生成动态库而不是可执行文件。
  • 为了让用户知道我们的动态库中有哪些接口可用,我们需要编写对应的头文件,比如可以写一个 max.h :
#ifndef __MAX_H__
#define __MAX_H__int max(int a, int b, int c);#endif
设置一个驱动函数来测试我们编写的动态库:
#include <stdio.h>
#include "max.h"int main(int argc, char *argv[])
{int a = 12, b = -2, c = 120;printf("The max value of 12, -2 and 120 is %d.\n", max(a, b, c));return 0;
}
通过 gcc test.c -L. -lmax 来生成 a.out,其中-lmax表示要链接 libmax.so,-L. 表示搜索要链接的库文件时包含当前路径。

同一目录下同时存在同名的动态库和静态库,比如 libmax.so 和 libmax.a 都在当前路径下,则gcc会优先链接动态库。

但是这样直接运行的话,会出现一个错误:

./a.out: error while loading shared libraries: libmax.so: cannot open shared object file: No such file or directory
由于 Linux 是通过/etc/ld.so.cache文件搜寻要链接的动态库的,而/etc/ld.so.cache是 ldconfig 程序读取/etc/ld.so.conf文件生成的,本次使用的动态库libmax.so并不在对应的目录下,就会导致程序无法找到对应的动态链接库,这样我们的解决方法有二:
  • 如果仅仅是本地使用,可以在编译后指定一个环境变量:LD_LIBRARY_PATH=. ./a.out ,这样程序会在本地寻找
    如果需要在系统层面共享这个库,可以把 libmax.so 所在的路径添加到 /etc/ld.so.conf 中,再以

  • root 权限运行 ldconfig 程序,更新 /etc/ld.so.cache
    具体采用的方法因使用场景而异,如果仅仅是测试用途的话,可以直接使用添加环境变量的方式解决。

小结

动态链接库是各个系统中的一个重要的组成部分且在 Linux 开发相关领域中尤为重要,也是一个面试的高频考点,除了动态链接库以外,还有以下相关知识也是高频考点,在面试前一定要准备好:
Linux 下 make 与 makefile。用什么参数指定 makefile 文件?什么是默认的makefile 文件?
Linux 静态库的使用,怎么创建一个静态库?怎么使用一个静态库?静态库文件的后缀名是什么?静态库的命名规范?

link

Linux 下的动态链接库问题相关推荐

  1. Linux下生成动态链接库是否必须使用 -fPIC 的问题

    From: http://www.linuxidc.com/Linux/2011-06/37268.htm 在 Linux 下制作动态链接库,"标准" 的做法是编译成位置无关代码( ...

  2. 在linux下编写动态链接库的步骤: g++ -lc

    引用自http://blog.csdn.net/lwhsyit/article/details/2828306 类似Windows系统中的动态链接库,Linux中也有相应的共享库用以支持代码的复用.W ...

  3. Linux下HOOK动态链接库中API的方法

    2012年,我写了一篇介绍Windows系统下Ring3层API的hook方案--<一种注册表沙箱的思路.实现--Hook Nt函数>,其在底层使用了微软的Detours库.5年后,我又遇 ...

  4. linux运行dll文件命令,linux下的动态链接库(DLL)

    一.公约 1. 库的命名习惯 一个linux DLL 有三个不同名字的文件组成 soname 文件 lib + 链接库名字 + .so + .版本号 每当链接库接口改变时都递增版本号.soname 文 ...

  5. linux下添加动态链接库路径的方法

    Linux共享库路径配置 Linux下找不到共享库文件的典型现象为明明已经安装某个软包(如libnet,MySQL),编译连接可以正常进行,但是在运行时出现如"error while loa ...

  6. linux下的动态链接库和静态链接库到底是个什么鬼?(一)静态链接库的编译与使用...

    知识不等于技术,这句话真的是越工作的时间长越深有体会,学习到的知识只有不断的实践,才成真正在自已的心里扎下根,成为自身的一部分,所以无论如何,我希望我的博客可以一直写下去,慢慢的沉淀,终会有回报,无聊 ...

  7. Linux下的静态链接库和动态链接库编程

    Linux下的静态链接库和动态链接库编程 参考: Linux下的静态链接库和动态链接库编程 - Histring - 博客园 Mac下静态库和动态库的创建和使用_C/C++_vincent2610的专 ...

  8. 《LINUX下动态链接库的创建与应用》

    大家都知道,在windows系统中有很多的动态链接库(以.dll为后缀的文档,dll即dynamic link library).这种动态链接库,和静态函数库不同,他里面的函数并不是执行程式本身的一部 ...

  9. 【ARM-Linux开发】linux下Eclipse进行C编程时动态链接库的生成和使用

    linux下Eclipse进行C编程时动态链接库的生成和使用 引用 http://linux.chinaitlab.com/soft/864157.html 欢迎进入Linux社区论坛,与200万技术 ...

最新文章

  1. Chrome之排序问题
  2. 区块链如何应用于保险行业
  3. STC单片机程序下载失败总结
  4. 收集一些非常实用的Linux命令
  5. [SpringBoot2]Thymeleaf
  6. java线程同步——竞争条件的荔枝+锁对象
  7. 【C++模板】特化与偏特化 template [partial] specialization
  8. mysql更新写入数据_七、MySQL插入、更新与删除数据
  9. 设计模式之美:Strategy(策略) -未经作者同意的转载
  10. Visio ——一款能让你画图“走捷径”的软件
  11. 银河麒麟V10系统安装U盘制作
  12. 家庭局域网_玩转Windows 10家庭组,轻松共享局域网资源,人人都可以做到
  13. 做PPT只会直接插入图片?这样处理图片,让PPT的颜值瞬间提升几倍
  14. php session fixation,Session Fixation 攻防实战
  15. 信息收集--子域名查询
  16. 【不忘初心】Win10_20H2_2009_19042.572_X64_六合一_[纯净精简版](2020.10.29)
  17. 如何选择GPS定位器
  18. dnf用计算机算比例,DNF比例计算查询
  19. 实现isPrime()函数,参数为整数,要有异常处理。如果整数是质数,返回True,否则返回False
  20. 数禾科技:科技加持,让普惠“信用”服务触手可及

热门文章

  1. 一个简单的第三方CNN自编码matlab工具箱
  2. 头插法和尾插法分别建立链表(复制即可应用)
  3. [雪峰磁针石博客]计算机视觉opcencv工具深度学习快速实战1人脸识别
  4. Spring4+SpringMVC+MyBatis整合思路
  5. [20181015]为什么是3秒.txt
  6. msm(CentOS 6)及jvm虚拟机性能监控(04)_recv
  7. 把java 工程转为 maven 工程
  8. YUDBModel【绿色插件】-对象序列化、反序列化、对象一键增删改查
  9. VLC for android 编译错误
  10. Filter的详解与配置应用