【Linux】动静态库的制作
🌠 作者:@阿亮joy.
🎆专栏:《学会Linux》
🎇 座右铭:每个优秀的人都有一段沉默的时光,那段时光是付出了很多努力却得不到结果的日子,我们把它叫做扎根
目录
- 👉动静库和静态库👈
- 👉制作动静态库👈
- 制作静态库
- 制作动态库
- 👉库的意义👈
- 👉总结👈
👉动静库和静态库👈
- 静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库。
- 动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。
- 一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码。
- 在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接(dynamic linking)。
- 动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间。而静态链接是将库的代码链接到可执行文件中,因此该可执行文件往往比较大。
👉制作动静态库👈
在工程项目开发中,我们往往会用到第三方提供的库。那第三方的库是如何制作出来的呢?第三方制作出来的库,是如何提供给我们使用的呢?为了回答两个问题,我们现在就来学习一下动静态库的制作。
制作静态库
为了更好地说明演示库的制作,我们先回顾一下以前的多文件的写法。头文件中放库中的头文件的包含和函数的声明等,源文件中放函数的实现等。
// myprint.h
#pragma once#include <stdio.h>
#include <time.h>extern void Print(const char* str);// mymath.h
#pragma once#include <stdio.h>extern int addToTarget(int from, int to);// myprint.c
#include "myprint.h"void Print(const char* str)
{printf("%s [%d]\n", str, (int)time(NULL));
}// mymath.c
#include "mymath.h"int addToTarget(int from, int to)
{int ret = 0;for(int i = from; i <= to; ++i){ret += i;}return ret;
}// main.c
#include "myprint.h"
#include "mymath.h"int main()
{Print("hello world");int ret = addToTarget(0, 100);printf("ret = %d\n", ret);return 0;
}
输入gcc main.c mymath.c myprint.c -o my.exe -std=c99
指令就可以生成可执行程序 my.exe了。
假如现在我们是库的制作者,如果我们将头文件 .h 和目标文件 .o 给别人,别人是否可以实现我们所写好的库呢?其实是可以的,见下图所示:
将目标文件提供给别人去编译,是不方便别人使用的。因为目标文件多了,编译起来就会比较麻烦,而且传输的过程中还可能出现目标文件丢失的情况。所以我们需要将目标文件打包,而形成的包就是传说中的静态库了。
将目标文件打包成静态库指令
ar -rc libhello.a mymath.o myprint.o
#以下是注释
#ar是GNU中的归档工具 archive 归档
#-r replace 替换
#-c create 创建
#lib 库的前缀 .a 静态库的后缀 两者之间的内容就是静态库的名字
使用Makefile来生成静态库
libhello.a:mymath.o myprint.oar -rc libhello.a mymath.o myprint.o
mymath.o:mymath.cgcc -c mymath.c -o mymath.o -std=c99
myprint.o:myprint.cgcc -c myprint.c -o myprint.o -std=c99.PHONY:clean
clean:rm -rf *.o libhello.a
现在我们已经制作好了静态库,那么如果将这个静态库发布给别人使用呢?发布给别人使用的库中是包含 include 和 lib 两个文件夹,其中 include 中包含库的所有头文件,lib 包含的是对应的库文件。
那么,我们修改一下 Makefile,让它可以自动生成上方所述的路径。
libhello.a:mymath.o myprint.oar -rc libhello.a mymath.o myprint.o
mymath.o:mymath.cgcc -c mymath.c -o mymath.o -std=c99
myprint.o:myprint.cgcc -c myprint.c -o myprint.o -std=c99.PHONY:hello
hello:mkdir -p hello/includemkdir -p hello/libcp -rf *.h hello/includecp -rf *.a hello/lib.PHONY:clean
clean:rm -rf *.o libhello.a hello
将其他文件清理后,就剩下静态库和我们写的程序了。
接下来,我们就来学习一下如何使用静态库。
- 将静态库拷贝到系统的默认搜索路径。头文件的默认搜索路径是
/usr/include/
,库文件的默认搜索路径是/lib64/
或者/usr/lib64/
。
现在我们已经将静态库拷贝到了对应的路径下,那我们使用gcc main.c
指令将代码编译一下,就会发现无法通过编译。原因是 gcc 默认链接的静态库是/lib64/libc.a
,如果想让 gcc 链接我们写的静态库,就需要使用下方的指令了。
gcc main.c -lhello
#-l 链接 hello是静态库的名字
注:将库拷贝到系统的默认路径下,就叫做库的安装。
将我们自己写的静态库拷贝到系统的默认链接下这种做法是不推荐的。因为我们自己写的库并没有经过可靠性验证,所以不太建议这种做法。那么我们需要将自己写的静态库移出系统的默认路径,该过程也称为库的卸载。
- 指定头文件、库的路径和要链接的库
gcc main.c -I ./hello/include/ -L ./hello/lib/ -lhello
#-I 指明头文件所在的路径
#-L 指明库的路径
-l 指明所要路径的库(因为库路径下可能不止一个库)
制作动态库
静态库的代码是会被拷贝进可执行程序中;而动态库在没有被链接前会被编译好,当使用动态库时,并不是将代码拷贝到可执行程序中,而是让可执行程序与动态库产生关联。
生成目标文件
gcc -fPIC -c mymath.c -o mymath.o -std=c99
gcc -fPIC -c myprint.c -o myprint.o -std=c99
readelf -S 目标文件名 #查查看ELF格式的文件信息
-fPIC 选项的意思是形成与位置无关的目标二进制文件。动态库形成后,可以在内存的任意位置加载。而静态库的代码是拷贝到可执行程序中,可执行程序是有自己的地址空间的,所以静态库的代码需要拷贝到地址空间的特定位置,这就是与位置有关。静态库是按照绝对编址的方式,而动态库是按照相对编址(段地址+偏移量)的方式。
将目标文件打包
动态库的打包并不是使用 ar 指令,而是采用 gcc 加上 -shared 选项将目标文件打包成库。注意:一定要加上 -shared 选项,不然会被 gcc 识别成要生成可执行程序,从而报出没有 main 函数的错误。
gcc -shared myprint.o mymath.o -o libhello.so
以上就形成了动态库了,那么我们也来学习一下用 Makefile 来生成动态库。
.PHONY:all
all:libhello.so libhello.alibhello.so:mymath_d.o myprint_d.ogcc -shared mymath_d.o myprint_d.o -o libhello.so
mymath_d.o:mymath.cgcc -fPIC -c mymath.c -o mymath_d.o -std=c99
myprint_d.o:myprint.cgcc -fPIC -c myprint.c -o myprint_d.o -std=c99libhello.a:mymath.o myprint.oar -rc libhello.a mymath.o myprint.o
mymath.o:mymath.cgcc -c mymath.c -o mymath.o -std=c99
myprint.o:myprint.cgcc -c myprint.c -o myprint.o -std=c99.PHONY:output
output:mkdir -p output/includemkdir -p output/libcp -rf *.h output/includecp -rf *.a output/libcp -rf *.so output/lib.PHONY:clean
clean:rm -rf *.o *.a *.so output
将动静态库拷贝到 uselib 路径下
链接动态库
gcc main.c -I output/include/ -L output/lib/ -lhello
当存在同名的动静态库时,使用上方的指令形成的可执行程序是无法执行的,其报错原因是无法找到对应的动态库。那为什么会这样呢?
当output/lib/
路径下只有静态库时,却又可以生成对应的可执行程序,这又是为什么呢?
原因是 gcc 默认链接的是动态库,而如果只有我们自己制作的静态库,没有自己制作的动态库,那么就只能链接该静态库了。注意:系统的动态库还是动态链接的,只是静态链接自己制作的静态库。如果想让全部库都是静态链接的话,需要加上 -static 选项。-static 的意义就是摒弃优先使用动态库的原则,而是直接使用静态库。
如果存在同名的动静态库,默认使用的就是动态库,上面的报错只是找不到而已。那如何解决呢?解决这个问题,就需要了解动态库的加载了。
动态库的加载
如果是静态链接,静态库中的代码会被拷贝到可执行程序中。当可执行程序运行时,静态库的代码也被加载到内存了。而如果采用的是动态链接,可执行程序和动态库是分批加载的,并不是一起加载的。我们知道栈区和堆区之间存在一个共享区,而动态库的代码就是被加载到进程地址空间的共享区中去了。
当有多个进程使用同一个动态库的代码,这时候就不需要加载动态库的代码,只需要建立页表映射关系就行了。如果多个进程使用同一个静态库,那么内存中就会有多份静态库的代码,这样就会浪费内存空间了。这也就是动态库的意义。
当我们执行可执行程序时,不是已经指定了动态库所在的路径了吗?为什么还是找不到动态库呢?其实这是告诉 gcc 编译器,并不是告诉给操作系统的加载器。当程序运行加载时,就和 gcc 没有关系了,所以我们需要将动态库所在的路径告诉给操作系统的加载器,这样才能够找到动态库。
因为 C语言的动态可以就在系统的默认路径下,所以操作系统就能够找到对应的动态库;而静态库的代码是直接拷贝到可执行程序中的,不存在需要找的问题。那么,我们如果让操作系统找到自己制作的动态库呢?第一种方式就是将自己制作的动态库拷贝到系统的默认路径下,但这种方式不好。我们可以采用下方的方法:
- 将动态库所在的路径导入到环境变量 LD_LIBRARY_PATH 中
系统可以通过环境变量 LD_LIBRARY_PATH 找到需要的动态库,将其加载到内存中。
这种方法有一个缺点,就是当我们将 Xshell 关掉时,再次启动时,会将导入到 LD_LIBRARY_PATH 中的路径都清空掉。
- 新增配置文件
我们只需要在/etc/ld.so.conf.d/
路径下创建一个.conf
后缀的文件,该文件中保存动态库的路径,最后输入sudo ldconfig
指令更新配置文件即可。
将配置文件删除后,还是找到我们的动态库的。原因是缓存中还有该配置文件,只要将配置文件更新一下就可以了。
- 在
/lib64/
路径下建立一个与动态库的软链接
还有一种方法就是修改登录脚本,Linux 的登录脚本文件有两个,分别是 .bashrc
和 .bash_profile
,它们都是在家目录下的。.bash
是被.bash_profile
所调用的,那么我们可以在.bash_profile
文件中增加动态库所在的路径即可,但这种方式不建议现在做。
以上就是动态库的制作了,现在我们来了解一下为什么要有库。
👉库的意义👈
- 站在使用库的角度,库的存在,可以大大减少我们开发的周期,提高软件本身的质量(健壮性等)。
- 站在写库的人的角度,1. 简单 2.代码安全。
- 好玩的库:ncurses(基于字符的界面库),搜索关键词 Centos 7 yum 安装 ncurses。boost(C++ 的准标准库)。
👉总结👈
本篇博客主要讲解了什么是动静态库以及动静态库的制作等等。那么以上就是本篇博客的全部内容了,如果大家觉得有收获的话,可以点个三连支持一下!谢谢大家!💖💝❣️
相关文章:

