Linux-动静态库

news2024/12/24 8:35:59

背景

在实践中,我们一定会使用别人的库(不限于C、C++的库),在实践中,我们会使用成熟、被广泛使用的第三方库,而不会花费很多时间自己造轮子,为了能更好地使用库,就要在学习阶段了解其本质。那么对于库而言,可以从两方面认识它:

  • 如果想自己写一个库呢?(编写者)
  • 别人应该如何使用我们写的库?(使用者)
    作为C、C++的使用者,应该知道它是一门编译型语言,一堆源文件(.cpp)和一堆头文件(.h)要合在一起才能生成一个可执行程序(.exe):

预处理: 头文件展开、去注释、宏替换、条件编译等,生成.i文件

编译: 词法分析、语法分析、语义分析、符号汇总等,检查无误后将代码翻译成汇编指令,生成.s文件

汇编: 将汇编指令转换成二进制指令,生成.o文件

链接: 将生成的各个.o文件进行链接,生成可执行程序(Windows:.exe,Linux:.out)

例如: 用test1.c,test2.c以及main1.c形成可执行文件,需要先得到各个文件的目标文test1.o,test2.o以及main1.o,然后将这些目标文件链接起来,最终形成一个可执行程序。
在这里插入图片描述

实际上,对于可能频繁用到的源文件,比如这里的test1.c test2.c 可以将他们的目标文件test1.o,test2.o进行打包,之后需要用到这两个目标文件就可以直接链接这个包当中的目标文件即可,上面的打包就可以称为一个库。库的本质就是一堆.O文件集合,库的文件当中并不包含主函数而只是包含了大量写好的方法以供调用,因此,我们说动静态库是可执行程序的"半成品" -》所以库中没有main函数


认识静态库

站在编写者角度:生成静态库
以下面四个文件和一个main.c文件为例,演示其打包为库的过程

在这里插入图片描述
Add.c

  1 int Add(int x, int y)
  2 {
  3   return x + y;
  4 }                                                                                                         

Add.h

extern int Add(int x, int y);

Sub.c

  1 int Sub(int x, int y)
  2 {
  3   return x - y;
  4 }                                                                                                         

Sub.h

extern int Sub(int x, int y);

在这里插入图片描述

gcc -o Test Add.c Sub.c main.c
//我们使用 gcc -o 选项将所有的源文件进行编译,形成可执行

在这里插入图片描述

我们不建议上述方法,建议是将所有的源文件编译成.o文件,再将所有的.o文件链接形成我们的可执行
在这里插入图片描述

在 Makefile 中,$< 是一个自动化变量,表示规则中的第一个依赖文件(prerequisite)。
通过使用 $<,你可以方便地引用规则中的第一个依赖文件,使规则更加灵活和通用。

在这里插入图片描述
总结上面的操作也就是

gcc Add.o Sub.o main.o -o Test
//将别人的.o文件与自己写的main.c文件形成的.o文件链接起来,形成可执行,这个就是静态库的打包

通过上面的例子我们知道,需要将生成的所有目标文件和main.o文件链接才能生成可执行程序,但是除了main.o之外的.o文件都太分散了,用起来很麻烦(当然可以通过Makefile简化步骤),给别人使用也不太方便,还容易缺失,所以将它们打包。而将目标文件打包的结果就是一个静态库

使用ar指令将所有目标文件打包为静态库

ar 命令是 GNU Binutils 的一员,可以用来创建、修改静态库,也可以从静态库中提取单个模块。它可以将一个或多个指定的文件并入单个写成 ar 压缩文档格式的压缩文档文件。
在这里插入图片描述

例如,将Add.o和 Sub.o打包:

ar -rc libtest.a Add.o Sub.o

在这里插入图片描述
那么上面这个文件夹中就只有打包的库文件和头文件(因为头文件是公开的,我们通常可以看到stdio.h里面的内容)

在这里插入图片描述
但是,我们使用gcc编译的时候为什么报链接错误呢?

