Linux的静态库和动态库

2023-11-19

库从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行。库分静态库和动态库两种。 

静态库和动态库的区别

1. 静态函数库

    这类库的名字一般是libxxx.a;利用静态函数库编译成的文件比较大,因为整个 函数库的所有数据都会被整合进目标代码中,他的优点就显而易见了,即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进去了。当然这也会成为他的缺点,因为如果静态函数库改变了,那么你的程序必须重新编译。

2. 动态函数库

    这类库的名字一般是libxxx.so;相对于静态函数库,动态函数库在编译的时候 并没有被编译进目标代码中,你的程序执行到相关函数时才调用该函数库里的相应函数,因此动态函数库所产生的可执行文件比较小。由于函数库没有被整合进你的程序,而是程序运行时动态的申请并调用,所以程序的运行环境中必须提供相应的库。动态函数库的改变并不影响你的程序,所以动态函数库的升级比较方便。 
linux系统有几个重要的目录存放相应的函数库,如/lib /usr/lib。

静态库的使用

静态库的操作工具:gcc和ar 命令。 

编写及使用静态库 

(1)设计库源码 pr1.c 和 pr2.c 

[root@billstone make_lib]# cat pr1.c 

void print1() 

                printf("This is the first lib src!\n"); 

[root@billstone make_lib]# cat pr2.c 

void print2() 

                printf("This is the second src lib!\n"); 

       (2)  编译.c 文件 

[bill@billstone make_lib]$ cc -O -c pr1.c pr2.c 

[bill@billstone make_lib]$ ls -l pr*.o 

-rw-rw-r--        1 bill          bill                    804    4 月  15 11:11 pr1.o 

-rw-rw-r--        1 bill          bill                    804    4 月  15 11:11 pr2.o 

(3)  链接静态库 

    为了在编译程序中正确找到库文件,静态库必须按照 lib[name].a 的规则命名,如下例中[name]=pr. 

[bill@billstone make_lib]$ ar -rsv libpr.a pr1.o pr2.o 

a - pr1.o 

a - pr2.o 

[bill@billstone make_lib]$ ls -l *.a 

-rw-rw-r--        1 bill          bill                  1822    4 月  15 11:12 libpr.a 

[bill@billstone make_lib]$ ar -t libpr.a 

pr1.o 

pr2.o 

(4)  调用库函数代码 main.c 

[bill@billstone make_lib]$ cat main.c 

int main() 

                print1(); 

                print2(); 

                return 0; 

(5)  编译链接选项 

    -L 及-l 参数放在后面.其中,-L 加载库文件路径,-l 指明库文件名字. 

[bill@billstone make_lib]$ gcc -o main main.c -L./ -lpr 

[bill@billstone make_lib]$ ls -l main* 

-rwxrwxr-x        1 bill          bill                11805    4 月  15 11:17 main 

-rw-rw-r--        1 bill          bill                      50    4 月  15 11:15 main.c 

(6)执行目标程序 

[bill@billstone make_lib]$ ./main 

This is the first lib src! 

This is the second src lib! 

[bill@billstone make_lib]$ 

动态库的使用

编写动态库 

(1)设计库代码 

[bill@billstone make_lib]$ cat pr1.c 

int p = 2; 