【Linux】动静态库的制作
🌠 作者:阿亮joy. 🎆专栏:《学会Linux》 🎇 座右铭:每个优秀的人都有一段沉默的时光,那段时光是付出了很多努力却得不到结果的日子,我们把它叫做扎根 目录👉动静库和静…...

数据备份学习笔记2
Linux实现本地备份的命令: mkdir -p /root/backup/date "%Y-%m-%d" tar -zcvPf /root/backup/date "%Y-%m-%d"/test20230221.tar.gz /root/test20230221/ 我们再看下tar命令选项: tar -czvf txt3.tar.gz txt3 tar -xvf txt4.tar.g…...
webRTC
WebRTC是一种实时通信技术,可以在浏览器中实现音频、视频和数据的实时传输。WebRTC使用标准的API和协议,如RTCPeerConnection和RTCDataChannel等,可以实现点对点通信和多方会议等多种应用场景。WebRTC可以应用于Web前端、移动端和桌面端等多种…...

用Python搓一个黑洞
文章目录简介单位制观测绘图简介 黑洞图像大家都知道,毕竟前几年刚发布的时候曾火遍全网,甚至都做成表情包了。 问题在于,凭什么认为这就是黑洞的照片,而不是一个甜甜圈啥的给整模糊了得到的呢?有什么理论依据吗&…...

