当前位置: 首页 > article >正文

Linux基础IO----动态库与静态库

什么是库?

库是由一些.o文件打包在一起而形成的可执行程序的半成品。

如何理解这句话呢?

首先,一个程序在运行前需要进行预处理、编译、汇编、链接这几步。

预处理: 完成头文件展开、去注释、宏替换、条件编译等,最终形成xxx.i文件。
编译: 完成词法分析、语法分析、语义分析、符号汇总等,检查无误后将代码翻译成汇编指令,最终形成xxx.s文件。
汇编: 将汇编指令转换成二进制指令,最终形成xxx.o文件。
链接: 将生成的各个xxx.o文件进行链接,最终形成可执行程序。

在链接之前的这些.o文件就是上文提到的被打包进库里的文件。

那么为什么要对这些文件进行打包呢?

拿我们平时常用的库举例,我们写程序所用到的输入输出函数,比如prinf、scanf,这些函数都不是我们自己去实现的,为什么却能为我们所用呢?原因就是这些函数是在库里的程序实现的,不需要我们手动重新再去“造轮子”,拿来就直接能用,库里还有很多方便使用的函数,在程序里包含不同的库,能使用的库函数就越多越方便我们实现程序。所以库存在的意义就是帮我们把基础的常用的函数等打包到一起直接提供我们使用。所以我们又说库是可执行程序的“半成品”。

认识动静态库

编写一个简单的程序:

能够正常打印处hello lib是因为我们的库中已经有了printf函数的实现,在gcc生成可执行程序时,将C标准库链接到我们的程序里了。接下来我们通过ldd+文件名命令查看一个可执行程序链接了哪些库吧:

注意:ldd命令只能查看可执行程序依赖的库和动态库的依赖库。

 其中lib.c.so.6就是该可执行程序依赖的库文件,我们通过ls命令可以发现lib.c.so.6是一个软链接:

在Linux中,动态库的后缀是.so  静态库的后缀是.a

去掉前缀lib和后缀.so  .a和后面的版本号就是库的名字,在这里就是c

在默认情况下gcc 或者g++编译器都是默认动态连接库的,若想进行静态链接需要加上-static选项:

可以发现静态连接库的可执行程序的大小非常大,这是因为静态链接就是把静态库直接整个加入到你的可执行程序里的,所以这个程序执行就不需要依赖仍和库。

 

动静态库的特征

静态库的特征

静态库是程序在编译链接的时候把库的代码直接复制到可执行程序里,导致文件变大,并且程序在执行的时候不在依赖静态库。

优点:静态链接库的程序运行不再依赖静态库。

缺点:程序占用大量空间,如果有多个程序都是静态链接的同一个库就会有很多重复代码。

动态库的特征

动态库是在程序运行的时候才去链接相应代码的,多个程序共享库内的代码,所以动态库也叫共享库,能够大大节省内存。链接时将库映射到进程的进程地址空间的共享区中,当进程调用库内的函数时就可以直接去共享区内找。

优点:节省空间,内存中不会存在很多重复的代码。

缺点:程序必须以来动态库运行,如果动态库找不到了程序就运行不了。

静态库的打包和使用

为了更好的理解静态库,下面我们将自己写的方法打包进一个我们自己的静态库中。

add.h add.c:

#pragma onceextern int my_add(int x, int y);
#include "add.h"int my_add(int x, int y)
{return x + y;
}

 

sub.h sub.c:

#pragma onceextern int my_sub(int x, int y);
#include "add.h"int my_sub(int x, int y)
{return x - y;
}

打包: 

 第一步:让源文件生成.o文件

第二步:用ar命令将 .o文件打包

ar命令是gnu的归档工具,常用于将目标文件打包为静态库,下面我们使用ar命令的-r选项和-c选项进行打包。

  • -r(replace):若静态库文件当中的目标文件有更新,则用新的目标文件替换旧的目标文件。
  • -c(create):建立静态库文件。

此外,我们可以用ar命令的-t选项和-v选项查看静态库当中的文件。

  • -t:列出静态库中的文件。
  • -v(verbose):显示详细的信息。

 第三步:将头文件和生成的静态库组织起来

