动静态库-Linux 学习
在软件开发中,程序库是一组预先编写好的程序代码,它们存储了常用的函数、变量和数据结构等。这些库可以帮助开发者节省大量的时间和精力,避免重复编写相同的代码。当我们在 Linux 系统中开发程序时,经常会用到两种类型的程序库:静态库和动态库。
- 静态库 (
.a):静态库是指在程序编译时,将库文件中的代码直接复制到可执行文件中。这意味着当程序运行时,库文件中的代码已经包含在可执行文件中,不需要在运行时进行加载。 - 动态库 (
.so):动态库是指在程序运行时才加载的库文件。程序本身不包含库文件的代码,而是通过链接到动态库来调用其中的函数和数据结构等。动态库通常以共享库的形式存在,多个程序可以共享一个动态库。
从库的制作者角度
静态库
我们可以自己尝试写一个简单的计算程序来实现简单的加减乘除功能。
我们可以先创建以下文件:
加法:Add.c , Add.h
减法:Sub.c , Sub.h
乘法:Mul.c , Mul.h
除法:Div.c , Divh

如果我们要上面的文件形成一个库,我们是不能在上面的这些文件中写main函数的,因为库中是没有main 函数的,我们也不能把main 函数打入库中。
// Add.h
#pragma once // 防止头文件被重复包含
#include <stdio.h>
int Add(int,int);
----------------------------
// Add.c
#include "Add.h"
int Add(int x, int y)
{return x + y;
}
// Sub.h
#pragma once
#include <stdio.h>
int Sub(int,int);
----------------------------
// Sub.c#include "Sub.h"
int Sub(int x, int y)
{return x - y;
}
//Mul.h
#pragma once
#include <stdio.h>
int Mul(int,int);
----------------------------
// Mul.c#include "Mul.h"
int Mul(int x, int y)
{return x * y;
}
//Div.h
#pragma once
#include <stdio.h>
int Div(int,int,int*);
------------------------------
// Div.c#include "Div.h"
int Div(int x, int y, int *code)
{*code = 0;if (y == 0){*code = -1;return -1; }return x / y;
}
我们现在要将上面的一堆的头文件 和 源文件 形成静态库
为 我们的方法进行测试,我们可以建立一个叫TestMain.c 的文件。
// TestMain.c
#include "Add.h"
#include "Sub.h"
#include "Mul.h"
#include "Div.h"int x = 20;int y = 10;printf("%d + %d = %d\n",x, y, Add(x,y));printf("%d - %d = %d\n",x, y, Sub(x,y));printf("%d * %d = %d\n",x, y, Mul(x,y));
我们可以运行一下上面的测试程序TestMain.c,不过我们要先进行编译:
// Linux 系统 gcc -o test Add.c Sub.c Mul.c Div.c TestMain.c// 我们在编译的时候没有加上头文件,因为当前的头文件和源文件是在同一个路径下的,所以我们不用加上头文件。
上面我们是把所有的源文件都进行了编译的,其实如果我们要形成一个可执行程序,我们不太建议将所有的源文件都直接进行编译,因为我们一旦这样做,每一个源文件都要进行预处理,编译,汇编,链接。所以一般在面对这样的多文件项目时我们一般都建议把这样的源文件编译成.o 文件。编译成.o 文件之后,然后我们在把所有的.o 文件进行对应的链接 形成一个可执行。
.c–(预处理,编译,汇编)—>.o----(链接)----> 可执行
// 介绍一下`-c` 的选项。
gcc -c test.c // 在 test.c形成可执行前(即:链接前) 终止,最终会生成一个`.o` 的文件,默认是同名的`test.o`
所以如果我们把上面文件中的TestMain.o 去掉,为什么要去掉呢?因为如果我们要做一个静态库,库中是不能有main 函数的,main 函数只能是用这个库的用户写的。这样一来就只剩下Add.0,Sub.o,Mul.o,Div.o 了,我们只需要对Add.0,Sub.o,Mul.o,Div.o 这些.o 文件进行打包,以后如果某个用户想要用到这些加减乘除的方法,只需要将自己写的main 函数编译成xxx.o 文件,然后再和打包好的文件中的.o 文件进行链接就好了。
生成静态库
那我们如何对我们的.o文件进行打包呢?
ar 命令
ar命令是一个把所有的.o 文件打包形成我们对应的库文件的过程。
ar -rc libmymath.a add.o sub.o
ar是gnu归档工具,选项:rc表示(replace and create),他的意思是:把所有的.o文件打包生成一个.a 文件,如果存在就替换(replace)如果不存在就创建(create)。
库的名字要以lib 开头,以.a 结尾,所以上面我们的库是mymath ,但是加上前缀和后缀之后就是:libmymath.a 了。
静态库的原理就是将库中的源代码直接翻译成
.o目标二进制文件,然后打包
动态库
一、什么是动态库?
动态库,也叫共享库(Shared Library),是一种在程序运行时才被加载到内存中的代码库。它的文件名通常以 libxxx.so 的形式命名(xxx 是库的名字,so 表示 shared object)。
与动态库相对的是静态库(Static Library),静态库在程序编译时会被直接嵌入到可执行文件中,文件名通常以 libxxx.a 的形式命名。
二、生成动态库
1. 编译选项
生成动态库需要使用 gcc 编译器,并指定以下选项:
-fPIC:生成位置无关代码(Position Independent Code, PIC)。这种代码可以在内存中的任何位置运行,是动态库的必要条件。-shared:表示生成共享库格式。
2. 示例代码
假设我们有以下文件:
add.c:实现加法函数。sub.c:实现减法函数。
文件内容如下:
// add.c
#include <stdio.h>int add(int a, int b) {return a + b;
}
// sub.c
#include <stdio.h>int sub(int a, int b) {return a - b;
}
3. 生成动态库的步骤
# 编译源文件为位置无关代码
gcc -fPIC -c add.c sub.c# 生成动态库
gcc -shared -o libmymath.so add.o sub.o
执行完上述命令后,会生成一个名为libmymath.so 的动态库文件。
从库的使用者角度
静态库的使用
上面我们自己写的库libmymath.a 是第三方库,gcc 默认不认识 。所以我们在使用gcc D的时候还要加上一个-l 选项来链接到我们的库,还记得上面我们所说的吗,我们的库是以lib为前缀的,以.a 为后缀的,但是在用-l 链接的时候,我们要去掉前缀和后缀,直接用mymath 像这样:-lmymath ,我们还要用-L 来制定库的路径,我们这样来表示-L. ,用. 来表示当前路径,如果你的静态库在当前路径下的话,所以连在一起就是:
[root@localhost linux]# gcc TestMain.c -L. -lmymath
- TestMain.c 是用户写的程序。
- -L 指定库路径
- -l 指定库名
-I: 指定头文件的路径
如果我们要把自己写的库交给其他用户使用的话,那我们就要把.h 和.a 交给他,
gcc 默认是动态链接的,
动态库的使用
使用动态库
1. 编译选项
在使用动态库时,需要指定以下选项:
-L:指定动态库所在的路径(如果动态库不在系统默认路径中)。-l:指定要链接的动态库的名字(去掉lib前缀和.so后缀)。
2. 示例代码
假设我们有一个主程序 main.c,它调用了动态库中的函数:
// main.c
#include <stdio.h>int add(int a, int b);
int sub(int a, int b);int main()
{printf("add(10, 20) = %d\n", add(10, 20));printf("sub(100, 20) = %d\n", sub(100, 20));return 0;
}
3. 编译主程序
# 编译主程序
gcc main.c -o main -L. -lmymath
-L.表示动态库在当前目录下。-lmymath表示链接libmymath.so动态库。
运行动态库
方法一:将 .so 文件拷贝到系统共享库路径
系统默认的动态库路径通常是 /usr/lib 或 /usr/local/lib或是:/lib64 。可以将动态库文件拷贝到这些路径下:
# 拷贝动态库到 /usr/local/lib
cp libmymath.so /usr/local/lib/
方法二:通过使用软连接 查找动态库
ln -s /*动态库的路径*/ libmymath.so
/*动态库的路径*/ : 这里填动态库的路径
libmymath.so : 这个是软连接的名字。
这样,我们通过在当前目录下建立软连接的方式找到我们对应的库。
gcc 可以在当前目录下找到动态库。所以我们可以在当前目录下建立对应库的软连接,这样来让 gcc 找到,我们也可以在系统的指定目录下建立对应的软连接。
方法三:设置 LD_LIBRARY_PATH 环境变量(LD 的意思就是 load -加载,所以这句话就是 : 加载库路径环境变量)
如果不想将动态库文件拷贝到系统路径,可以通过设置 LD_LIBRARY_PATH 环境变量来指定动态库的路径:
# 设置 LD_LIBRARY_PATH
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/*这里填你写的动态库的路径*/
但是这里导入的环境变量是内存级的,所以你重启电脑之后就没了。
方法四:直接更改系统配置文件:使用 ldconfig 配置动态库路径
如果动态库文件存放在非默认路径下,可以通过修改 /etc/ld.so.conf 文件或在 /etc/ld.so.conf.d/ 下添加配置文件来指定动态库路径。
例如:
# 创建配置文件
echo "/path/to/your/library" > /etc/ld.so.conf.d/mylib.conf# 更新动态库缓存
ldconfig
同一组库,提供动静两种库,gcc默认使用动态库。
五、使用外部库
Linux 系统中有很多外部库,例如:
ncurses:用于处理屏幕显示和用户输入的库。glib:用于通用工具函数的库。openssl:用于加密和安全通信的库。
使用外部库的步骤与使用自己编写的动态库类似,需要:
- 安装外部库(通常通过包管理工具,如
apt或yum)。
比如安装ncurses库
sudo yum install -y ncurses-devel - 在编译时指定库的路径和名称。
例如,使用 ncurses 库:
# 编译
gcc main.c -o main -lncurses# 运行
./main
相关文章:
动静态库-Linux 学习
在软件开发中,程序库是一组预先编写好的程序代码,它们存储了常用的函数、变量和数据结构等。这些库可以帮助开发者节省大量的时间和精力,避免重复编写相同的代码。当我们在 Linux 系统中开发程序时,经常会用到两种类型的程序库&am…...
DeepSeek 系列模型:论文精读《A Survey of DeepSeek Models》
引言:一篇快速了解 DeepSeek 系列的论文。我在翻译时加入了一些可以提高 “可读性” 的连词 ✅ NLP 研 2 选手的学习笔记 笔者简介:Wang Linyong,NPU,2023级,计算机技术 研究方向:文本生成、大语言模型 论文…...
Python解决“找出整形数组中占比超过一半的数”问题
这里写目录标题 问题描述测试样例解决思路代码法1法2 问题描述 小R从班级中抽取了一些同学,每位同学都会给出一个数字。已知在这些数字中,某个数字的出现次数超过了数字总数的一半。现在需要你帮助小R找到这个数字。 测试样例 样例1: 输入&…...
机器人学习模拟框架 robosuite (3) 机器人控制代码示例
Robosuite框架是一个用于机器人模拟和控制的强大工具,支持多种类型的机器人。 官方文档:Overview — robosuite 1.5 documentation 开源地址:https://github.com/ARISE-Initiative/robosuite 目录 1、通过键盘或SpaceMouse远程控制机器人…...
kakfa-3:ISR机制、HWLEO、生产者、消费者、核心参数负载均衡
1. kafka内核原理 1.1 ISR机制 光是依靠多副本机制能保证Kafka的高可用性,但是能保证数据不丢失吗?不行,因为如果leader宕机,但是leader的数据还没同步到follower上去,此时即使选举了follower作为新的leaderÿ…...
【微知】如何查看Mellanox网卡上的光模块的信息?(ethtool -m enp1s0f0 看型号、厂商、生产日期等)
背景 服务器上插入的光模块经常被忽略,往往这里是定位问题最根本的地方。如何通过命令查看? 命令 ethtool提供了-m参数,m是module-info的意思,他是从光模块的eeprom中读取数据。(应该是用i2c协议读取的)…...
yum源选要配置华为云的源,阿里云用不了的情况
curl -O /etc/yum.repos.d/CentOS-Base.repo https://repo.huaweicloud.com/repository/conf/CentOS-7-reg.repo...
nginx accesslog 打印自定义header
比如我在请求的header中添加了一个path-match-type,那我现在nginx的accesslog 中打印出来,应该如何配置呢? rootnginx-59f5d66df6-jw5k8:/# cat /etc/nginx/nginx.conf user nginx; worker_processes auto;error_log /var/log/nginx/erro…...
好数——前缀和思想(题目分享)
今天我的舍友去参加“传智杯”广东省的省赛,跟我说了这样一道题,他说他想不出来怎么去优化代码,怎么做都是套用两层for循环超时,下面我就根据题意,使用前缀和的算法去优化一下思路,题目本身是不难的&#x…...
MWC 2025 | 移远通信大模型解决方案加速落地,引领服务机器人创新变革
随着人工智能、大模型等技术的蓬勃发展,生成式AI应用全面爆发。在此背景下,服务机器人作为大模型技术在端侧落地的关键场景,迎来了前所未有的发展机遇。 作为与用户直接交互的智能设备,服务机器人需要应对复杂场景下的感知、决策和…...
【大模型基础_毛玉仁】0.概述
更多内容:XiaoJ的知识星球 【大模型基础_毛玉仁】 系列文章参考 系列文章 【大模型基础_毛玉仁】0.概述 【大模型基础_毛玉仁】1.1 基于统计方法的语言模型 更新中。。。。。。 参考 书籍:大模型基础_完整版.pdf Github:https://github.co…...
ADB、Appium 和 大模型融合开展移动端自动化测试
将 ADB、Appium 和 大模型(如 GPT、LLM) 结合,可以显著提升移动端自动化测试的智能化水平和效率。以下是具体的实现思路和应用场景: 1. 核心组件的作用 ADB(Android Debug Bridge): 用于与 Android 设备通信,执行设备操作(如安装应用、获取日志、截图等)。Appium: 用…...
springboot425-基于SpringBoot的BUG管理系统(源码+数据库+纯前后端分离+部署讲解等)
💕💕作者: 爱笑学姐 💕💕个人简介:十年Java,Python美女程序员一枚,精通计算机专业前后端各类框架。 💕💕各类成品Java毕设 。javaweb,ssm…...
Ubuntu系统上部署Node.js项目的完整流程
以下是在Ubuntu系统上部署Node.js项目的完整流程,分为系统初始化、环境配置、项目部署三个部分: 一、系统初始化 & 环境准备 bash # 1. 更新系统软件包 sudo apt update && sudo apt upgrade -y# 2. 安装基础工具 sudo apt install -y buil…...
X Window---图形接口
摘抄自 鸟哥的linux私房菜 基础篇 第四版 有鉴于图形用户接口(Graphical User Interface, GUI) 的需求日益加重,在 1984 年由 MIT 与其他第三方首次发表了 X Window System ,并且更在 1988 年成立了非营利性质的 XFree86 这个组织。所谓的XFree86 其实是…...
数据序列化协议 Protobuf 3 介绍(Go 语言)
Protobuf 3 入门 1. 什么是序列化? 1.1 概念 序列化(Serialization 或 Marshalling) 是指将数据结构或对象的状态转换成可存储或传输的格式。反向操作称为反序列化(Deserialization 或 Unmarshalling),它…...
FineReport 操作注意
1.父单元格重复的时候,如何取消合并 效果如下: 只需要在单元格中,将数据设置为【列表】即可。 2.待定...
3D手眼标定转换详细实施步骤及原理概述
3D手眼标定转换详细实施步骤及原理概述 一、手眼标定的核心目标二、3D手眼标定的原理概述一、基本概念与坐标系定义**二、数学建模与方程推导****1. 坐标变换的齐次矩阵表示****2. 手眼标定方程推导** **三、方程求解方法****1. 分离旋转与平移****2. 旋转矩阵求解****3. 平移向…...
Verilog:SCCB控制器
目录 一、SCCB协议 (1)SCCB时序 (2)与I2C的区别 二、Verilog 实现 (1)设计要求 (2)设计要点 (3)模块完整代码 三、功能验证 (1)写…...
维度建模基础篇:从理论到核心组件解析
维度建模基础篇:从理论到核心组件解析 引言 在数据仓库与商业智能(BI)领域,维度建模(Dimensional Modeling)作为一种经典的数据组织方法论,自Kimball提出以来,已成为构建高效分析型系统的核心范式1,2,3。其以业务需求为导向,通过事实表与维度表的组合,实现对复杂…...
与中国联通技术共建:通过obdiag分析OceanBase DDL中的报错场景
中国联通软件研究院(简称联通软研院)在全面评估与广泛调研后,在 2021年底决定采用OceanBase 作为基础,自研分布式数据库产品CUDB(即China Unicom Database,中国联通数据库)。目前,该…...
大数据与网络安全讲座
🍅 点击文末小卡片 ,免费获取网络安全全套资料,资料在手,涨薪更快 大数据的价值为大家公认。业界通常以4个“V”来概括大数据的基本特征——Volume(数据体量巨大)、Variety(数据类型繁多)、Value(价值密度低)、Velocity(处理速度快…...
AtCoder Beginner Contest 395 E
点我写题 题意:给个有向图,从1出发,每次可以走一条有向边,花费为1,也可以选择把全部有向边翻转,花费x,问到n的最小花费 思路:最短路dp,定义dis[i][0/1]表示走到i为止&…...
Linux进程管理6 - CFS调度
0、CFS调度器 CFS调度器使用完全公平调度算法。 完全公平调度算法引入虚拟运行时间的概念:虚拟运行时间 = 实际运行时间 * nice_0_weight / 进程的权重。完全公平调度算法使用红黑树把进程按虚拟运行时间从小到大排序,每次调度选择虚拟运行时间最小的进程。时间片 操作系统进…...
张驰咨询:用六西格玛重构动力电池行业的BOM成本逻辑
在动力电池行业,BOM(物料清单)成本每降低1%,都可能改写企业的利润曲线。某头部企业的三元锂电池BOM成本曾较行业标杆高出11%,单电芯利润率被压缩至3%的生死线。然而,通过张驰咨询的六西格玛方法论ÿ…...
pyside6学习专栏(九):在PySide6中使用PySide6.QtCharts绘制6种不同的图表的示例代码
PySide6的QtCharts类支持绘制各种型状的图表,如面积区域图、饼状图、折线图、直方图、线条曲线图、离散点图等,下面的代码是采用示例数据绘制这6种图表的示例代码,并可实现动画显示效果,实际使用时参照代码中示例数据的格式将实际数据替换即可…...
SpringBoot获取YAML配置文件中的属性值(二):使用Environment环境组件读取值
Spring Boot 使用 Properties 和 YAML 配置文件文件,系列文章: 《Spring使用@Value注解与@PropertySource注解加载配置文件》 《SpringBoot获取YAML配置文件中的属性值(一):使用@Value注解、@ConfigurationProperties注解》 《SpringBoot获取YAML配置文件中的属性值(二)…...
14天 -- Redis 的持久化机制有哪些?Redis 主从复制的实现原理是什么? Redis 数据过期后的删除策略是什么?
Redis 的持久化机制有哪些? Redis 是一种高性能的键值存储系统,主要用于缓存、消息队列等场景。为了防止数据丢失,Redis 提供了多种持久化机制,主要包括以下两种: 1. RDB(Redis Database Backupÿ…...
《深度学习实战》第10集:联邦学习与隐私保护
第10集:联邦学习与隐私保护 2025年3月4日更新了代码,补充了实例程序运行截图 和 如何提高模型准确率的方法 系统梳理 集集精彩 代码验证 保证实战 随着数据隐私问题日益受到关注,联邦学习(Federated Learning) 作为一…...
如何解决跨域请求的问题(CORS)?
文章目录 1. 引言2. 理解 CORS2.1 CORS 基本概念2.2 同源策略与跨域分类 3. CORS 的核心机制3.1 预检请求(Preflight Request)3.2 简单请求 4. 服务器端配置 CORS4.1 关键响应头4.2 Node.js (Express) 示例4.3 其他后端语言配置 5. 前端处理 CORS 请求5.…...
