【Linux】一文看懂Linux静态库和动态库

文章目录

    • 一、静态库(Static Library)
    • 二、动态库(Dynamic Library)
    • 三、静态库和动态库的比较
    • 四、静态库的制作与使用
    • 五、动态库的制作与使用
    • 六、如何区分链接的是动态库还是静态库

在Linux系统编程中,库是一组预先编写好的代码,可以在多个程序中使用。根据链接方式不同,库可以分为静态库和动态库。下面详细介绍这两种库以及它们的使用方法。

一、静态库(Static Library)

静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为 .a 。这类库的名字一般是libxxx.a,xxx是静态库的名字,lib是静态库的前缀。

利用静态库编译成的文件比较大, 因为库会被整合进目标代码中,它的优点就显而易见了,即编译后的执行程序不需要外部的库支持,因为所有使用的库函数都已经被编译进可执行文件。当然这也会成为它的缺点,因为如果静态库变了,那么你的程序必须重新编译,而且体积比较大。

静态链接库的特点

(1)、编译时链接
编译时链接:在编译时,库代码被嵌入到可执行文件中。编译器和链接器将库文件中的目标代码与应用程序的目标代码进行整合,生成单一的可执行文件。
独立性:生成的可执行文件可以独立运行,无需依赖库文件的存在。
(2)、生成单个大文件
文件体积较大:由于库代码被嵌入到可执行文件中,生成的可执行文件体积较大,包含了所有必需的库代码。
(3)、分发和部署
易于分发:由于所有依赖库都已经包含在可执行文件中,分发和部署相对简单,不需要额外的库文件。
无库版本兼容问题:避免了因为库版本不同而造成的兼容性问题。应用程序总是运行特定版本的库代码,确保了应用程序行为的一致性。
(4)、加载时间
更快的加载时间:由于所有必需的代码都在可执行文件中,加载可执行文件时无需额外的动态链接步骤,启动速度相对较快。
(5)、运行时内存消耗
独立内存消耗:每个使用静态库的可执行文件在运行时都会占用独立的内存,这可能会导致内存使用效率较低,特别是在多个应用程序使用同一个静态库时。
(6)、更新和维护
更新麻烦:如果需要更新库代码,必须重新编译所有依赖该库的应用程序。每次更新库都需要重新编译和分发整个应用程序。
安全性和稳定性:不容易受到外部库更新或系统环境变化的影响,程序行为稳定且可预测。
(7)、库代码优化
编译器优化:静态链接过程中,编译器可以对整个程序进行全局优化,包括库代码和应用程序代码一起进行优化,可能生成更高效的机器代码。
(8)、无库搜索路径问题
无需配置库路径:由于所有代码都嵌入到可执行文件中,不需要在运行时配置库的搜索路径,不会遇到找不到库文件的问题。
(9)、调试和诊断
调试方便:所有代码包括库代码都在一个文件中,调试工具可以直接访问所有代码,有助于调试和诊断问题。

二、动态库(Dynamic Library)

动态库(Dynamic Library),也叫共享库(Shared Library),是一种在运行时加载的库。它们的文件扩展名通常是 .so(共享对象)。这类库的名字一般是libxxx.so,有时候也会看到一些开源库命名成libxxx.so.x.y.z,xxx是动态库的名字,lib是动态库前缀,x是主版本号,y是次版本号,z是发布版本号。

相对于静态库,动态库在编译的时候并没有被编译进目标代码中,而是在程序运行时才被载入,因此动态库所产生的可执行文件比较小。由于动态库没有被整合进目标代码中,而是程序运行时动态的加载并调用,所以程序的运行环境必须提供相应的库。动态库的改变并不影响你的程序,所以动态库的升级比较方便。而且如果多个程序都要使用同一个函数,动态库就非常适合,可以减小应用程序的体积。

动态链接库的特点