当我们把自己的库给别人用的时候,实际上需要给别人两个文件夹,一个文件夹下面放的是一堆头文件的集合,另一个文件夹下面放的是所有的库文件。

因此,在这里我们可以将add.h和sub.h这两个头文件放到一个名为include的目录下,将生成的静态库文件libcal.a放到一个名为lib的目录下,然后将这两个目录都放到mathlib下,此时就可以将mathlib给别人使用了。

 

使用:

创建下面程序,包含头文件add.h:

#include <stdio.h>
#include <add.h>int main()
{int a = 10, b = 20;int sum = my_add(a, b);printf("%d + %d = %d\n",a,b,sum);return 0;
}

 方法一:使用gcc编译main.c生成可执行程序时需要携带三个选项:

  • -I:指定头文件搜索路径。
  • -L:指定库文件搜索路径。
  • -l:指明需要链接库文件路径下的哪一个库。

gcc main.c -I./mathlib/include -L./mathlib/lib -lcal

根据命名规则我们的库名字就是cal,所以 最后一个选项是cal

 说明:

  • 编译器不知道你自己写的头文件add.h的位置,所以编译的时候需要你指出来,同时还需要库文件的路径来定位库。
  • 实际中,在库文件的lib目录下可能会有大量的库文件,因此我们需要指明需要链接库文件路径下的哪一个库。库文件名去掉前缀lib,再去掉后缀.so或者.a及其后面的版本号,剩下的就是这个库的名字。
  • -I-L-l这三个选项后面可以加空格,也可以不加空格。

方法二:把头文件和库文件拷贝到系统路径下

为什么用C语言自带的库不是需要这样大费周章的写路径,其实是因为编译器找库和头文件首先是去系统路径下找的,所以不需要直接指出,同时gcc是用来编译C程序的所以默认找的是c库所以也不用指明库的名字

可以尝试:

sudo cp mathlib/lib/libcal.a /lib64/

