Linux下动静态库的制作与使用

news2024/11/23 2:29:04

学习导航

    • 一、关于动静态库的基本认识
    • 二、设计库的工程师角度
      • (1)制作静态库
      • (2)制作动态库
    • 二、使用库的用户角度
      • (1)使用静态库
      • (2)使用动态库
    • 三、理解的角度

一、关于动静态库的基本认识

1.静态库

  • 静态库以 .a 作为文件后缀
  • 程序在编译链接的时候,将静态库的代码拷贝到可执行文件中,因此程序运行的时候将不再依赖库文件

2.动态库

  • 动态库以 .so 作为文件后缀
  • 程序在运行的时候才去链接动态库的代码,多个程序间共享同一份库代码
  • 一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码
  • 在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接(dynamic linking)
  • 操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间 。因此动态库的使用更加广泛

二、设计库的工程师角度

(1)制作静态库

制作静态库有以下三个步骤:

  1. 将所有的 .c 文件编译生成 .o 文件
    image-20221111174044751

  2. 打包成静态库
     我们只提供所有的 .o 文件,别人可以直接链接使用吗?可以。因为链接的本质就将需要的 .o 文件链接起来。我们可以手动将所有 .o 文件链接:
    image-20221111171121037
     虽然我们可以直接将所有 .o 文件链接生成可执行程序,但是当库中的.o文件很多的时候,使用会比较繁琐,整个文件也会比较冗余。因此我们可以使用ar (archive) 指令将所有.o文件打包成静态库:
    image-20221111174231759
    [注意]:库的名字也是有讲究的,需要以 lib 作为前缀,.a 或者 .so作为后缀

  3. 发布
     使用一个库需要什么?头文件库文件,因此我们分别将其添加到 /lib文件夹和/include文件夹下,作为我们的发布方式:
    image-20221111191007019image-20221111191641785

(2)制作动态库

  1. 将所有的 .c 文件编译生成 .o 文件
     注意要带上 -fPIC 选项,从而产生位置无关码,采用相对地址的方案确定动态库的位置
    image-20221111192314989
  2. 生成动态库
    - shared 选项用于指定生成共享库image-20221111193114879
  3. 发布
    image-20221111192544791image-20221111193234859

二、使用库的用户角度

大家都知道,包含头文件有以下两种方式:

  • include “xxx” :在当前目录下寻找头文件
  • include :在系统目录下寻找头文件

(1)使用静态库

 在使用自实现的库时,包含头文件是一个大问题。因为往往我们所写的目标文件和库文件、头文件不在同一路径下,而且库文件和头文件通常会分别存储(参见发布方式),因此我们不能直接使用上述的两种包含头文件的方式。以下给出三种解决方案:

  1. 拷贝到系统路径下
     系统的头文件被存放在 /usr/include 路径下,库文件则被存放在 /lib64路径下 。编译器会自动去系统路径下寻找头文件和库文件,因此我们可以考虑将头文件和库文件添加到系统路径中。这本质就是在安装第三方库
    image-20221112092231325但是当我们再次尝试使用库文件和头文件时,发生了如下的错误:image-20221112092457251
     我们要搞清楚这样一个概念:路径只是用来找到库在哪里,但是某个路径下可能同时存在很多的库。当我们使用第三方库(非C语言标准)时,编译器原生是不认识的,所以我们需要在编译时主动添加 -l 选项指定我们要链接的库
    image-20221112093059699【说明】:
  • -l和后面的库名之间,空格也有可五
  • -l指定的库名需要去掉lib前缀和.a后缀,因为在匹配的时候会自动加上。例如使用名为 libmydate.a的库文件时,就需要写成-lmydate

   但是不推系荐将我们日常写的库添加到系统路径下,因为有可能会污染系统目录的命名池。当然如果你水平很高,那也当然没问题。

  1. 指定搜索路径
    image-20221112101645945
    [说明]:
  • -I选项:指定头文件查找的路径
  • -L选项:指定库文件查找的路径
  • -l选项:指定使用的库

(2)使用动态库

当我们指定文件路径生成可执行程序后,尝试运时却遇到如下错误提示:

image-20221112102330006

使用ldd指令查看文件的依赖关系就可以发现问题所在:

image-20221112102427587

​ 为什么 .so 文件会找不到呢,我们明明指定了路径了啊?这里我们又需要区分一组概念了:

  • -I -L -l 都是 gcc 的选项,只与gcc有关
  • 形成可执行程序后,gcc就与之后的事无关了
  • 程序是由进程运行的。没有人告诉进程库文件所在路径,自然会出现上述的错误提示

