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

Linux_库制作与原理浅理解

18fde01fee5e4278981004762ce48cc4.png

✨✨ 欢迎大家来到小伞的大讲堂✨✨

🎈🎈养成好习惯,先赞后看哦~🎈🎈

所属专栏:LInux_st
小伞的主页:xiaosan_blog

制作不易!点个赞吧!!谢谢喵!!

1. 什么是库

库是写好的现有的,成熟的,可以复用的代码。现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。

本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。库有两种:

  • 静态库.a[Linux]、.lib[windows]
  • 动态库.so[Linux]、.dll[windows]

// ubuntu 动静态库
// C 

//C++ 

1.1场景:

//my_stdio.h
#pragma once
#define SIZE 1024
#define FLUSH_NONE 0
#define FLUSH_LINE 1
#define FLUSH_FULL 2
struct IO_FILE
{int flag;   // 刷新⽅式int fileno; // ⽂件描述符char outbuffer[SIZE];int cap;int size;// TODO
};
typedef struct IO_FILE mFILE;
mFILE *mfopen(const char *filename, const char *mode);
int mfwrite(const void *ptr, int num, mFILE *stream);
void mfflush(mFILE *stream);
void mfclose(mFILE *stream);
//my_stdio.c
#include "my_stdio.h"
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
mFILE *mfopen(const char *filename, const char *mode)
{int fd = -1;if (strcmp(mode, "r") == 0){fd = open(filename, O_RDONLY);}else if (strcmp(mode, "w") == 0){fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);}else if (strcmp(mode, "a") == 0){fd = open(filename, O_CREAT | O_WRONLY | O_APPEND, 0666);}if (fd < 0)return NULL;mFILE *mf = (mFILE *)malloc(sizeof(mFILE));if (!mf){close(fd);return NULL;}mf->fileno = fd;mf->flag = FLUSH_LINE;mf->size = 0;mf->cap = SIZE;return mf;
}
void mfflush(mFILE *stream)
{if (stream->size > 0){// 写到内核⽂件的⽂件缓冲区中!write(stream->fileno, stream->outbuffer, stream->size);// 刷新到外设fsync(stream->fileno);stream->size = 0;}
}
int mfwrite(const void *ptr, int num, mFILE *stream)
{// 1. 拷⻉memcpy(stream->outbuffer + stream->size, ptr, num);stream->size += num;// 2. 检测是否要刷新if (stream->flag == FLUSH_LINE && stream->size > 0 && stream -> outbuffer[stream->size - 1] == '\n'){mfflush(stream);}return num;
}
void mfclose(mFILE *stream)
{if (stream->size > 0){mfflush(stream);}close(stream->fileno);
}
//my_string.h
#pragma once
int my_strlen(const char *s);
//my_string.c
#include "my_string.h"
int my_strlen(const char *s)
{const char *end = s;while (*end != '\0')end++;return end - s;
}

当我们借代码给别人时,并且老师想要查看他的源码,这时候,我们拷贝*.c文件,就容易被发现。我们就可以

gcc -c  *.c (将.c文件编译成.o文件,.o文件是一堆二进制乱码)

 当我们有一千个.c文件时,我们需要tar或者zip打包传输,然而解压出来也是一千个文件,太麻烦了,为了避免这样的麻烦,我们就有ar命令将所有的.o文件打包,可以直接使用gcc/g++链接,无需解压。这就是库

2.静态库的制作

静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中,程序运行的时候将不再需要静态库

ar -rc 新建包文件名 目标文件名 

 

一般命名为:lib+名+(.a)

ar 是 gnu 归档⼯具, rc 表⽰ (replace and create)
 
$ ar -tv libmystdio.a
rw-rw-r-- 1000/1000 2848 Oct 29 14:35 2024 my_stdio.o
rw-rw-r-- 1000/1000 1272 Oct 29 14:35 2024 my_string.o
 
• t: 列出静态库中的⽂件
• v:verbose 详细信息 

我们的编译默认执行的为动态链接库,只有在该库找不到动态.so的时候才会采用同名静态库,我们也可以采用-static强转设置链接静态库

2.1静态库的生成

2.1.1 当前路径下 

通过编译源文件 

main.c 为用户调用主程序

此时我们发现其调用接口操作系统不认识,因为这时候的.a文件为库文件,我们需要链接库文件 

唉,为什么链接库了,却显示没有找到,应该是名字的问题,库的文件名应该是去掉lib,去掉.a

因为gcc查找库不会从当前查找,如果你能编译的过,或许是vim配置更改了某些条件,

我们需要-L指定当前路径查找 ,我们就能运行成功了

2.1.1.1总结:

2.1.2 不同路径下

此时你又想到一个方法,我们将库直接打包发

tar czf lib.tgz lib     //打包压缩

tar xzf lib.tgz    //解压

编译源文件(错误,一般不能)

正确做法 (一般情况下是不能创建的,因为编译时会从当前路径寻找,可能是因为vim原因)

创建可执行程序(链接库) 

2.2总结三种情况:
// 场景1:头⽂件和库⽂件安装到系统路径下
$ gcc main.c -lmystdio
// 场景2:头⽂件和库⽂件和我们⾃⼰的源⽂件在同⼀个路径下
$ gcc main.c -L. -lmymath
// 场景3:头⽂件和库⽂件有⾃⼰的独⽴路径
$ gcc main.c -I头⽂件路径 -L库⽂件路径 -lmymath
Makefile 
libmystdio.a:my_stdio.o my_string.o@ar -rc $@ $^@echo "build $^ to $@ ... done"
%.o:%.c@gcc -c $<@echo "compling $< to $@ ... done"
.PHONY:clean
clean:@rm -rf *.a *.o stdc*@echo "clean ... done"
.PHONY:output
output:@mkdir -p stdc/include@mkdir -p stdc/lib@cp -f *.h stdc/include@cp -f *.a stdc/lib@tar -czf stdc.tgz stdc@echo "output stdc ... done''

3.动态库的制作

动态库(.so):程序在运⾏的时候才去链接动态库的代码,多个程序共享使⽤库的代码。
• ⼀个与动态库链接的可执⾏⽂件仅仅包含它⽤到的函数⼊⼝地址的⼀个表,⽽不是外部函数所在⽬标⽂件的整个机器码
• 在可执⾏⽂件开始运⾏以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接(dynamic linking)
动态库可以在多个程序间共享,所以动态链接使得可执⾏⽂件更⼩,节省了磁盘空间。操作系统采⽤虚拟内存机制允许物理内存中的⼀份动态库被要⽤到该库的所有进程共⽤,节省了内存和磁盘空间。

 

gcc -fPIC -c *.c

gcc -shared -o libmyc.so *.o

shared:表示生成共享库格式
fPIC:产生位置无关码(position independent code)
库名规则:libxxx.so

当我们编译时,我们发现 undefined

我们链接库 

我们为什么不能执行呢

ldd:查看可执行程序链接库

发现 libmyc.so为not found,我们告诉了gcc我们库的位置,而系统不等于库,系统不知道库的位置,所以不可行

3.1 拷贝库

系统执行程序回到/lib64找库文件

3.2 软链接

3.3 添加环境变量

3.4加载配置文件

ls /etc/ld.so.conf.d(ld:加载 so:动态库 :conf:配置文件)

在/etc/ld.so.conf.d创建文件,将库目录写入

 

刷新系统配置文件 

当我们同时存在动静态库时,可执行程序会使用动态链接

http://www.xdnf.cn/news/1210195.html

相关文章:

  • Python高效历史记录管理:保存最后N个元素的完整指南
  • 【CSS】盒子类型
  • 功率场效应晶体管MOSFET关键指标
  • leaflet中绘制轨迹线的大量轨迹点,解决大量 marker 绑定 tooltip 同时显示导致的性能问题
  • 车载刷写架构 --- 刷写思考扩展
  • Redis的持久化策略-AOF和RDB(详细图解)
  • Java面试宝典:MySQL8新特性底层原理
  • Vue2 vs Vue3:核心差异与升级亮点
  • DeepSeek MoE 技术解析:模型架构、通信优化与负载均衡
  • 飞书 —— 多维表格 —— AI生成
  • 系统学习算法:专题十五 哈希表
  • 数据库02 网页html01 day44
  • 抵御酒店管理系统收银终端篡改攻击 API 加密的好处及实现——仙盟创梦IDE
  • 如何创建一个 Solana 钱包?
  • 文件操作与IO流
  • 如何编写好的测试用例?
  • 泛微E9 引入高版本spring导致webservices接口报错
  • 青少年软件编程图形化Scratch等级考试试卷(四级)2025年6月
  • SpringBoot之起步依赖
  • 在 Web3 时代通过自我主权合规重塑 KYC/AML
  • java导出pdf(使用html)
  • Java:为什么需要通配符捕获(wildcard capture)
  • 【WRF-Chem 实例1】namelist.input 详解- 模拟CO2
  • 【跨国数仓迁移最佳实践3】资源消耗减少50%!解析跨国数仓迁移至MaxCompute背后的性能优化技术
  • 机器学习第二课之线性回归的实战技巧
  • Three.js 性能优化全面指南:从几何体合并到懒加载资源
  • Ubuntu上开通Samba网络共享
  • nodejs 实现Excel数据导入数据库,以及数据库数据导出excel接口(核心使用了multer和node-xlsx库)
  • CTF Misc入门篇
  • 创建型设计模式-工厂方法模式和抽象工厂方法模式