sudo cp mathlib/include/*

将你的库加入系统路径,需要注意的是就算把文件拷贝到系统路径下,使用gcc时仍需指定库名。

扩展:
实际上我们拷贝头文件和库文件到系统路径下的过程,就是安装库的过程。但并不推荐将自己写的头文件和库文件拷贝到系统路径下,这样做会对系统文件造成污染。

动态库的打包和使用

打包:

还是以刚才的四个文件举例:

第一步:让源文件生成对应的.o文件

此时用源文件生成目标文件时需要携带-fPIC选项:

  • -fPIC(position independent code):产生位置无关码。

fPIC的作用:

  • 实现内存地址无关性
    • 使用-fPIC编译的代码,不依赖与在内存中的具体位置,可在不同内存地址上正确运行。动态链接库被不同程序加载时,可能加载到不同内存地址,位置无关代码可以适应这种情况。
  • 支持动态库共享
    • 允许多个进程共享动态库的单个副本 。若不使用-fPIC,加载动态库代码段时,因代码含绝对地址,需重定位,这会使每个使用该库的进程在内核里生成各自的代码段副本,造成内存浪费
  • 提高程序灵活性与可移植性
    • 使动态链接库能在不同环境、不同内存布局下加载和使用,无需因内存地址差异重新编译 

第二步:使用-shared选项将所有目标文件打包为动态库

gcc -shared -o libcal.so add.o sub.o

第三步:将头文件和生成的动态库组织起来 

和静态库一样,将头文件和库文件整合到一起一个放include一个放lib目录

 

使用:

还是用main.c来演示:

#include <stdio.h>
#include <add.h>int main()
{int x = 20;int y = 10;int z = my_add(x, y);printf("%d + %d = %d\n", x, y, z);return 0;
}

说明一下,使用该动态库的方法与刚才我们使用静态库的方法一样,我们既可以使用 -I-L-l这三个选项来生成可执行程序,也可以先将头文件和库文件拷贝到系统目录下,然后仅使用-l选项指明需要链接的库名字来生成可执行程序,下面我们仅以第一种方法为例进行演示。

gcc main.c -I./mlib/include -L./mlib/lib -lcal

编译成功但是执行失败,这是为什么呢? 

在编译时通过 -L./mlib/lib 指定了动态库的搜索路径,但这只对编译链接阶段有效,而运行阶段的动态库搜索需要单独配置。

方法一:拷贝.so文件到系统共享库路径下

我们直接将库文件拷贝到系统共享的库路径下,这样一来系统就能够找到对应的库文件了。

 sudo cp mlib/lib/libcal.so /lib64

方法二:更改LD_LIBRARY_PATH

LD_LIBRARY_PATH是程序运行动态查找库时所要搜索的路径,我们只需将动态库所在的目录路径添加到LD_LIBRARY_PATH环境变量当中即可。

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/YOURPATH/libtest/mlib/lib

 但是这个环境变量的修改时暂时的,下次重启就失效了。

相关文章:

Linux基础IO----动态库与静态库

什么是库&#xff1f; 库是由一些.o文件打包在一起而形成的可执行程序的半成品。 如何理解这句话呢&#xff1f; 首先&#xff0c;一个程序在运行前需要进行预处理、编译、汇编、链接这几步。 预处理&#xff1a; 完成头文件展开、去注释、宏替换、条件编译等&#xff0c;最终…...

LeetCode百题刷004(哈希表优化两数和问题)

遇到的问题都有解决的方案&#xff0c;希望我的博客可以为你提供一些帮助 一、哈希策略优化两数和问题 题目地址&#xff1a;1. 两数之和 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/two-sum/description/ 思路分析&#xff1a; 题目要求在一个整型…...

解析Java String.getBytes()编码与new String()解码的字符集转换机制

引言 在Java开发中&#xff0c;字符编码与解码是处理文本数据的基础操作&#xff0c;但稍有不慎就会导致乱码问题。理解字符串在内存中的存储方式以及如何正确使用编码转换方法&#xff0c;是保证跨平台、多语言兼容性的关键。本文将通过编码与解码的核心方法、常见问题场景及…...

从万有引力到深度学习,认识模型思维

从万有引力到深度学习&#xff0c;认识模型思维 引言 从牛顿发现万有引力定律到现代深度学习的崛起&#xff0c;“模型思维”始终是人类理解世界、解决问题的核心工具。它不仅是科学研究的基石&#xff0c;更是技术创新的底层逻辑。本文将从科学史、技术应用、认知效率等角度…...

2022 年 9 月青少年软编等考 C 语言八级真题解析

目录 T1. 道路思路分析T2. 控制公司思路分析T3. 发现它,抓住它思路分析T4. 青蛙的约会思路分析T1. 道路 题目链接:SOJ D1216 N N N 个以 1 ∼ N 1 \sim N 1∼N 标号的城市通过单向的道路相连,每条道路包含两个参数:道路的长度和需要为该路付的通行费(以金币的数目来表示…...

FPGA通信之VGA与HDMI

文章目录 VGA基本概念&#xff1a;水平扫描&#xff1a;垂直扫描&#xff1a; 时序如下&#xff1a;端口设计疑问为什么需要输出那么多端口不输出时钟怎么保证电子枪移动速度符合时序VGA转HDMI 仿真电路图代码总结&#xff1a;VGA看野火电子教程 HDMITMDS传输原理为什么使用TMD…...

Leetcode百题斩-二叉树

二叉树作为经典面试系列&#xff0c;那么当然要来看看。总计14道题&#xff0c;包含大量的简单题&#xff0c;说明这确实是个比较基础的专题。快速过快速过。 先构造一个二叉树数据结构。 public class TreeNode {int val;TreeNode left;TreeNode right;TreeNode() {}TreeNode…...

修改 K8S Service 资源类型 NodePort 的端口范围

在 Kubernetes 中&#xff0c;Service 类型为 NodePort 时&#xff0c;默认分配的端口范围为 30000~32767。如果你希望使用自定义端口&#xff08;如 8080、8888 等&#xff09;&#xff0c;就需要修改 kube-apiserver 的默认配置。 本文将详细介绍如何修改 Kubernetes 中 Nod…...

ACM Latex模板:合并添加作者和单位

目录&#xff1a; 1.ACM会议论文Latex模板&#xff0c;逐个添加作者和单位&#xff1a; 1&#xff09;Latex&#xff1a; 2&#xff09;效果&#xff1a; 2. ACM会议论文Latex模板&#xff0c;合并添加作者和单位&#xff1a; 1&#xff09;Latex&#xff1a; 2&#x…...

爬虫IP代理技术深度解析:场景、选型与实战应用

目录 一、代理IP的核心技术架构 二、典型应用场景技术解析 场景1&#xff1a;电商价格监控系统 场景2&#xff1a;社交媒体舆情分析 场景3&#xff1a;金融数据采集 三、代理IP选型方法论 1. 性能评估矩阵 2. 成本优化模型 3. 风险管控体系 四、未来技术演进方向 五、…...

将MCP(ModelContextProtocol)与Semantic Kernel集成(调用github)

文章目录 将MCP&#xff08;ModelContextProtocol&#xff09;与Semantic Kernel集成&#xff08;调用github&#xff09;一、模型上下文协议&#xff08;MCP&#xff09;简介1.1 简介1.2 示例 二、集成步骤2.1 安装环境依赖2.2 构建语义内核&#xff08;Kernel&#xff09;2.3…...

游戏引擎学习第311天:支持手动排序

仓库: https://gitee.com/mrxiao_com/2d_game_7(已满) 新仓库: https://gitee.com/mrxiao_com/2d_game_8 回顾并为今天的内容定下基调 我们接下来要继续完成之前开始的工作&#xff0c;上周五开始的部分内容&#xff0c;虽然当时对最终效果还不太确定&#xff0c;但现在主要任…...

LambdaQueryWrapper、MybatisPlus提供的基本接口方法、增删改查常用的接口方法、自定义 SQL

DAY26.2 Java核心基础 MybatisPlus提供的基本接口方法 分页查询 导入依赖springboot整合Mybatis-plus <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.3</version&g…...

深度学习---可视化

模型可视化 深度学习模型可视化是理解、调试和优化模型的关键技术&#xff0c;涉及模型结构、参数、层输出、数据流动、训练过程等多维度分析。 一、可视化的核心作用 模型理解 解析复杂模型的网络架构&#xff08;如CNN的层级连接、Transformer的注意力机制&#xff09;。揭…...

军事大模型及其应用分析

一、军事大模型概述 在军事智能化浪潮下&#xff0c;大模型技术加速从理论迈向实战&#xff0c;成为重塑军事决策体系的核心力量&#xff0c;推动军事体系数字工程进入新阶段。 美国依托成熟的商业科技生态&#xff0c;率先推进大模型军事应用。Palantir 公司的 AIP 军事智能…...

c++算法题

题目 字符串的替换操作 replace(String &s, String &t, String &v) 是指&#xff1a; 若t是s的子串&#xff0c;则用串v替换串t在串s中的所有出现&#xff1b;若t不是s的子串&#xff0c;则串s不变。例如&#xff0c;若串s为“aabbabcbaabaaacbab”&#xff0c;串…...

云原生安全 SaaS :从基础到实践

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 1. 基础概念 什么是 SaaS&#xff1f; SaaS&#xff08;Software as a Service&#xff0c;软件即服务&#xff09;是一种基于云计算的软件交付模式。用…...

《Drain日志解析算法》论文阅读笔记

这篇文档介绍了一种名为Drain的在线日志解析方法&#xff0c;它采用固定深度的解析树进行流式日志处理 [cite: 1, 6]。 摘要 日志记录了宝贵的系统运行时信息&#xff0c;广泛应用于Web服务管理中 [cite: 1]。典型的日志分析过程首先需要解析原始日志消息&#xff0c;因为它们…...

MMAction2重要的几个配置参数

embed_dims&#xff08;全称 embedding dimensions&#xff09;是指每个 patch&#xff08;块&#xff09;或特征的通道数/维度&#xff0c;是 Transformer 或 Swin Transformer 等模型中最核心的特征表示维度。 embed_dims 必须能被 num_heads 整除 具体解释 在 Swin Transfo…...

Windows系统如何查看ssh公钥

很多人只是一味的为拿到ssh公钥而努力&#xff0c;往往却会忽略了ssh公钥与私钥背后的作用。 咱们在这里会花两分钟。 一分钟速通概念&#xff0c;一分钟教会你如何获取。 一分钟速通概念&#xff1a; 如何生成&#xff1a; SHH 公钥 与 私钥 是基于非对称加密算法&#xff…...

UniApp+Vue3微信小程序二维码生成、转图片、截图保存整页

二维码生成工具使用uqrcode/js&#xff0c;版本4.0.7 官网地址&#xff1a;uQRCode 中文文档&#xff08;不建议看可能会被误导&#xff09; 本项目采用了npm引入方式&#xff0c;也可通过插件市场引入&#xff0c;使用上会略有不同 准备工作&#xff1a; 安装&#xff1a;pnpm…...

8.2 线性变换的矩阵

一、线性变换的矩阵 本节将对每个线性变换 T T T 都指定一个矩阵 A A A. 对于一般的列向量&#xff0c;输入 v \boldsymbol v v 在空间 V R n \pmb{\textrm V}\pmb{\textrm R}^n VRn 中&#xff0c;输出 T ( v ) T(\boldsymbol v) T(v) 在空间 W R m \textrm{\pmb W}\…...

【2025】嵌入式软考中级部分试题

大题: 大模型 神经网络 机器学习 深度学习的包含关系 不一定对 订阅-发布者模型 发布/订阅模式特点: ①解耦:发布者和订阅者之间没有直接联系,它们通过中间的消息代理(如消息队列或事件总线)进行通信。这种解耦使得系统更加灵活,可以独立地添加或移除发布者和订阅者…...

Antd中Upload组件封装及使用:

1.Upload上传组件功能: 文件校验 : 文件格式校验/文件大小校验/上传文件总个数校验 相关功能 : 拖拽功能/上传到远程(七牛)/文件删除及下载 2.组件效果展示: 3.疑难点及解决方案: Promise.all多文件并行上传到远程(七牛云): (1)在beforeUpload钩子函数中获取token (2)循环fi…...

Linux环境基础开发工具->vim

引入&#xff1a;vim是什么&#xff1f; vs叫作继承开发环境&#xff0c;我们可以在里面编辑代码&#xff0c;调式代码&#xff0c;运行代码....这种叫集成开发环境&#xff1b;而vim只用来编辑代码&#xff0c;也就是类似于在windows上打开一个记事本来写代码的操作 集成开发…...

跳板问题(贪心算法+细节思考)

首先直接看题&#xff1a; 这题直接贪心其实问题不大&#xff1a; 下面先展示我的一个错误代码&#xff1a; # include<iostream> # include<vector> # include<algorithm>using namespace std;int main() {int N,M;cin>>N>>M;vector<vecto…...

RuoYi前后端分离框架集成UEditorPlus富文本编辑器

一、背景 采用若依框架搭建了一个小型的电子书项目,项目前端、后端、移动端就一人,电子书的章节内容是以富文本内容进行呈现的,产品设计人员直接给了一个第三方收费的富文本编辑器截图放到开发文档中,提了一沓需求点,概况下来就是要做成下图中的样子。作为一个后端开发人…...

IPD流程落地:项目任务书Charter开发

目录 简介 第一个方面&#xff0c;回答的是Why的问题。 第二点&#xff0c;要回答做什么的问题&#xff0c;也就是产品定义What的问题。 第三点就是要回答执行策略与计划的问题&#xff0c;也就是How、When、Who的问题。 第四点是对上述这些分析的总结分析&#xff0c;要为…...

Vue 2 混入 (Mixins) 的详细使用指南

1.基本概念 混入 (Mixins) 是 Vue 2 中用于组件代码复用的重要特性&#xff0c;它允许你将可复用的功能分发到多个组件中。 混入是一种灵活的代码复用方式&#xff0c;可以包含任意组件选项&#xff08;data、methods、生命周期钩子等&#xff09;。当组件使用混入时&#xff…...

day020-sed和find

文章目录 1. sed1.1 查找、过滤文本1.1.1 根据行号取行1.1.2 根据行号取范围1.1.3 过滤出指定行1.1.4 过滤出指定范围内容 1.2 替换文件内容1.2.1 将文件中虚拟用户命令解释器替换成/bin/bash1.2.2 修改原文件并备份1.2.3 为每行开头加上# 1.3 反向引用&#xff08;后向引用&am…...