因为自己写的库是第三方库,gcc不认识,所以需要指定-l链接我们自己写的第三方库

gcc main.c -ltest

在这里插入图片描述
但是链接的时候又出现错误,不能找到这个库,所以需要提供一个选项-L,说明这个库是在哪个路径底下

gcc main.c -ltest -L.

在这里插入图片描述

站在使用者角度:打包静态库
我们将头文件和.o文件分别放在一个文件夹下的两个文件夹中
在这里插入图片描述
然后将这个文件夹的压缩包给别人,用的时候就是将include里面的内容拷贝到/user/include目录底下,将lib里面的内容拷贝到/lib64/目录下。或者指定库的路径

指定库的路径

指定库的路径


动态库

依然使用之前的四个文件和一个main.c文件示例。

  1. 生成所有源文件对应的目标文件
    gcc 需要增加-fPIC选项(position independent code):位置无关码
gcc -fPIC -c Add.c
gcc -fPIC -c Print.c

位置无关代码对于 gcc 来说:

  • -fPIC作用于编译阶段,告诉编译器产生与位置无关的代码,此时产生的代码中没有绝对地址,全部都使用相对地址,从而代码可以被加载器加载到内存的任意位置都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。
  • 如果不加-fPIC选项,则加载. so 文件的代码段时,代码段引用的数据对象需要重定位,重定位会修改代码段的内容,这就造成每个使用这个. so 文件代码段的进程在内核里都会生成这个. so 文件代码段的拷贝,并且每个拷贝都不一样,这样就和动态库一样占用内存了,具体取决于这个. so 文件代码段和数据段内存映射的位置。
  • 不加-fPIC编译生成的. so 文件是要在加载时根据加载到的位置再次重定位的,因为它里面的代码 BBS 位置无关代码。如果该. so 文件被多个应用程序共同使用,那么它们必须每个程序维护一份. so 的代码副本 (因为. so 被每个程序加载的位置都不同,显然这些重定位后的代码也不同,当然不能共享)。
    我们总是用-fPIC来生成. so,但从来不用-fPIC来生成. a。但是. so 一样可以不用-fPIC选项进行编译,只是这样的. so 必须要在加载到用户程序的地址空间时重定向所有表目。
  1. 使用 gcc 的 -shared 选项将所有目标文件打包为一个动态库
gcc -shared -o libtest.so Add.o Print.o

在这里插入图片描述


动态库的使用

对于动态库,即使显式地提示 gcc main.c 中调用了第三方库中的函数,也会因为找不到库而编译错误。

例如,仍然使用 gcc 的三个选项说明编译 main.c 需要的库文件和头文件,以及应该链接哪个库。注意,此时的工作目录依然是:
在这里插入图片描述

gcc main.c -I./mylib/include -L./mylib/lib -ltest

在这里插入图片描述
不同于静态库,这里动态库生成的可执行程序并不能运行。

在这里插入图片描述
在这里插入图片描述

  • 拷贝到系统目录
    sudo cp mylib/lib/libtest.so /lib64
  • 建立动态库的软链接
ln -s mylib/lib/libtest.so libtest.so

在这里插入图片描述

  • 更改 LD_LIBRARY_PATH环境变量
    LD_LIBRARY_PATH是程序运行动态查找库时所要搜索的路径,我们只需将动态库所在的目录路径添加到LD_LIBRARY_PATH环境变量中,告诉系统程序依赖的动态库所在的路径:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/root/2024_1_28/dy_test/my_lib/lib

注意要用:隔开,否则会覆盖原来的环境变量。但是这个方法是临时的,因为这个环境变量是内存级别的环境变量,机器会在下次登录时清理。

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

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

相关文章

[嵌入式系统-4]:龙芯1B 开发学习套件-1-开发版硬件介绍