(1)、运行时链接
动态加载:动态链接库在程序运行时被加载,可以按需加载,提升应用程序的启动速度和灵活性。
灵活性:允许在程序运行时替换或更新库,而不需要重新编译和重新分发应用程序。
(2)、减少可执行文件体积
可执行文件小:由于不包含库的实现代码,可执行文件较小,主要包含符号表和链接信息。
共享代码:多个程序可以使用相同的动态库,从而减少总的存储需求。
(3)、共享内存和资源
内存共享:多个进程可以共享同一个动态库的内存实例,节省系统资源并提高效率。
资源高效:由于共享同一个库实例,可以显著减少内存使用量,特别是在大型应用程序和多程序环境中。
(4)、简化更新和维护
库独立更新:只需更新动态库文件,而无需重新编译依赖这些库的所有应用程序。
快速修复:应用程序一旦发现问题,可以通过更新动态库快速修复,而无需对应用程序进行大规模修改。
(5)、增强的灵活性
运行时决策:应用程序可以在运行时决定使用哪些库,实现更高的灵活性和适应性。
(6)、系统依赖管理
库路径管理:需要管理库文件的搜索路径,以确保在运行时能够正确加载所需的库文件。
环境变量:环境变量如 LD_LIBRARY_PATH可以用来指定库搜索路径,同时 ldconfig 提供了配置方便的库路径管理。
(7)、调试复杂性
默认路径:调试动态库相对复杂,因为需要确保调试符号可用,并且调试工具能够正确解析和加载动态库。
诊断工具:需要使用特定的工具(如ldd)来检查动态库依赖关系,并使用工具(如 strace)来追踪库加载过程。
(8)、性能影响
启动时间稍慢:由于需要在程序启动时加载和链接动态库,启动时间可能会略微增加,但通常影响较小。
运行时效率:如果管理得当,动态库可以提升系统整体资源利用效率,但需要处理好潜在的符号解析和加载开销。

三、静态库和动态库的比较

链接时间
静态库:在编译时链接。
动态库:在运行时链接。

可执行文件大小:
静态库:可执行文件包含所有相关库代码,因此通常较大。
动态库:可执行文件只包含库的引用,较小。

内存消耗:
静态库:每个使用同一静态库的程序都有一份库代码拷贝。
动态库:多个进程可以共享同一份动态库的内存映像,因此总消耗较少。

更新和维护:
静态库:更新库时,需要重新编译所有依赖该库的程序。
动态库:更新库后,所有依赖该库的程序在下次启动时都会使用新库。

加载时间:
静态库:加载时间较短,因为所有代码已经在可执行文件中。
动态库:首次加载时需要额外的时间以加载动态库。
在这里插入图片描述
总结
静态库和动态库在Linux系统编程中各有优劣。静态库简单易管理,但消耗更多的磁盘空间和内存,适用于不频繁更新的库。动态库节省资源,适用于共享库更新频繁的场景,但需要注意库版本兼容性问题。

四、静态库的制作与使用

【1】源码
foo.c

#include <stdio.h>void foo() 
{printf("This is function foo\n");return;
}

bar.c

#include <stdio.h>void bar() 
{printf("This is function bar\n");return;
}

main.c

#include <stdio.h>
#include "test.h"int main(int argc, char *argv[])
{foo();bar();return 0;
}

【2】编译源代码文件为目标文件

gcc -c foo.c -o foo.o
gcc -c bar.c -o bar.o

【3】创建静态库文件
使用 ar 命令将目标文件组合成一个静态库文件。

ar rcs libmylib.a foo.o bar.o

【4】链接静态库
链接静态库并编译可执行文件

gcc main.c -I. -L. -lmylib -o app

-I: 后面接头文件
-L: 后面接库文件路径路径
-l: 后面接库文件名

ubuntu下demo运行示例如下:
在这里插入图片描述

五、动态库的制作与使用

【1】源码
 源码同静态库源码
【2】编译源代码文件为目标文件