Spring MVC常用功能及注解
目录 一、什么是Spring MVC 1.1 Spring MVC定义 1.2 MVC定义 1.3 MVC和Spring MVC的关系 1.4 Spring MVC的作用 二、Spring MVC的使用 2.1 Spring MVC的创建和连接 2.1.1 RequestMapping注解 2.1.2 GetMapping注解 2.1.3 PostMapping注解 2.2 获取参数 2.2.1 获取单…...
shell 编程
文章目录一、shell 编程1.1. 脚本执行1.2. 变量1.3. 特殊变量1.4. 运算符1.5. for 循环1.6. while 循环1.7. case 语句1.8. read 命令1.9. if 判断1.10. 判断语句1.11. 自定义函数1.12. 脚本调试二、sed2.1. sed 选项2.2. sed function2.3. sed 删除(d 命令…...

Leetcode.1401 圆和矩形是否有重叠
题目链接 Leetcode.1401 圆和矩形是否有重叠 Rating : 1709 题目描述 给你一个以 (radius, xCenter, yCenter)表示的圆和一个与坐标轴平行的矩形 (x1, y1, x2, y2),其中 (x1, y1)是矩形左下角的坐标,而 (x2, y2)是右上角的坐标。 如果圆和矩…...

CHAPTER 3 Web Server - httpd配置(二)
Web Server - httpd配置二3.1 httpd配置3.1.1 基于用户的访问控制3.1.2 basic认证配置示例:1. 添加用户2. 添加网页文件3. 定义安全域4. 修改父目录权限5. 访问效果6. 在配置文件中定义一个".htaccess"隐藏文件7. 添加组3.1.3 虚拟主机1. 构建方案2. 基于…...

VSCode 连接 SSH 服务器
欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://blog.csdn.net/caroline_wendy/article/details/129133964 配置VSCode 下载VSCode:https://code.visualstudio.com/ 安装 Remote - SSH: 点击右下角蓝色图标: 连接服务器: 即可。 默认连接:ssh chen…...

如何选择靠谱的插画培训课程
如何选择靠谱的插画培训课程,今天教你3个维度选择一个靠谱的插画培训班! 插画培训机构课程: 1.选择插画培训班时,要先考察课程,看看课程内容是否符合自己的需求,是否有助于提高插画技术。课程设置应该灵活…...

剑指 Offer 28. 对称的二叉树
剑指 Offer 28. 对称的二叉树 难度:easy\color{Green}{easy}easy 题目描述 请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。 例如,二叉树 [1,2,2,3,4,4,3] 是对称的。 但是下…...

深入Spring底层透析后置处理器之豁然开朗篇
目录前言Spring的后置处理器Bean工厂后置处理器Bean后置处理器自定义Component实现注解开发前言 看这篇文章之前,需要了解Bean创建的过程,本篇文章是接着bean创建的基本流程的续写 Bean创建的基本过程:http://t.csdn.cn/1lK2d Spring的后置处…...

软件测试(基础定义篇)
测试基础 1、什么是软件测试?2、常见的测试分类3、质量模型 4、软件测试流程 5、测试用例 6、测试用例设计方法 )1、什么是软件测试? 1、什么是软件? 答:软件是控制计算机硬件工作的工具。 2、软件的组成? 3、什么是…...
华为OD机试 - 寻找目标字符串 | 机试题算法思路 【2023】
最近更新的博客 华为OD机试 - 简易压缩算法(Python) | 机试题算法思路 【2023】 华为OD机试题 - 获取最大软件版本号(JavaScript) 华为OD机试 - 猜字谜(Python) | 机试题+算法思路 【2023】 华为OD机试 - 删除指定目录(Python) | 机试题算法思路 【2023】 华为OD机试 …...