目录 前言&#xff1a; 一、龙芯 1B 开发学习套件简介 1.1 概述 二、龙芯1B 200开发板硬件组成与接口介绍 2.1 概述 2.2 核心板 2.2.1 CPU 2.2.2 什么是核心板 2.2.3 龙芯1B 200核心板 2.2.4 龙芯1B核心板的接口定义 2.3 开发板 2.3.1 龙芯1B0200开发板 2.3.2 龙芯…

Linux使用匿名管道实现进程池得以高效通信

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;Nonsense—Sabrina Carpenter 0:50━━━━━━️&#x1f49f;──────── 2:43 &#x1f504; ◀️ ⏸ ▶️ …

Redis 持久化详解:RDB 与 AOF 的配置、触发机制和实际测试

什么是持久化&#xff1f; 就是 Redis 将内存数据持久化到硬盘&#xff0c;避免从数据库恢复数据。之所以避免从数据库恢复数据是因为后端数据通常有性能瓶颈&#xff0c;大量数据从数据库恢复可能会给数据库造成巨大压力。 Redis 持久化通常有 RDB 和 AOF 两种方式&#xff…

​ PaddleHub 首页图像 - 文字识别chinese_ocr_db_crnn_server​

PaddleHub 便捷地获取PaddlePaddle生态下的预训练模型&#xff0c;完成模型的管理和一键预测。配合使用Fine-tune API&#xff0c;可以基于大规模预训练模型快速完成迁移学习&#xff0c;让预训练模型能更好地服务于用户特定场景的应用 零基础快速开始WindowsLinuxMac Paddle…

算法学习系列(三十):高斯消元解线性方程组

目录 引言一、高斯消元法二、代码模板三、例题 引言 这个高斯消元法主要是线性代数的一些东西&#xff0c;然后步骤跟上课讲的步骤是一样的&#xff0c;只不过使用代码实现了而已&#xff0c;在竞赛和笔试中还是有出现的可能的&#xff0c;所以掌握它还是很重要的&#xff0c;…

「 典型安全漏洞系列 」07.OS命令注入详解

引言&#xff1a;什么是操作系统命令注入&#xff0c;如何防御和利用漏洞&#xff1f; 1. 简介 操作系统命令注入&#xff08;OS command injection&#xff09;是一种Web安全漏洞&#xff0c;允许攻击者在运行应用程序的服务器上执行任意操作系统&#xff08;OS&#xff09;命…

专栏:数据库、中间件的监控一网打尽

前言 对于数据库、中间件的监控&#xff0c;目前社区里最为完善的就是 Prometheus 生态的各个 Exporter&#xff0c;不过这些 Exporter 比较分散&#xff0c;不好管理&#xff0c;如果有很多目标实例需要监控&#xff0c;就要部署很多个 Exporter&#xff0c;要是能有一个大一…

基于springboot的房屋交易系统

文章目录 项目介绍主要功能截图&#xff1a;部分代码展示设计总结项目获取方式 &#x1f345; 作者主页&#xff1a;超级无敌暴龙战士塔塔开 &#x1f345; 简介&#xff1a;Java领域优质创作者&#x1f3c6;、 简历模板、学习资料、面试题库【关注我&#xff0c;都给你】 &…

【C语言/数据结构】排序(快速排序及多种优化|递归及非递归版本)

&#x1f308;个人主页&#xff1a;秦jh__https://blog.csdn.net/qinjh_?spm1010.2135.3001.5343&#x1f525; 系列专栏&#xff1a;《数据结构》https://blog.csdn.net/qinjh_/category_12536791.html?spm1001.2014.3001.5482 ​​​​ 目录 交换排序 快速排序 hoare版代…

【CanvasKeyFrames - HTML5 Canvas 图片序列帧播放工具】

前言 一、CanvasKeyFrames 是什么&#xff1f; 用来做canvas动画的工具。 二、使用步骤 效果如图&#xff1a;上下波动的线条 1.引入库 代码如下&#xff08;示例&#xff09;&#xff1a; 在html中引入&#xff1a; <script src"canvas-keyframes.js"><…