gcc -fPIC -c foo.c -o foo.o
gcc -fPIC -c bar.c -o bar.o

其中,-fPIC 表示生成位置无关代码。
【3】创建动态库文件
使用 gcc 命令将目标文件组合成一个动态库文件。

gcc -shared -o libmylib.so foo.o bar.o

【2】【3】步骤合为一句指令,如下:

gcc foo.c bar.c -fPIC -shared -o libmylib.so

【4】链接动态库
链接动态库并编译可执行文件

gcc main.c -I. -L. -lmylib -o app

-I: 后面接头文件
-L: 后面接库文件路径路径
-l: 后面接库文件名

ubuntu下demo运行示例如下:
如果动态库不在标准库路径中,必须设置库路径。例如,如果库在当前目录,可以使用:LD_LIBRARY_PATH=. ./app,或者将库路径添加到系统路径中。
在这里插入图片描述

六、如何区分链接的是动态库还是静态库

通过上面“静态库的制作与使用”和“动态库的制作与使用”我们看到链接库并编译执行文件都执行了命令

gcc main.c -I. -L. -lmylib -o app

根据这一句命令,如何区分链接的是静态库还是动态库呢

在编译和链接程序时,gcc 默认优先链接动态库(.so文件)而不是静态库(.a文件)。然而,也可以通过指定选项明确告诉编译器链接静态库或动态库。以下是具体的说明和方法:

链接静态库
如果你明确想要链接静态库,你可以使用 -static 选项。这将强制 gcc 使用静态库进行链接:

gcc main.c -I. -L. -lmylib -o app -static  
//这里的-static选项是告诉编译器mylib是静态库,如果不用强制也可以用下面命令
//gcc main.c -I. -L. -lmylib -o app 

这会通过添加 -static 选项来强制链接静态库 libmylib.a(假设该库存在于库搜索路径下)。

链接动态库
如果不加任何特别的选项,gcc 默认会优先链接动态库(.so文件),前提是该动态库存在于指定的库路径中。

gcc main.c -I. -L. -lmylib -o app

这条命令会根据搜索路径优先尝试链接 libmylib.so,如果未找到动态库,才会尝试链接 libmylib.a。

检查链接的库
你可以使用 ldd 命令检查最终生成的可执行文件链接了哪些库。ldd 将显示动态链接库的路径和信息:

ldd app

如果可执行文件是动态链接的,你会看到它列出了链接的动态库(libmylib.so 等)。如果没有列出特定库或只显示基本系统库,这表明某些库(如 libmylib.a)是静态链接的。

静态库链接的可执行文件,执行ldd app,结果如下:
在这里插入图片描述
动态库链接的可执行文件,执行ldd app,结果如下:
在这里插入图片描述
出现错误:libmylib.so => not found

错误原因:ldd提示找不到库文件,而库文件就在当前目录中。因为链接器ldd默认的目录是/lib和/usr/lib,如果放在其他路径也可以,需要让ldd知道库文件在哪里。

解决方法1:编辑/etc/ld.so.conf文件,在新的一行中加入库文件所在目录;比如笔者应加:/home/hsiao/work,执行命令

ldconfig

目的是用ldconfig加载,以更新/etc/ld.so.cache文件。

解决方法2:执行命令

export LD_LIBRARY_PATH=/home/hsiao/work

export LD_LIBRARY_PATH=/home/hsiao/work 这条命令用于设置环境变量 LD_LIBRARY_PATH,其作用是告诉运行时链接器(dynamic linker/loader)在 /home/hsiao/work 目录中查找动态库(共享库,即 .so 文件)。

总结
静态库链接:使用 -static 来强制链接静态库。
动态库链接:默认情况下,gcc 优先链接动态库。无需特别选项,如果动态库存在于搜索路径中,它会被默认使用。
检查链接结果:使用 ldd 命令检查生成的可执行文件链接了哪些库。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/869723.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【全面讲解下Foxit Reader】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

