当前位置: 首页 > 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.lryc.cn/news/603748.html

相关文章:

  • vim的`:q!` 与 `ZQ` 笔记250729
  • grep常用指令
  • 【lucene】SegmentCoreReaders
  • 【lucene】currentFrame与staticFrame
  • Qt 移动应用传感器开发
  • 20250729使用WPS打开xlsx格式的电子表格时候隐藏显示fx的编辑栏的方法
  • ElasticStack技术栈概述及Elasticsearch8.2.2集群部署并更换JDK版本为openjdk-17
  • sqlite3---维护命令、回调函数
  • 【机器学习深度学习】分布式训练的核心技术全解:数据并行、模型并行、流水线并行与3D混合并行
  • 基于最小二乘支持向量机(LSSVM)的气象预测
  • css 二维变换之详说
  • 引领汽车加速向具身智能进化,吉利携阶跃星辰参展WAIC 2025
  • 考古学家 - 华为OD统一考试(JavaScript 题解)
  • STM32寄存器中的缩写
  • 【HTML】浅谈 script 标签的 defer 和 async
  • 数据库4.0
  • 健壮性篇(一):优雅地“拥抱”错误:构建一个可预测的错误处理边界
  • vue-计算属性
  • Android Slices:让应用功能在系统级交互中触手可及
  • FPGA数码管驱动模块
  • windows软件ARM64和AMD64(x64)区别,如何查看电脑支持哪种
  • 沪铝本周想法
  • C++ 模板补充
  • 网工知识——OSPF摘要知识
  • 重生之我在暑假学习微服务第四天《Docker-下篇》
  • 《林景媚与时间守护者》
  • 博途SCL: Input、Output、Static、Temp、Constant、InOut 的详细介绍及案例
  • 实现视频实时马赛克
  • DevOps 详解
  • PHP入门:从0到1开启Web开发之旅