void print(){ 

                printf("This is the first dll src!\n"); 

[bill@billstone make_lib]$   

(2)生成动态库 

[bill@billstone make_lib]$ gcc -O -fpic -shared -o dl.so pr1.c 

[bill@billstone make_lib]$ ls -l *.so 

-rwxrwxr-x        1 bill          bill                  6592    4 月  15 15:19 dl.so 

[bill@billstone make_lib]$ 

动态库的隐式调用 

  在编译调用库函数代码时指明动态库的位置及名字,  看下面实例 

[bill@billstone make_lib]$ cat main.c 

int main() 

                print(); 

                return 0; 

[bill@billstone make_lib]$ gcc -o tdl main.c ./dl.so 

[bill@billstone make_lib]$ ./tdl 

This is the first dll src! 

[bill@billstone make_lib]$ 

当动态库的位置活名字发生改变时,  程序将无法正常运行;  而动态库取代静态库的好处之一则是通过更新动态库而随时升级库的内容. 

动态库的显式调用 

  显式调用动态库需要四个函数的支持,  函数 dlopen 打开动态库,  函数 dlsym 获取动态库中对象基址,  函数 dlerror 获取显式动态库操作中的错误信息,  函数 doclose 关闭动态库.

[bill@billstone make_lib]$ cat main.c 

#include <dlfcn.h> 

int main() 

                void *pHandle; 

                void (*pFunc)();                                                    //  指向函数的指针 

                int *p; 

                pHandle = dlopen("./d1.so", RTLD_NOW);                  //  打开动态库 

                if(!pHandle){ 

                                printf("Can't find d1.so \n"); 

                                exit(1); 

                } 

                pFunc = (void (*)())dlsym(pHandle, "print");                //  获取库函数 print 的地址 

                if(pFunc) 

                                pFunc(); 

                else 

                                printf("Can't find function print\n"); 

                p = (int *)dlsym(pHandle, "p");                                      //  获取库变量 p 的地址 

                if(p) 

                                printf("p = %d\n", *p); 

                else 

                                printf("Can't find int p\n"); 

                dlclose(pHandle);                                                                //  关闭动态库 

                return 0; 

[bill@billstone make_lib]$ gcc -o tds main.c –ld1 –L.

此时还不能立即./tds,因为在动态函数库使用时,会查找/usr/lib、/lib目录下的动态函数库,而此时我们生成的库不在里边。 这个时候有好几种方法可以让他成功运行: 最直接最简单的方法就是把libstr_out.so拉到/usr/lib或/lib中去。 还有一种方法 export LD_LIBRARY_PATH=$(pwd) 另外还可以在/etc/ld.so.conf文件里加入我们生成的库的目录,然后/sbin/ldconfig。 /etc/ld.so.conf是非常重要的一个目录,里面存放的是链接器和加载器搜索共享库时要检查的目录,默认是从/usr/lib /lib中读取的,所以想要顺利运行,我们也可以把我们库的目录加入到这个文件中并执行/sbin/ldconfig 。另外还有个文件需要了解/etc/ld.so.cache,里面保存了常用的动态函数库,且会先把他们加载到内存中,因为内存的访问速度远远大于硬盘的访问速度,这样可以提高软件加载动态函数库的速度了。

库依赖的查看

使用ldd命令来查看执行文件依赖于哪些库。

该命令用于判断某个可执行的 binary 档案含有什么动态函式库。
[root@test root]# ldd [-vdr] [filename]
参数说明:
--version  打印ldd的版本号
-v --verbose  打印所有信息,例如包括符号的版本信息
-d --data-relocs  执行符号重部署,并报告缺少的目标对象(只对ELF格式适用)
-r --function-relocs  对目标对象和函数执行重新部署,并报告缺少的目标对象和函数(只对ELF格式适用)
--help 用法信息。

如果命令行中给定的库名字包含'/',这个程序的libc5版本将使用它作为库名字;否则它将在标准位置搜索库。运行一个当前目录下的共享库,加前缀"./"。

动态库的命名惯例

共享库有三个文件名:real name , soname , linker name.

real name:真的库文件

soname:符号链接的名字,只包含共享库的主版本号,主版本号一致即可保证库函数的接口一致

linker name:仅在编译连接时使用,类型于windows的dll的lib

如:两个库 libMyDll.so.1.3 libMyDll.so.1.6 这两个都为real name, 其中libMyDll.so.1为soname,所以两个soname相同及两库必须兼容通用,linker name 必须如下生成

ln -s libMyDll.so.1.3 libMyDll.so



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux的静态库和动态库 的相关文章

  • Linux 内核使用的设备树文件 (dtb) 可视化工具? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找一个可以图形化表示Linux内核中使用的硬件设备树的工具 我正在尝试了解特定 Arm 芯片组
  • 任何退出 bash 脚本但不退出终端的方法

    当我使用exitshell 脚本中的命令 该脚本将终止终端 提示符 有什么方法可以终止脚本然后停留在终端中吗 我的剧本run sh预计通过直接获取或从另一个脚本获取来执行 编辑 更具体地说 有两个脚本run2 sh as run sh ec
  • 使用脚本检查 git 分支是否领先于另一个分支

    I have branch1 and branch2我想要某种 git branch1 isahead branch2 这将显示如果branch1已承诺branch2没有 也可能指定这些提交 我无法检查差异原因branch2 is在之前br
  • Vagrant 遇到问题 - “404 - 未找到”

    我正在尝试使用 Vagrant 制作一个 LAMP 盒子 有人告诉我它使用起来非常简单 我对网络和虚拟机完全陌生 对 Linux Ubuntu 的经验也很少 我目前已尝试按照官方文档页面上的教程进行操作 http docs vagrantu
  • 使用 ioctl 在 C++ 中以编程方式添加路由

    我编写了简单的 C 函数 添加了新路线 void addRoute int fd socket PF INET SOCK DGRAM IPPROTO IP struct rtentry route memset route 0 sizeof
  • GCC:分段错误和调试程序仅在优化时崩溃

    这是线程的后续内容 C 分段错误 也许 GDB 在骗我 https stackoverflow com questions 22828609 c segmentation fault and maybe gdb is lying to me
  • 更新Linux中的包含路径

    我的 my path to file 文件夹中有几个头文件 我知道如何将这些文件包含在新的 C 程序中 但每次我都需要在包含它之前输入头文件的完整路径 我可以在linux中设置一些路径变量 以便它自动查找头文件吗 您可以创建一个 makef
  • Bash:将字符串添加到文件末尾而不换行

    如何将字符串添加到文件末尾而不换行 例如 如果我使用 gt gt 它将添加到文件末尾并换行 cat list txt yourText1 root host 37 echo yourText2 gt gt list txt root hos
  • bash while 循环的布尔表达式中的 -lt 意味着什么?

    我猜测它代表小于基于输出 但是我在哪里可以找到有关此语法的文档 bin bash COUNTER 0 while COUNTER lt 10 do echo The counter is COUNTER let COUNTER COUNTE
  • 如何在 Linux 和 C 中使用文件作为互斥体?

    我有不同的进程同时访问 Linux 中的命名管道 并且我想让此访问互斥 我知道可以使用放置在共享内存区域中的互斥体来实现这一点 但作为一种家庭作业 我有一些限制 于是 我想到的是对文件使用锁定原语来实现互斥 我做了一些尝试 但无法使其发挥作
  • “git add”返回“致命:外部存储库”错误

    我刚刚进入 git 的奇妙世界 我必须提交我对程序所做的一系列更改 位于名为的目录中 var www myapp 我创建了一个新目录 home mylogin gitclone 从这个目录中 我做了一个git clone针对公共回购 我能够
  • 由于符号链接错误,无法在 Mac OSX 10.8.1 中安装 ruby​​-1.9.2

    首先 我尝试了常见的rvm安装 rvm安装1 9 2 但是 显示了以下错误 The provided compiler usr bin gcc is LLVM based it is not yet fully supported by r
  • 代码退出-1073741515 (0xc0000135)“未找到依赖的 dll”

    我正在尝试编写一个简单的程序 与 2019 年相比 Windows 10 64 位 调试 gt x64 遵循 将 Visual C 项目配置为面向 64 位平台 1 include
  • 为 Linux 编译 Objective-C 应用程序(API 覆盖范围)

    我可能在这里问一些奇怪的问题 但我不确定从哪里开始 问题是我正在考虑使用 Obj C 和 Foundation 类在 Mac 上编写一个命令行工具 但存在一个非常大的风险 那就是我希望能够为不同的 Linux 发行版编译它 以便将来作为服务
  • 与 glib-2.0 链接时,cygwin gcc 4.3 中的参数顺序很重要

    我正在尝试使用 cygwin 编译适用于 os x 和 linux 的代码 然而 我发现 gcc 的参数顺序给出了意想不到的结果 例如 以下情况会失败 gcc std gnu99 I usr include glib 2 0 I usr l
  • Python 3.4.3 subprocess.Popen 在没有管道的情况下获取命令的输出?

    我试图将命令的输出分配给变量 而不让命令认为它正在通过管道传输 原因是 如果正在通过管道传输 则相关命令会给出未格式化的文本作为输出 但如果从终端运行 则会给出颜色格式化的文本 我需要获取这种颜色格式的文本 到目前为止我已经尝试了一些事情
  • 如何在 Linux 上通过 FTP 递归下载文件夹 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 Locked 这个问题及其答案是locked help locked posts因为这个问题是题外话 但却具有历史意义 目前不接受新的答案
  • ctypes 加载 dll 时没有错误消息,但什么也没发生

    我尝试在ctypes中使用windll LoadLibrary将dll文件导入python 尽管没有任何错误消息 但头文件中列出的函数似乎都没有成功加载 我想知道是dll文件有问题 还是我错误地使用了windll LoadLibrary方法
  • gcc 没有小字符串优化吗?

    Most std string实现 包括 GCC 使用小字符串优化 例如 有一个answer https stackoverflow com a 21710033 2640636讨论这个 今天 我决定检查我编译的代码中的字符串在什么时候被移
  • SSH,运行进程然后忽略输出

    我有一个命令可以使用 SSH 并在 SSH 后运行脚本 该脚本运行一个二进制文件 脚本完成后 我可以输入任意键 本地终端将恢复到正常状态 但是 由于该进程仍在我通过 SSH 连接的计算机中运行 因此任何时候它都会登录到stdout我在本地终

随机推荐

  • checkbox样式改写

    div class checkbox font s div
  • js 微观任务、宏观任务、循环机制

    javascript是单线程语言 就是因为单线程的特性 就不得不提js中的同步和异步 同步和异步 所谓单线程 无非就是同步队列和异步队列 js代码是自上向下执行的 在主线程中立即执行的就是同步任务 比如简单的逻辑操作及函数 而异步任务不会立
  • 计算机网络--绪论

    一 计网的体系结构 1 概念和功能 2 组成和分类 3 标准化工作及相关组织 二 性能指标 1 速率 2 带宽 3 吞吐量 4 时延 5 时延带宽积 6 往返时间RTT利用率 7 利用率 三 分层结构 1 分层 四 OSI参考模型 1 OS
  • 随机数产生方法

    5 产生一定范围随机数的通用表示公式 要取得 a b 的随机整数 使用 rand b a a 要取得 a b 的随机整数 使用 rand b a 1 a 要取得 a b 的随机整数 使用 rand b a a 1 通用公式 a rand n
  • 【Vue】Vue基础自用笔记&Day02_①Vue过滤器②按键修饰符③自定义指令

    Vue基础 Day02 1 Vue过滤器 2 按键修饰符 3 自定义Vue指令 1 Vue过滤器 Vue js 允许你自定义过滤器 可被用于一些常见的文本格式化 过滤器可以用在两个地方 双花括号 插值和 v bind 表达式 后者从 2 1
  • 袁红岗的编程感悟

    我自己知道 近几年也一直在用 但就是说不出来 直到最近几天才能够表达 叫作Think in Code 也就是用代码思考 同时也把代码当成自己思想表达的方式 正如哲学家用文字设计 诠释思想 程序员 说话 用的是代码 这就是一个程序员的境 界
  • 使用python实现简单全连接神经网络

    最近在学习神经网络的相关知识 特在此做一个笔记 python语言的功能很强大 可以使用很少的代码实现很多功能 因此大家如果想研究深度学习的话 一定要懂得python语言 这篇笔记记录我的第一次使用python编写神经网络代码的过程 其中代码
  • Centos7 ELK7.6.2集群搭建

    Centos7 ELK7 6 2集群搭建 ELK7 6 2网盘安装包下载 一 单节点准备 配置ip 配置主机名和主机名映射 关闭防火墙 事件同步 更换yum源 阿里云yum源 安装常用软件 系统优化 创建用来启动es的普通用户 jdk安装
  • 微信小程序(日历/日期)选择插件

    微信小程序日历选择器插件点击日历日期可以获取到年月日 wxml
  • stm32学习笔记——通用计时器基本原理

    stm32f10x最多有8个定时器 stm32f103zet6就有8个定时器 分别是4个通用定时器 2个高级定时器 2个基本定时器 定时器种类 位数 计时器模式 产生DMA请求 捕获 比较通道 互补输出 特殊应用场景 高级定时器 TIM1
  • Spring Boot 应用启动时 java.lang.reflect.InaccessibleObjectException 问题的解决

    Spring Boot 的应用启动的时候遇到下面的错误 java lang reflect InaccessibleObjectException Unable to make private native accessible Set c
  • windows下命令行修改系统时间;修改系统时间的软件

    找了很久 都没有找到 还找了关键词 dos下修改系统时间 因为看到linux下修改系统时间是用hwclock 命令写入主板芯片 而我由于某些原因想自动化修改系统时间 所以找windows下修改系统时间的软件 没有找到 有一个 意天禁止修改系
  • 图解Git

    基本用法 上面的四条命令在工作目录 暂存目录 也叫做索引 和仓库之间复制文件 git add files 把当前文件放入暂存区域 git commit 给暂存区域生成快照并提交 git reset files 用来撤销最后一次git add
  • UNITY一些关于旋转的问题

    实现平滑的旋转 旋转的目的是为了朝向目标物体 untiy中的旋转rotation是一个四元数 在代码里面我们可以用Quaternion 来记录一个人物角色的最初的旋转角度 注意 这个要在awake里赋值 目的是取得该值 为了实现平滑的旋转
  • 关于powershell中错误:无法将“XXX”项识别为 cmdlet、函数、脚本文件或可运行程序的名称解决方案

    在利用ffmpeg进行格式转换时报错 无法将 ffmpeg 项识别为 cmdlet 函数 脚本文件或可运行程序的名称 发现是改动了ffmpeg所在根文件夹名字 导致path环境变量找不到ffmpeg程序 改动环境变量就正常了 快速打开环境变
  • protobuf对象 转为Json串写入elastic search遇到的问题总结

    背景 从kafka中消费数据后拿到的是protobuf序列化后的字节数组 转化为Java中的proto对象后 需要将这些protocol对象继续处理成Json串写入elasticsearch 各种问题 Json工具选择 刚开始尝试使用fas
  • Failed to convert property value of type 'java.lang.String' to required type 'int' for property

    junit Spring 测试Service org springframework beans TypeMismatchException Failed to convert property value of type java lan
  • Django ORM中常用字段类型与参数

    ORM中常用字段类型与参数 在ORM中一个模型类对应的是数据库中的一张表 对象对应的是数据库中的记录 属性则对应的是字段 此篇为章主要整理的是常用的字段类型和对应的参数 字段类型 1 自增长字段 自增长 id models AutoFiel
  • 详述Java三种注释方法及实例说明

    1 注释方法汇总 实例说明在第二部分 1 1单行注释 1 符号 2 注释范围 从符号 开始 到本行结束 3 快捷键 Ctrl Ctrl 和 的组合 选中要注释的内容 按 Ctrl 便可 同时单行注释多行内容 若想多个同个取消 则选中 以及单
  • Linux的静态库和动态库

    库从本质上来说是一种可执行代码的二进制格式 可以被载入内存中执行 库分静态库和动态库两种 静态库和动态库的区别 1 静态函数库 这类库的名字一般是libxxx a 利用静态函数库编译成的文件比较大 因为整个 函数库的所有数据都会被整合进目标