3年经验的B端产品经理,应该是什么水平?

问你一个问题&#xff1a;你觉得3年经验的B端产品经理&#xff0c;应该是什么水平&#xff1f;很多朋友可能也没有仔细想过&#xff0c;自己3年后应该达到一个什么水平&#xff1f;能做什么体量的业务&#xff1f;要能拿多少薪资&#xff1f; 前几天和一个B端产品经理聊天&…

SQL之delete、truncate和drop区别

MySQL删除数据的方式都有哪些&#xff1f; 常用的三种删除方式&#xff1a;通过 delete、truncate、drop 关键字进行删除&#xff1b;这三种都可以用来删除数据&#xff0c;但场景不同。 一、从执行速度上来说 drop > truncate >> DELETE;二、从原理上讲 1、DELET…

ctfshow-web入门-文件上传(web161、web162、web163)远程包含

目录 1、web161 2、web162 3、web163 1、web161 先传配置文件&#xff0c;可以上传成功 因为我前面给的 .user.ini 都是带了图片头 GIF89a 的&#xff0c;前面的题这个图片头可以去掉&#xff0c;但是在这里如果去掉是不行的。 因此后面上传的东西我们都带上这个图片头&…

FPGA程序设计

在设计FPGA时&#xff0c;多运用模块化的思想取设计模块&#xff0c;将某一功能设计成module。 设计之前要先画一下模块设计图&#xff0c;列出输入输出接口&#xff0c;再进一步设计内部功能。 状态机要画图&#xff0c;确定每个状态和状态之间怎么切换。状态用localparam定…

宏碁F5-572G-59K3笔记本笔记本电脑拆机清灰教程(详解)

1. 前言 我的笔记本开机比较慢&#xff0c;没有固态&#xff0c;听说最近固态比较便宜&#xff0c;就想入手一个&#xff0c;于是拆笔记本看一下有没有可以安的装位置。&#xff08;友情提示&#xff0c;在拆机之前记得洗手并擦干&#xff0c;以防静电损坏电源器件&#xff09…

视频版权音乐处理☞AI分离人声、音效、背景音乐的需求和进展-2024

随着互联网的普及和短视频的兴起&#xff0c;视频内容的全球各大平台分发越来越普遍。然而&#xff0c;不同国家和地区的音乐版权、不同社媒平台拥有的版权和处理政策都存在差异&#xff0c;因此同一个视频在多渠道分发的时候就会产生版权侵权风险。如何既能满足全球多渠道、多…

【UE5】调用ASR接口,录制系统输出。录制音频采样率不匹配

暂时测出window能用。阿里的ASR接口当前仅支持8000和16000。UE默认采样44100。

补码一位乘法原理(布斯编码详讲)

最近在看补码乘法的时候&#xff0c;感觉到很奇怪的一点&#xff0c;那就是补码的一位乘法&#xff0c;就是上网查了大量的资料都没有理解到它真正的原理&#xff0c;总感觉还是不会。那么&#xff0c;补码乘法的原理到底是什么呢&#xff1f;而让我们一直困惑的点是哪里呢&…

9.3 栅格图层符号化单波段伪彩色渲染

文章目录 前言单波段伪彩色QGis设置为单波段伪彩色二次开发代码实现单波段伪彩色 总结 前言 介绍栅格图层数据渲染之单波段伪彩色渲染说明&#xff1a;文章中的示例代码均来自开源项目qgis_cpp_api_apps 单波段伪彩色 使用单波段假彩色渲染栅格图层能够使用配色方案&#xff…

昇思25天学习打卡营第22天 | Shufflenet图像分类

ShuffleNet图像分类 当前案例不支持在GPU设备上静态图模式运行&#xff0c;其他模式运行皆支持。 ShuffleNet网络介绍 ShuffleNetV1是旷视科技提出的一种计算高效的CNN模型&#xff0c;和MobileNet, SqueezeNet等一样主要应用在移动端&#xff0c;所以模型的设计目标就是利用有…