基于springboot药房管理系统源码和论文

伴随着全球信息化发展&#xff0c;行行业业都与计算机技术相衔接&#xff0c;计算机技术普遍运用于药房管理行业。实施计算机系统来管理可以降低逍遥大药房管理成本&#xff0c;使整个逍遥大药房行业的发展有显著提升。 本论文主要面向逍遥大药房管理中出现的一些常见问题&…

多符号表达式的共同子表达式提取教程

生成的符号表达式&#xff0c;可能会存在过于冗长的问题&#xff0c;且多个符号表达式中&#xff0c;有可能存在相同的计算部分&#xff0c;如果不进行处理&#xff0c;计算过程中会导致某些算式计算多次&#xff0c;从而影响计算效率。 那么多个符号表达式生成函数时&#xf…

深信服技术认证“SCSA-S”划重点:基线管理与安全配置

为帮助大家更加系统化地学习网络安全知识&#xff0c;以及更高效地通过深信服安全服务认证工程师考核&#xff0c;深信服特别推出“SCSA-S认证备考秘笈”共十期内容&#xff0c;“考试重点”内容框架&#xff0c;帮助大家快速get重点知识~ 划重点来啦 *点击图片放大展示 深信服…

Java 集合 03 综合练习(黑马)

练习1、 ps&#xff1a;输出结果为地址值&#xff0c;是因为在输出对象时&#xff0c;默认调用了对象的toString()方法。在没有重写toString()方法的情况下&#xff0c;toString()方法返回的是对象的地址值。如果想要输出对象的属性值而不是地址值&#xff0c;可以重写toString…

记一个有趣的bug:panic执行时机

其实这并不是一个Bug&#xff0c;只是在收拢一个后端模块的错误日志和错误码时发现在请求成功时始终会多一条错误日志 最开始大概长这样。msg在算子不报错误的情况下不被赋值&#xff0c;所以这里不会打印错误日志&#xff0c;后面收拢了该模块的错误码&#xff0c;导致msg在…

爬虫学习笔记-xpath的基本使用

html示例 基本使用 #导入包 #pip install lxmlfrom lxml import etree# xpath解析 # 1.本地文件 etree.parse # 2.服务器响应的数据 etree.HTML()tree etree.parse(baidu.html) # 获取所有的ul下的li标签 l1 tree.xpath(//ul/li) print(l1) print(len(l1))# 获取所有带有id的…

js数组/对象的深拷贝与浅拷贝

文章目录 一、js中的深拷贝和浅拷贝二、浅拷贝1、Object.assign()2、利用es6扩展运算符&#xff08;...&#xff09; 二、深拷贝1、JSON 序列化和反序列化2、js原生代码实现3、使用第三方库lodash等 四、总结 一、js中的深拷贝和浅拷贝 在JS中&#xff0c;深拷贝和浅拷贝是针对…

python零散学习

文章目录 __name__和__main__关系变量/函数的命名规则&#xff08;下划线&#xff09;python&#xff1a;List列表、Tuple元组、Dic字典%占位符使用class相关python常见内置类属性self python内置函数isinstance&#xff08;object,classtype&#xff09;globals() 高级语法相关…

干货分享 | TSMaster 信号映射的配置方法

TSMaster信号映射模块可以将数据库变量映射为系统变量&#xff0c;经过映射后的系统变量就等同于数据库中的变量&#xff0c;该系统变量的读写操作就等同于读写数据库变量。其在系统软件中的位置如下图所示&#xff1a; 信号映射模块设计的目的&#xff0c;就是为了实现上层应用…

新建VM虚拟机-安装centOS7-连接finalshell调试

原文 这里有问题 首先进入/etc/sysconfig/network-scripts/目录 cd /etc/sysconfig/network-scripts/ 然后编辑文件 ifcfg-ens33 vi ifcfg-ens33