下面提供四种解决方案:

  1. 将库文件添加到系统路径下
    程序运行时会自动去 /lib64 路径下查找对应库文件
  2. 将库文件导入到环境变量中
     程序运行时,会自动在 LD_LIBRARY_PATH 环境变量中查找需要的动态库路径,因此我们可以手动将库文件的路径添加到 LD_LIBRARY_PATH中,最好添加绝对路径,这样在哪里都可以用。(:用于分隔不同路径)
// 注意不要写成如下的形式,这样就将LD_LIBRARY_PATH的初始数据覆盖了
export LD_LIBRARY_PATH=xxx
  1. 配置系统文件
    ​ 当我们重新启动xshell的时候,会发现我们之前追加的环境变量信息不见了。这是因为每次重启的时候,bash都会从配置文件中读取数据重新生成环境变量
     为了永久修改,我们可以尝试修改系统配置文件。操作系统除了在默认路径下搜索库文件外,还会遍历 /etc/ld.so.conf.d 下的所有配置文件,根据配置文件的内容找到目标库所在路径。

    配置文件的内容也非常简单,就是库文件所在的路径
    image-20221112112344308

    再使用 ldconfig 命令将配置文件加载到内存中,从而让配置文件生效。
    image-20221112114453688

  2. 在系统路径中创建库文件的软链接
    软链接本质上就是快捷方式,使用 unlink 指令可以取消链接
    image-20221112115801052

三、理解的角度

[问题一]:为什么静态库不需要运行时查找?

​ 答:使用静态库生成可执行程序时,库文件的代码已经拷贝到代码区了。因此不需要运行时查找。

[问题二]:为什么动态库需要运行时查找?

​ 答:因为程序和动态库是分开加载的。(以下的讲解需要对进程地址空间有一定的理解)

​ 当我们将程序加载到内存中时,OS为我们的程序创建进程控制块PCB,并建立起进程地址空间。因为我们的代码中用到了动态库,因而有部分代码是需要跳转到动态库中执行的。

​  要想跳转到动态库中,前提是将动态库加载到内存。既然要加载到内存中,动态库就必须要能被找到。动态库加载到内存后,通过页表将内存中的动态库映射到堆栈之间的区域,这个区域就叫做共享区

​  我们的代码被存放在代码区,当需要执行动态库中的代码时,跳转到共享区即可,执行完毕再跳转回代码区中继续向下执行。由此我们可以在自己的地址空间中执行完所有的代码(自己的和动态库的)。

​ 整个内存中,虽然动态库只有一份,但是通过进程地址空间,动态库可以被多个进程所共享,因此可以大大节省内存空间。

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

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

相关文章

[TCP/IP] Linux 搭建服务器局域网

文章目录[TCP/IP] Linux 搭建服务器局域网1. 使用python内置库http.server2. 使用Http-Server[TCP/IP] Linux 搭建服务器局域网 1. 使用python内置库http.server python3: http.server 命令行启动: # python 3 python -m http.server 8000 # python 2 python -m S…

ZYNQ_FPGA_SPI通信协议多种实现方式

文章目录PLPSSPIGPIOAXI-GPIOAXI-Quad-SPI(待测试)本文记录一下在使用AD9363中的SPI通信问题,同时针对在ZYNQ系列开发板上实现SPI的方法做一个总结。ZYNQ系列包含了PL端和PS端,因为本科阶段有一定的ARM的开发经验,便想…

2022年,软件测试已经不吃香了吗?