【Linux】进程(9):进程控制3(进程程序替换)

大家好&#xff0c;我是苏貝&#xff0c;本篇博客带大家了解Linux进程&#xff08;9&#xff09;进程控制1&#xff0c;如果你觉得我写的还不错的话&#xff0c;可以给我一个赞&#x1f44d;吗&#xff0c;感谢❤️ 目录 &#xff08;A&#xff09;什么是进程程序替换&#xf…

js实现图片放大镜功能,简单明了

写购物项目的时候&#xff0c;需要放大图片&#xff0c;这里用js写了一个方法&#xff0c;鼠标悬浮的时候放大当前图片 这个是class写法 <!--* Descripttion: * Author: 苍狼一啸八荒惊* LastEditTime: 2024-07-10 09:41:34* LastEditors: 夜空苍狼啸 --><!DOCTYPE …

7.10号小项目部分说明

总体说明 糖锅小助手 我这次主要对上次糖锅小助手界面添加了一个侧边栏&#xff08;侧边输入框放置了三个按钮&#xff0c;可以跳转到其他ai聊天界面&#xff0c;还可以退出聊天界面回到登录界面&#xff09;和一个日期输入框&#xff08;日期输入框获取时间&#xff0c;根据时…

Ubuntu固定虚拟机的ip地址

1、由于虚拟机网络是桥接&#xff0c;所以ip地址会不停地变化&#xff0c;接下来我们就讲述ip如何固定 2、如果apt安装时报错W: Target CNF (multiverse/cnf/Commands-all) is configured multiple times in /etc/apt/sources.list:10&#xff0c; 检查 /etc/apt/sources.list…

分类模型的算法性能评价

一、概述 分类模型是机器学习中一种最常见的问题模型&#xff0c;在许多问题场景中有着广泛的运用&#xff0c;是模式识别问题中一种主要的实现手段。分类问题概况起来就是&#xff0c;对一堆高度抽象了的样本&#xff0c;由经验标定了每个样本所属的实际类别&#xff0c;由特定…

Type-C/DP1.4到HDMI2.0替代龙讯LT8711HE,集睿智远CS5262

NCS8622是一款高性能低功耗的Type-C/DP1.4到HDMI2.0转换器&#xff0c;设计为连接USB Type-C源或DP1.4源到HDMI2.0。 NCS8622集成了符合DP1.4标准的接收器&#xff0c;以及符合HDMI2.0标准的发射器。此外&#xff0c;CC控制器用于将CC通信到实现DP Alt模式。DP接收器集成了HDCP…

什么是数据同步服务RSYNC?

大家好呀&#xff01;这里是码农后端。今天来介绍一下数据同步服务RSYNC&#xff0c;作为Linux/Unix系统中远程或本地复制同步&#xff08;复制&#xff09;文件和目录最常用的命令&#xff0c;相比于scp命令&#xff0c;其具有增量备份、数据同步时保持文件的原有属性等优点。…

在Linux上安装和配置RocketMQ:保姆级教程

感谢您阅读本文&#xff0c;欢迎“一键三连”。作者定会不负众望&#xff0c;按时按量创作出更优质的内容。 ❤️ 1. 毕业设计专栏&#xff0c;毕业季咱们不慌&#xff0c;上千款毕业设计等你来选。 当安装RocketMQ时&#xff0c;确保遵循以下步骤&#xff1a; 步骤概述 安装 …

flask模块化、封装使用缓存cache(flask_caching)

1.安装flask_caching库 pip install flask_caching 2.创建utils Python 软件包以及cache_helper.py 2.1cache_helper.py代码 from flask_caching import Cachecache Cache()class CacheHelper:def __init__(self, app, config):cache.init_app(app, config)staticmethoddef…