【Linux】动静态库
目录
写在前面的话
如何编写静态库库
编写静态库
ar命令
Makefile自动化形成静态库
如何使用编写的静态库
1.拷贝到系统路径中
2.指定路径搜索
如何编写动态库
编写动态库
完善Makefile
如何使用编写的动态库
指定路径搜索(不可行及原因)
环境变量LD_LIBRARY_PATH
修改配置文件
写在前面的话
本文章主要讲解了动静态库的编写以及使用。在了解静态链接和动态链接的基础上,观看本文的效果会更好。
欢迎阅读我之前写的:动静态链接,里面有关于动态和静态链接的详细介绍,而且也有对动静态库的一些基本认识,欢迎阅读哦.
如何编写静态库
这里我们将编写两个类型的库:动态库(.so) 和 静态库(.a).
编写静态库
静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库.
需要说明:库里不能包含main函数,因为是要别人用的。写main函数的话就会和别人的main函数冲突了.
我现在分别创建了4个文件:mymath.h mymath.c myprint.h myprint.c.
分别写入以下内容:
- mymath.h:
#pragma once #include<stdio.h> extern int addToTarget(int start, int end);//声明函数
- mymath.c
#include "mymath.h" # //这段函数的作用是计算start-end之间的和int addToTarget(int start, int end) { int sum = 0; int i = start; for(i; i <= end; i++){ sum += i; } return sum; }
- myprint.h
#pragma once #include<stdio.h> #include<time.h> extern void Print(const char* str);
- myprint.c
#include "myprint.h" //这段函数功能是输出传入的字符串,后面加上时间戳 void Print(const char* str) {printf("%s[%d]\n",str,(int)(time(NULL))); }
然后我们编写一个main.c文件,来调用这些函数.
#include "myprint.h"
#include "mymath.h" int main()
{ Print("hello,world"); int res = addToTarget(1,100); printf("res: %d\n",res); return 0;
}
指令编译所有.c文件,目标生成my.exe可执行文件:
gcc main.c mymath.c myprint.c -o my.exe
然后我们执行my.exe文件,得到了我们预期的结果:

这只是我们的正常使用,毕竟源代码.c文件就在我们手上。
当我们把.h文件和 .c文件编译成的.o文件,给别人,别人可以用吗?
答案是可以的,我们首先把两个.c文件编译成.o文件:
gcc -o myprint.o -c myprint.c
gcc -o mymath.o -c mymath.c
然后我们换到另一个文件中,把两个.o和两个.h文件复制到这个文件中,然后将main.c也编译成main.o文件,此时我们将这三个.o文件一起编译,形成可执行程序。
gcc main.o mymath.o myprint.o -o my.exe
我们发现照样可以成功运行:

但问题是我们这里有太多的.o文件,发给别人也不方便,而且容易丢失,编译的时候还得都写上,这也未必太麻烦了。
所以此时我们需要把这些.o文件打包,这个打包的过程就是形成静态库的过程.
ar命令
把这些.o文件打包需要用到ar命令,命令格式如下:
ar -[选项] lib+库文件名+.a 所有.o文件
选项这里只说r(replace替换),c(create创建)就可以了,就足以让我们创建静态库了.
其中需要注意的是:要形成的静态库的名字 前缀必须是lib,后缀必须是.a,中间可以随便起名字.
比如我想把所有的.o文件打包成名字叫hello的静态库,指令如下:
ar -rc libhello.a main.o myprint.o mymath.o

这样就形成了.
Makefile自动化形成静态库
有了以上的认知,我们便对一个文件形成静态库的过程有了大概的了解:
.c文件 ---> .o文件 ---> 打包形成静态库
既然是这么一套固定的流程,那么我们完全可以用Makefile来完成这些工作。需要注意的是搞清各个文件的依赖关系,然后再进行编写。所以最后的Makefile编写如下:
libhello.a: mymath.o myprint.o ar -rc libhello.a mymath.o myprint.o
mymath.o : mymath.c gcc -o mymath.o -c mymath.c
myprint.o: myprint.c gcc -o myprint.o -c myprint.c .PHONY:clean
clean: rm -rf *.o libhello.a
这样,我们不需要再手动编译了,直接使用make就好了.

但这样只是将.o文件打包了,还有.h文件,就是通常#include<>的那些,一般都是.h文件
.h声明,然后从.o打包形成的库里面找
所以我们还需要做一件工作:将.h和.o文件规整到一起.在Makefile加入以内容:
.PHONY:hello
hello: mkdir -p hello/lib mkdir -p hello/include cp -rf *.h hello/include cp -rf *.a hello/lib
即创建了三个目录,hello,lib和include,把当前所有的.h文件放到include文件夹中,所有.a库文件放到lib文件夹中。

