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

库的制作与原理(一)

·1.库的概念

库是写好的,现成的可以复用的代码。本质上库是一种可执行的二进制形式,可以被操作系统载入内存执行。库有俩种:静态库 .a[Linux]   .lib[windows]       动态库 .so[Linux]  .dll[windows]

就是把.c文件变成.o文件,把许多的.o文件一起打包成.a或者.so。

需要用到的代码

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;
};

typedef struct IO_FILE mFILE;

mFILE* mfopen(const char* filename,const char* mode);
int mfwirte(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<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(mpde,"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;
        return mf;


}

void mfflush(mFILE* stream)
{
        if(stream->size>0)
        {
                //写到内核文件的缓冲区中
                write(stream->fileno,steam->outbuffer,stream->size);
                //用fsync函数稳定刷新到外设
                fsync(stream->fileno);
                stream->size=0;


        }

}

int mfwrite(const void* ptr,int num,mFILE* stream)
{
        memcpy(stream->outbuffer+stream,ptr,num);
        stream->size+=num;
        //检查是否更新
        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;
}

fsync 函数是 POSIX 标准中定义的一个函数,用于将文件描述符指向的文件的数据强制写入到磁盘上。这个函数确保了所有缓冲区中的数据都被写入到磁盘,并且磁盘上的数据是最新的。这对于需要确保数据持久化的应用场景非常重要,例如数据库、日志文件等。

2.静态库

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

一个可执行程序可能用到许多库,这些库运行有的是静态库,有的是动态库,而我们编译默认认为动态链接库,只有在该库找不到动态.so的时候才会采用同名静态库。可以使用gcc的-static强转设置链接静态库。

静态库的生成

makefile文件

libmystdio.a:my_stdio.o my_string.o
        @ar -rc $@ $^
        @echo "bulid $^ to  $@"



%.o:%.c
        @gcc -c $<
        @echo "compling $< to $@"

.PHONY:clean
clean:
        @rm -rf *.a *.o stdc*


.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

ar是gun归档工具,rc表示replace and create

静态库的使用

#include "my_stdio.h"
#include "my_string.h"
#include <stdio.h>
int main()
{
        const char *s = "abcdefg";
        printf("%s: %d\n", s, my_strlen(s));
        mFILE *fp = mfopen("./log.txt", "a");
        if(fp == NULL) return 1;
        mfwrite(s, my_strlen(s), fp);
        mfwrite(s, my_strlen(s), fp);
        mfwrite(s, my_strlen(s), fp);
        mfclose(fp);
        return 0;
}
~        

场景一:头文件和库文件安装到系统默认路径下时

指令:gcc main.c -lmystdio 

场景二:头文件和库文件和源文件在同一路径下时

指令:gcc main.c -L. -lmymath

场景三:头文件和库文件有自己的独立路径

gcc main.c -I头文件路径 -L库文件路径 -lmymath(链接库的名称)

注意:库的名称要去掉前面的lib和后缀才是名字 

3.动态库

动态库(.so):程序在运行时的时候才去链接动态库的代码,多个程序共享使用库的代码。

一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机械码。

动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间,操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有1进程共享,节省了内存和磁盘空间。

动态库的生成


libmystdio.so:my_stdio.o my_string.o
        @gcc -o $@ $^ -shared
        @echo "bulid $^ to  $@"



%.o:%.c
        @gcc -fPIC -c $<
        @echo "compling $< to $@"

.PHONY:clean
clean:
        @rm -rf *.so *.o stdc*


.PHONY:output
output:
        @mkdir -p stdc/include
        @mkdir -p stdc/lib
        @cp -f *.h stdc/include
        @cp -f *.so stdc/lib
        @tar -czf stdc.tgz stdc

shared:表示生成共享库格式

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

库名规则:libxxx.so

动态库使用

场景一:头文件和库文件安装到标准系统路径下

gcc main.c -lmystdio 

场景二:头文件和库文件与源文件在同一个路径下

gcc main.c -L. -lmymath 

场景三:头文件和库文件都有自己的独立路径

gcc main.c -I头文件路径 -L库文件路径 -lmymath 

 4.库运行搜索路径

问题:

按照指令却显示问题,是因为链接器没有正确找到库文件的路径

 

解决方案

拷贝.so文件到系统共享库路径下,一般指/user/lib,或者指明完整库路径,例如拷贝到/lib64路径下

先系统共享路径下建立软连接,在/lib64下建立一个与库文件的软连接,先找到软连接再找到库

更改环境变量:LD_LIBRARY_PATH,这个通常是空的,OS运行程序,要查找动静态库,也会在该环境变量, 把完整库的路径赋值给这个环境变量

ldconfig方案:配置/etc/ld.so.conf.d/,ldconfig更新 ,这个路径系统会提前准备打开,把库路径放进去就会1提前准备好,在/etc/ld.so.conf.d/路径下配置好文件还要ldconfig更新一下。

5.目标文件

编译和链接这俩个步骤,在windows下被IDE封装的很完美。

 

 编译的过程:将程序的源代码翻译成CPU能够直接运行的机器代码。

为什么要有目标文件?假如有多个原文件,直接就合在一起编译,要是其中有一个要修改,则又要重新全部在和一起就浪费效率了,而每个都形成目标文件,改了一个也只要单独编译这一个,不影响其它。目标文件是一个二进制文件,文件的格式是ELF,是对二进制代码的一种封装。

6.ELF文件

以下四种文件都是ELF文件:

可重定位位文件:xxx.o文件

可执行文件

共享目标文件:xxx.so文件

内核转储

一个ELF文件由以下四部分组成:

ELF头:描述文件的主要特性。位于文件的开始位置,主要目的是定位文件的其它部分。

程序头表:列举了所有有效的段和它们的属性。表里记着每个段的开始位置和位移,长度,因为放在二进制文件中,需要段表的描述信息才能把它们每个段分隔开。

节头表:包含对节的描述

节:ELF文件中的基本组成单位,包含了特定类型的数据,ELF文件的各种学习和数据存储在不同的节中,如代码节存储了可执行代码,数据节存储了全局变量和静态数据等。

最常见的节:

代码节(.text) 数据节(.data)

相关文章:

  • Kubernetes 使用 Kube-Prometheus 构建指标监控 +飞书告警
  • 粘贴到Word里的图片显示不全
  • Flutter_学习记录_各个屏幕的适配
  • 深度体验通义灵码2.0 AI 程序员
  • 基于SpringBoot的“宠物救助及领养平台”的设计与实现(源码+数据库+文档+PPT)
  • ctfshow——robots后台泄露
  • 多态的好处
  • 基于光度立体视觉的三维重建方法
  • Linux系统使用Docker部署Geoserver并做数据挂载进行地图服务的发布和游览
  • JAVA 集成 ElasticSearch
  • 力扣每日一题【算法学习day.132】
  • ARMS 助力假面科技研发运维提效,保障极致游戏体验
  • A097基于SpringBoot实现的社区博客管理系统
  • 百度云DeepSeek一体机:百舸、千帆和一见介绍及区别对比
  • Java.lang包中的常用类 --8个包装类型、Math、Class
  • 自动驾驶的等级划分
  • 逻辑架构与软件架构在PREEvision中的设计关系
  • 为Eclipse IDE安装插件IBM编程助手watsonx Code Assistant
  • 计算机创造的奇迹——C语言
  • 基于springboot+vue的新生报到管理系统
  • 来沪一个月几乎未花住宿钱,女子虚构卫生问题屡薅酒店羊毛被刑拘
  • 国台办:实现祖国完全统一是大势所趋、大义所在、民心所向
  • 阿坝州委书记徐芝文已任四川省政府党组成员
  • 火车站员工迟到,致出站门未及时开启乘客被困?铁路部门致歉
  • 专访|西蒙·斯特朗格:以“辞典”的方式讲述二战家族史
  • 马上评丨学术不容“近亲繁殖”