最近因为疫情等各种原因,大厂裁员,失业等等频频受到关注。 不解释,确实存在,各行各业都很难,但是,说软件测试行业不吃香,我还真不认同(不是为培训机构说好话,大环境不好…

JVM从入门到入魔,这份JVM必知必会的完整版带你彻底玩懂JVM

市面上各类 JVM 相关的资料虽多如牛毛,但是明显都很难让大家系统性地学明白,同时一线大厂技术面试现在 JVM 知识也是必考科目。 在大厂摸爬滚打 10 多年的 Java 高级技术专家全面梳理了系统化学习 JVM 的知识和经验,从入门到入魔&#xff0c…

位运算常用技巧以及练习

几个有趣的操作 利用或操作|和空格将英文字符转换成小写 // 可以变成小写i : a | fmt.Printf("%c\n", i)j : A | fmt.Printf("%c\n", j)利用与操作&和下划线把英文字符转换成大写 // 可以变成大写m : b & _n : B & _fmt.Printf("%c\n…

大数据ClickHouse进阶(二十七):ClickHouse服务监控

文章目录 ClickHouse服务监控 一、系统表 1、metrics 2、events 3、asynchronous_metrics

【爬虫系列】Python 爬虫入门(2)

接上篇,继续梳理 Python 爬虫入门的知识点。这里将重点说明,如何识别网站反爬虫机制及应对策略,使用 Selenium 模拟浏览器操作等内容,干货满满,一起学习和成长吧。 1、识别反爬虫机制及应对策略 1.1 测试网站是否开启…

项目中如何配置 Maven 为国内源

目录 1. 创建出一个 Maven 项目 2. 打开项目配置界面, 检查并配置国内源 2.1 打开配置界面 (当前项目界面和新项目配置界面) 2.2 搜索 "Maven" 2.3 设置 setting.xml (给此 xml 中添加国内源) 2.4 把上面的步骤 (2.1~2.3) 在新项目的配置界面中重新配置一遍. …

【MySQL】MySQL事务隔离机制与实现原理详解(MySQL专栏启动)

📫作者简介:小明java问道之路,专注于研究 Java/ Liunx内核/ C及汇编/计算机底层原理/源码,就职于大型金融公司后端高级工程师,擅长交易领域的高安全/可用/并发/性能的架构设计与演进、系统优化与稳定性建设。 &#x1…

加权黑猩猩优化算法(WChOA)附Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。 🍎个人主页:Matlab科研工作室 🍊个人信条:格物致知。 更多Matlab仿真内容点击👇 智能优化算法 …

Java实现五子棋(附源码)

文章目录一、游戏介绍二、效果展示三、代码展示1、登录页面2、算法程序3、棋盘实现四、资源下载五、文末总结一、游戏介绍 今天给大家分享一个用java写的小游戏——《五子棋》 (完整代码可在【资源下载】目录查看) 。五子棋是一种两人对弈的纯策略型棋类…

中缀表达式转后缀表达式

1 后缀表达式 一种不需要括号的表达式方法,也把它称为 逆波兰表达式,是波兰逻辑学家卢卡西维奇(Lukasiewicz)发明的一种表示表达式的方法。 2 中缀表达式 中缀表达式也就是我们常见的表达式书写方法,比如“8(2-1)352”就是一个中…

HTML期末大作业——游戏介绍(HTML+CSS+JavaScript) web前端开发技术 web课程设计网页规划与设计 Web大学生网页成品

🎉精彩专栏推荐👇🏻👇🏻👇🏻 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 💂 作者主页: 【主页——🚀获取更多优质源码】 🎓 web前端期末大作业…

前端爱心代码跟个风

光棍节new一个对象发给Ta <!DOCTYPE html> <html><head><title></title> </head> <style>* {padding: 0;margin: 0;}html,body {height: 100%;padding: 0;margin: 0;background: rgb(2, 2, 2);}canvas {position: absolute;width: …

关于 SAP 电商云 Spartacus UI Navigation Service 执行的一些明细

第一次触发的时候&#xff0c;navigation.uid 并没有值&#xff1a; 下图&#xff1a;navigation.service 的 getNavigationNode 方法。 触发这个订阅的入口&#xff1a; <cx-navigation-ui*ngIf"data$ | async as data"[node]"node$ | async"[ngC…

【HTML实战】把爱心代码放在自己的网站上是一种什么体验?

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【HTML】 最近随着电视剧《点燃我温暖你》的火热播出&#xff0c;剧中帅气学霸李洵的炫酷爱心代码也迅速火出了圈&#xf…

【毕业设计】口罩佩戴检测系统 - opencv 卷积神经网络 机器视觉 深度学习

文章目录&#x1f6a9; 0 简介&#x1f6a9;1 课题背景&#x1f6a9; 2 口罩佩戴算法实现2.1 YOLO 模型概览2.2 YOLOv32.3 YOLO 口罩佩戴检测实现2.4 实现代码2.5 检测效果&#x1f6a9; 3 口罩佩戴检测算法评价指标3.1 准确率&#xff08;Accuracy&#xff09;3.2 精确率(Prec…

Golang学习之路5-结构体/类封装等使用

文章目录前言一、结构体1.声明结构体2.匿名结构体二、类1.封装及绑定2.继承3.多态及接口4.类访问权限总结前言 go语言支持类的操作&#xff0c;但是没有class关键字&#xff0c;使用struct来模拟类、结构体。类支持封装、绑定方法、继承等 一、结构体 结构体是由零个或多个任…

【C++进阶】map和set( 万字详解)—— 上篇

&#x1f387;C学习历程&#xff1a;进阶 博客主页&#xff1a;一起去看日落吗持续分享博主的C学习历程博主的能力有限&#xff0c;出现错误希望大家不吝赐教分享给大家一句我很喜欢的话&#xff1a; 也许你现在做的事情&#xff0c;暂时看不到成果&#xff0c;但不要忘记&…

青少年python系列 42.面向对象-继承

青少年python系列目录_老程序员115的博客-CSDN博客 青少年python教学视频ppt源码 继承&#xff1f;继承啥&#xff1f;提起继承这两个字&#xff0c;最先能够联想到的应该就是子继父业这个成语。还记得之前在我们的课程中提及过&#xff0c;在面向对象编程时&#xff0c;是可以…