这里首先把资源全部清理一下,然后make编译形成.o文件,再make hello 形成hello目录,里面包含了两个目录include 和 lib ,分别保存.h文件和库文件.
如何使用编写的静态库
1.拷贝到系统路径中
头文件gcc系统默认搜索路径是:/usr/include
库文件gcc系统默认搜索路径是:/lib64 或者 /usr/lib64
sudo cp hello/include/*.h /usr/include/ //拷贝头文件
sudo cp hello/lib/*.a /lib64 //拷贝库文件
拷贝完成后,我们再次编译main.c

发现还是不行,这是由于我们平常使用的是系统自带的库,而我们编写的是第三方库,所以我们编译时需要指定链接哪一个库.
gcc main.c -lhello
注意,-l后面直接加库的名字,不加前缀lib和后缀.a.
此时我们再编译,便运行成功了.

这种把自己的库拷贝到系统路径下的行为就叫做库的安装.
但是一般不建议采用这种办法。会污染别人已经写好的库。
2.指定路径搜索
我们可以直接在编译的时候加上头文件和库文件的路径.
gcc main.c -I ./hello/include/ -L ./hello/lib/ -lhello
选项:-I(i的大写)表示头文件的搜索路径
-L表示库文件的搜索路径
-l(小写的L)表示在特定路径下,要使用哪一个库.
如何编写动态库
动态库(.so):程序在运行的时候才去链接动态库的代码,多个程序共享使用库的代码。
编写动态库
同样地,我么也需要先将.c文件编译成.o文件,但此时需要加上选项 -fPIC.
gcc -fPIC -c myprint.c -o myprint.o
gcc -fPIC -c mymath.c -o mymath.o
选项
-fPIC是指生成位置独立代码(Position Independent Code,PIC)。它通常用于创建可在不同内存地址空间加载的共享库(动态链接库)。具体来说,
-fPIC选项的作用是告诉编译器生成与位置无关的代码,这些代码可以在内存中的任何位置加载和执行,与共享库的加载地址无关。这是通过使用相对偏移而不是绝对地址来访问全局变量和函数等的。
看不懂没有关系,我们后面会继续细说的.
然后我们需要将这些.o文件它打包成动态库.它没有单独的命令,使用gcc进行打包,但是需要加上 -shared的选项,如下:
gcc -shared myprint.o mymath.o -o libhello.so
这样我们就完成了动态库的打包和编写.

由于流程是固定的,所以我们依然可以使用Makefile来完成。
完善Makefile
首先我们需要先将.c编译诚.o文件,并打包成动态库
然后需要将生成的动态库也放到我们之前创建的lib目录中。
完善后的效果如下(框起来的是新增的内容):
.PHONY:all
all:libhello.so libhello.a libhello.so:mymath_d.o myprint_d.o gcc -shared mymath_d.o myprint_d.o -o libhello.so
mymath_d.o:mymath.c gcc -c -fPIC mymath.c -o mymath_d.o
myprint_d.o:myprint.c gcc -c -fPIC myprint.c -o myprint_d.o libhello.a: mymath.o myprint.o ar -rc libhello.a mymath.o myprint.o
mymath.o : mymath.c gcc -o mymath.o -c mymath.c
myprint.o: myprint.c gcc -o myprint.o -c myprint.c .PHONY:output
output: mkdir -p hello/lib mkdir -p hello/include cp -rf *.h hello/include cp -rf *.a hello/lib cp -rf *.so hello/lib
.PHONY:clean
clean: rm -rf *.o libhello.a output

此时我们即可以形成动态库,也可以形成静态库.
然后此时我们make编译,再make output将文件拷贝到指定目录中.

此时便把动态库也成功放入到lib路径下了.
此时我们便可以利用tar指令打包发送到网上,然后让别人使用了。
如何使用编写的动态库
指定路径搜索(不可行及原因)
首先,静态库中的第一种拷贝到系统路径里这种方法一定是可行的.
第二种方法,这条指令:
gcc main.c -I ./hello/include/ -L ./hello/lib/ -lhello
我们首先要知道,gcc默认使用的是动态链接,即使用动态库.
a.当库中只有静态库时,gcc就只能针对该库进行静态链接.
b.当动静态库同时存在时,默认使用的就是动态库
c.如果动静态库同时存在,强制使用静态库,那就需要再上面指令后面加上 -static
表示的是:摒弃优先使用动态库的原则,而是直接使用静态库的方法.
代码如下:
gcc main.c -I ./hello/include/ -L ./hello/lib/ -lhello -static
我们同样地利用上面那一条指令进行编译生成可执行程序后,我们把可执行程序移动到上一级目录.然后运行它。

此时我们再运行,发现报错了,就是找不到这个共享的文件,这是为什么呢、我们不是已经指定路径了吗,为什么还找不到呢?
我们要明白,动态库是一个独立的文件,动态库可以和可执行程序分批加载!
而我们指定路径是给gcc指定查找的,是告诉了gcc的动态库的路径。
当我们运行和加载的时候,就和gcc没有关系了,所以我们要告诉操作系统或者加载器 这个动态库的路径!
如果此时新来一个进程,也需要用相同的动态库,操作系统只需要将物理内存中动态库数据经过页表映射到对应进程的地址空间 中的共享区的位置,这样代码区的代码遇到动态库中的函数直接去共享区去找。
那为什么静态库不用呢?
静态链接的一旦编译好,就和库没有关系了,因为已经把库中代码拷贝到自己写的C/C++代码中了.即已经在可执行程序中了.
环境变量LD_LIBRARY_PATH
这个是库加载时搜索的路径.我们只需要把我们的库的路径导入到这个环境变量里面即可.
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:你的库文件路径
导入完成后,此时我们便可以成功运行了

但这个方法有一个缺点,就是每次退出后,我们导入的这些环境变量就会清空,下次还需要重新导入,比较麻烦。
修改配置文件
我们既不想在系统中安装我们的库,又想永久保存,那该怎么办呢?
我们只需要在/etc/ld.so.conf.d/路径下 随便创建一个文件.然后vim打开文件,输入你动态库文件路径,然后退出保存即可.
sudo vim /etc/ld.so.conf.d/mylib.conf
然后输入你的库文件路径即可,然后退出,执行重新加载指令
sudo ldconfig
这样也可以照样正常运行了.

到这里动静态库就讲完了,感谢您的阅读哦~
相关文章:
【Linux】动静态库
目录 写在前面的话 如何编写静态库库 编写静态库 ar命令 Makefile自动化形成静态库 如何使用编写的静态库 1.拷贝到系统路径中 2.指定路径搜索 如何编写动态库 编写动态库 完善Makefile 如何使用编写的动态库 指定路径搜索(不可行及原因) 环境变量LD_LIBRARY_PAT…...
《kubernetes权威指南》-第一章学习笔记
1.什么是kubernetes? kubernetes是一个全新的基于容器技术的分布式架构领先方案。 2.为什么要用kubernetes? 使用kubernetes提供的解决方案能够减少30%的开发成本,并且能够将开发人员的精力更加集中于业务本身,同时可以降低系统…...
ubuntu 18.04 磁盘太满无法进入系统
安装了一个压缩包,装了一半提示磁盘空间少导致安装失败。我也没在意,退出虚拟机打算扩展硬盘。等我在虚拟机设置中完成扩展操作,准备进入虚拟机内部进行操作时,发现登录不进去了 shift 登入GUN GRUB设置项的问题 网上都是在开机…...
基于LNMP配置WordPress建站时出现的问题汇总
目录 wordpress上传文件报错问题描述原因分析:解决方案: wordpress裁剪图片报错问题描述原因分析:解决方案: 配置固定链接和伪链接 wordpress上传文件报错 WP内部错误,在上传文件时发生了错误,显示权限不足…...
【Spring Cloud】Gateway的配置与使用
文章目录 前言第一步,创建一个springboot工程第二步,添加依赖第三步,编写yml文件第四步,启动主启动类总结 前言 Gateway其实是springcloud 原生的东西,但是我还是想放在这里讲,因为我们使用nacos时&#x…...
概念、框架简介--ruoyi学习(一)
开始进行ruoyi框架的学习,比起其他的前后端不分离的,这个起码看的清晰一些吧。 这一节主要是看了ruoyi的官方文档后,记录了以下不懂的概念,并且整理了ruoyi框架中的相关内容。 一些概念 前端 store store是状态管理库&#x…...
IDEA的基础使用——【初识IDEA】
IDEA的基础使用——【初识IDEA】 文章目录 IDEA简介前言官网 IDEA的下载与安装选择下载路径勾选自己需要的其余按默认选项进行即可 目录简介安装目录简介 运行Hello WorldIDEA快捷键常用模板模板一:psvm(main)模板二:模板三&#…...
LeetCode刷题总结-动态规划篇
LeetCode刷题总结-动态规划篇 本文总结LeetCode上有动态规划的算法题,推荐刷题总数为54道。具体考点分析如下图: 1.中心扩展法 题号:132. 分割回文串 II,难度困难 2.背包问题 题号:140. 单词拆分 II,难…...
el-table使用xlsx实现导入文件编辑功能
需求:列表根据xlsx文件导入后,和列表进行对比,之后实现编辑功能 1.下载xlsx 我下的是之前的版本,新版不知道兼不兼容,这个包900多k npm install xlsx0.14.5 2.在需要使用表格导入的页面引入 import XLSX from &quo…...
Android9、11 有线网络开关设置
Android9、11 有线网络开关设置 Android9、11 有线网络开关设置_android 以太网开关_峥嵘life的博客-CSDN博客...
【MySQL】mysql问题 | [ERROR] unknown variable ‘column-statistics=0‘
一、说明 1、用到一个开源项目,dbBkTool[asurplus] 2、这个项目用于MySQL定时备份的 3、然后有个执行的时候,发下报错 [ERROR] unknown variable column-statistics0 二、解决 1、把MySQL客户端升级到8.0.19之后,就不报错了 2、column-stat…...
ElasticSearch 7.x
前言 elastic表示可伸缩,search表示查询。所以es的核心即为查询。通常情况下,我们的数据可以分为三类:结构化数据、非结构化数据、半结构化数据。 结构化数据:一般会用特定的结构来组织和管理数据,表现为二维表结构。…...
MVC乱码问题
RequestMapping(value "insert",produces {"text/html;charsetutf-8"}) //前端响应回去加响应头,解决乱码问题,这个还跟JSP响应头还不一样,这是响应的字符串,纯文本,那个前端的是out.Writer()对象ÿ…...
1004. 最大连续1的个数 III
题目描述: 主要思路: 刚看到这个问题首先想到的是二分答案,二分长度,然后利用滑动窗口判断是否可以达成。 class Solution { public:bool find(int x,vector<int> nums, int k){int now0;for(int i0,j0;i<nums.size();…...
【机器学习】西瓜书学习心得及课后习题参考答案—第3章线性模型
过了一遍第三章,大致理解了内容,认识了线性回归模型,对数几率回归模型,线性判别分析方法,以及多分类学习,其中有很多数学推理过程以参考他人现有思想为主,没有亲手去推。 术语学习 线性模型 l…...
面试官问我:一个 TCP 连接可以发多少个 HTTP 请求?我竟然回答不上来...
一道经典的面试题是从 URL 在浏览器被被输入到页面展现的过程中发生了什么,大多数回答都是说请求响应之后 DOM 怎么被构建,被绘制出来。但是你有没有想过,收到的 HTML 如果包含几十个图片标签,这些图片是以什么方式、什么顺序、建…...
树莓派Pico|RP2040|官方文档|在MS Windows上构建“Hello World”及环境配置
9.2. 在MS Windows上构建 在Microsoft Windows 10或Windows 11上安装工具链与其他平台有些不同。然而安装后,RP2040的构建代码基本类似。 警告 官方不支持在Windows 7或8上使用Raspberry Pi Pico,但在Windows 7或8上可以使其工作。 9.2.1. 安装工具…...
全球公链进展| 2023/7/31
一周速览 过去一周,明星项目动态如下: 第114次以太坊核心开发者共识会议:Devnet #8 最早下周推出 Layer2网络Shibarium跨链桥已上线公开测试 Optimism 推出「Law of Chains」v0.1 版本 Sui 通过 SIP#6 ,允许开发人员构建流动…...
Spring源码(三)Spring Bean生命周期
Bean的生命周期就是指:在Spring中,一个Bean是如何生成的,如何销毁的 Bean生命周期流程图 1、生成BeanDefinition Spring启动的时候会进行扫描,会先调用org.springframework.context.annotation.ClassPathScanningCandidateCompo…...
【iOS】Cydia Impactor 错误:file http.hpp; line:37; what: _assert(code == 200)
Cydia Impactor 报错,信息如下 file http.hpp; line:37; what: _assert(code 200)解决方案:Cydia Impactor 已被弃用,切换到sideloadly 即可,亲测成功,并且支持双重验证登录 csdn备份地址 HERE...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
消息队列系统设计与实践全解析
文章目录 🚀 消息队列系统设计与实践全解析🔍 一、消息队列选型1.1 业务场景匹配矩阵1.2 吞吐量/延迟/可靠性权衡💡 权衡决策框架 1.3 运维复杂度评估🔧 运维成本降低策略 🏗️ 二、典型架构设计2.1 分布式事务最终一致…...
沙箱虚拟化技术虚拟机容器之间的关系详解
问题 沙箱、虚拟化、容器三者分开一一介绍的话我知道他们各自都是什么东西,但是如果把三者放在一起,它们之间到底什么关系?又有什么联系呢?我不是很明白!!! 就比如说: 沙箱&#…...
高防服务器价格高原因分析
高防服务器的价格较高,主要是由于其特殊的防御机制、硬件配置、运营维护等多方面的综合成本。以下从技术、资源和服务三个维度详细解析高防服务器昂贵的原因: 一、硬件与技术投入 大带宽需求 DDoS攻击通过占用大量带宽资源瘫痪目标服务器,因此…...
OCR MLLM Evaluation
为什么需要评测体系?——背景与矛盾 能干的事: 看清楚发票、身份证上的字(准确率>90%),速度飞快(眨眼间完成)。干不了的事: 碰到复杂表格(合并单元…...