使用echart绘制中国地图并显示人数
文章目录引言效果如图所示vue中echarts4.9版本,地图的使用引言 在做毕设的过程中,有一个需求:根据用户的ip,在前端展示出中国地图,然后展现出每个省有多少人这样子 经过百度后,发现可以使用echart来完成该…...

Git的常用命令
1:软件安装1.1:Git下载与安装百度上搜索Git官网:https://git-scm.com/下载:https://git-scm.com/download/win下载Git安装程序,双击安装 Git-2.9.3.2-64-bit.exe配置环境变量path 使用git --version查看 git 是否安装成…...
AcWing1018.最低通行费
1018.最低通行费一个商人穿过一个 NN 的正方形的网格,去参加一个非常重要的商务活动。他要从网格的左上角进,右下角出。每穿越中间 1 个小方格,都要花费 1 个单位时间。商人必须在 (2N−1)(2−1) 个单位时间穿越出去。而在经过中间的每个小方…...

【面试题】vue中的插槽是什么?
大厂面试题分享 面试题库后端面试题库 (面试必备) 推荐:★★★★★地址:前端面试题库一、slot是什么在HTML中 slot 元素 ,作为 Web Components 技术套件的一部分,是Web组件内的一个占位符该占位符可以在后期…...
Go语言结构体struct详解,Go空结构体的这些妙用你知道吗?
本文详解了Go语言结构体的各个知识点,最后介绍了空结构体的3种妙用。希望对你有帮助。 定义 结构体,是一种自定义的数据类型,由多个数据类型组合而成。用于描述一类事物相关属性。 定义方式: type 类型名 struct {字段名 字段类…...
华为OD机试 - 航天器(Python) | 机试题+算法思路+考点+代码解析 【2023】
航天器 题目 给航天器一侧加装长方形和正方形的太阳能板(图中的斜线区域); 需要先安装两个支柱(图中的黑色竖条); 再在支柱的中间部分固定太阳能板; 但航天器不同位置的支柱长度不同; 太阳能板的安装面积受限于最短一侧的那支支柱的长度; 现提供一组整型数组的支柱高度数据;…...

短视频矩阵系统源码新发布技术方案有那几种?
短视频矩阵运营在平台政策频繁更迭的浪潮中,已成为内容分发的核心战场。行业领先者如筷子科技、云罗抖去推、超级编导等平台,其稳定高效的代发能力背后,离不开前沿技术方案的强力支撑。本文将深入剖析当前主流的六大短视频矩阵系统代发解决方…...
业态即战场:零售平台的生意模型与系统设计解构
目录 一、当我们在电商买菜、点外卖时,其实是零售业态在进化 (一)从“商场选货”到“算法推货”:零售的时代已经不同 (二)“控货”和“卖场”——零售的两种基本商业模式 二、四种经典零售业态解析:控货 vs 卖场,地面 vs 线上 (一)地面控货零售:直营模式的黄金…...
SQL Server全局搜索:在整个数据库中查找特定值的高效方法
SQL Server全局搜索:在整个数据库中查找特定值的高效方法 一、需求背景:为什么需要数据库全局搜索? 在数据库管理和开发过程中,我们经常会遇到这样的场景: 只记得某个数据值,但忘记了它所在的表或列需要…...
护网行动面试试题(2)
文章目录 51、常见的安全工具有哪些?52、说说Nmap工具的使用?53、近几年HW常见漏洞有哪些?54、HW 三(四)大洞56、获得文件读取漏洞,通常会读哪些文件57、了解过反序列化漏洞吗?58、常见的框架漏…...

OpenVINO环境配置--OpenVINO安装
TOC环境配置–OpenVINO安装 本节内容 OpenVINO 支持的安装方式有很多种,每一种操作系统以及语言都有对应的安装方法,在官网上有很详细的教程: 我们可以根据自己的需要,来点选环境配置和安装方法,然后网页会给出正…...

手撕 K-Means
1. K-means 的原理 K-means 是一种经典的无监督学习算法,用于将数据集划分为 kk 个簇(cluster)。其核心思想是通过迭代优化,将数据点分配到最近的簇中心,并更新簇中心,直到簇中心不再变化或达到最大迭代次…...
<2>-MySQL库的操作
目录 一,创建数据库 二,查看字符集和校验规则 三,修改数据库 四,删除数据库 五,备份和恢复数据库 六,查看连接 一,创建数据库 创建一个名为bin_db的数据库,并设置字符集为utf8…...

考研系列—操作系统:冲刺笔记(1-3章)
目录 第一章 计算机系统概述 1.基本概念 2.内核态和用户态 3.中断(外中断)、异常(内中断-与当前执行的) 4.系统调用 5.操作系统引导程序 2021年真题: 6.操作系统结构 大纲新增 (1)分层结构 (2)模块化 (3)外核 7.虚拟机 第二章 进程管理 1.画作业运行的顺序和甘…...

每日Prompt:每天上班的状态
提示词 一个穿着清朝官服的僵尸脸上贴着符纸,在电脑面前办公,房间阴暗,电脑桌面很乱,烟灰缸里面满是烟头...

用go从零构建写一个RPC(4)--gonet网络框架重构+聚集发包
在追求高性能的分布式系统中,RPC 框架的底层网络能力和数据传输效率起着决定性作用。经过几轮迭代优化,我完成了第四版本的 RPC 框架。相比以往版本,这一版本的最大亮点在于 重写了底层网络框架 和 实现了发送端的数据聚集机制,这…...