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

深入了解linux系统—— 库的制作和使用

什么是库?

库,简单来说就是现有的,成熟的代码;

就比如我们使用的C语言标准库,我们经常使用输入scanf和输出printf,都是库里面给我们实现好的,我们可以直接进行服用。

库呢又分为静态库和动态库,在Linux中静态库文件后缀.a,动态库文件后缀.so;在Windows中静态库文件后缀.lib,动态库文件后缀.dll

这里注意一下库的命名规则:

库的命名都是以lib开头,.a/.so为后缀;去掉前缀lib和后缀.a/.so剩下的部分才是库的名字;

例如C标准库libc.so,去掉前缀和后缀,c就是库的名字。

在这里插入图片描述

动静态链接

在之前我们知道gcc/g++在编译时默认使用动态链接,若想要进行静态链接就要带-static选项;

  • 静态链接,本质上就是程序在编译链接时,将静态库的内容链接到可执行文件中,这样可执行程序在执行时就不会再依赖库;但是静态链接的可执行文件都比较大。
  • 动态链接:本质上就是程序在编译链接时,在可执行文件和动态库之间建立某种关联,这样可执行程序在执行时机会依赖动态库。

静态库

库分为静态库和动态库,那什么是静态库呢?

静态库简单来说就是所有.o文件的归档文件,也就是说静态库就是将所有的.o文件合并在一起。

这样在链接形成可执行程序时,将静态库和.o文件再合并在一起形成可执行文件。

静态库的制作

这里提供两份源文件代码mystdio.cmystring.c来制作库

//mystdio.c
#include "mystdio.h"
MYFILE* BuyFile(int fd, int flag)
{MYFILE* myfile = (MYFILE*)malloc(sizeof(MYFILE));myfile->fileno = fd;myfile->flag = flag;myfile->bufflen = 0;myfile->flush_buff = LINE_FLUSH;//初始化缓冲区memset(myfile->outbuff, 0, sizeof(myfile->outbuff));return myfile;
}
MYFILE* MyOpen(const char* pathname, const char* mode)
{//确定文件的打开方式int fd = -1;int flag = 0;if(strcmp(mode, "w") == 0){flag = O_CREAT | O_WRONLY | O_TRUNC;fd = open(pathname, flag, 0666);}else if(strcmp(mode, "a") == 0){flag = O_CREAT | O_WRONLY | O_APPEND;fd = open(pathname, flag, 0666);}else if(strcmp(mode, "r"))                                                                                                                                                      {flag = O_RDONLY;fd = open(pathname, flag);}else{//???}if(fd < 0) return NULL;//打开文件失败return BuyFile(fd,flag);
}
void MyClose(MYFILE* file)
{if(file == NULL) return;if(file->fileno < 0) return;MyFlush(file);close(file->fileno);free(file);
}
int MyWrite(MYFILE* file, void* str, int len)
{//将数据拷贝到缓冲区当中//int n = 0;if(file->bufflen + len > MAX){//n = MAX - file->bufflen;                                                                                                                                                  //memcpy(file->outbuff + file->bufflen, str, n);//MyFlush(file);MyFlush(file);}//memcpy(file->outbuff + file->bufflen,(void*)((char*)str + n), strlen((char*)str) - n);memcpy(file->outbuff + file->bufflen,str,len);file->bufflen += len;if(file->flush_buff & NONE_FLUSH)MyFlush(file);else if((file->flush_buff & LINE_FLUSH) && (file->outbuff[file->bufflen-1] == '\n' || file->bufflen == MAX))MyFlush(file);else if((file->flush_buff & FULL_FLUSH) && (file->bufflen == MAX))MyFlush(file);return 0;
}
void MyFlush(MYFILE* file)
{if(file->bufflen <= 0)  return;write(file->fileno, file->outbuff, file->bufflen);file->bufflen = 0;fsync(file->fileno);
}//mystring.c
#include "mystring.h"
int my_strlen(const char* str)    
{    const char* s = str;    while(*s != '\0')    s++;    return s - str;    
}

头文件mystdio.hmystring.h

//mystdio.h
#include <sys/stat.h>    
#include <fcntl.h>    
#include <string.h>    
#include <stdlib.h>    
#include <unistd.h>    
#define MAX 10//缓冲区大小                                           
#define NONE_FLUSH  001 //0001    
#define LINE_FLUSH  002 //0010    
#define FULL_FLUSH  004 //0100
typedef struct IO_FILE{    int fileno;//文件描述符    int flag;    char outbuff[MAX]; //缓冲区    int bufflen; //缓冲区内容长度    int flush_buff;    
}MYFILE;
MYFILE* MyOpen(const char* pathname, const char* mode);    
void MyClose(MYFILE* file);    
int MyWrite(MYFILE* file, void* str, int len);    
void MyFlush(MYFILE* file); 
//mystring.h
int my_strlen(const char* str);   

静态库是如何生成的呢?

静态库是.o文件的归档文件,所以我们在制作库时,就要现将所有的.c文件编译形成.o文件

在这里插入图片描述

有了.o文件,现在就要对这些.o文件进行归档形成静态库;

这里就要使用指令ar -rc(其中argnu归档工具,-rc表示replacecreate

在这里插入图片描述

静态库的使用

了解了静态库是如何制作的,那我们如何去使用静态库呢?

站在一个库的使用者的角度,我们拿到一个库时,我们并不知道这个库里都实现了哪些方法;我们就要参考所有的头文件。

所以我们就可以把头文件看做库的使用手册,在头文件中记录了库中实现的方法。

在这里插入图片描述

现在我们获得了静态库libmyc.a和头文件mystdio.hmystring.h

我们通过查看头文件,知道了库libmyc.a实现了哪些方法,实现了test.c中使用了libmyc.a中的方法

  #include "mystdio.h"    #include "mystring.h"    int main()    {    MYFILE* myfile = MyOpen("log.txt","w");    if(myfile == NULL) return -1;    const char* str = "abc-abc\n";    MyWrite(myfile, (void*)str, my_strlen(str));    MyWrite(myfile, (void*)str, my_strlen(str));MyClose(myfile);    printf("%d\n",my_strlen(str));    return 0;    } 

这里我们直接编译test.c

在这里插入图片描述

可以看到,存在链接时报错,找不到这些方法;这是因为gcc默认情况下只会去链接C标准库,如果想要去链接第三方库,就要带-l选项指明要链接的库。

gcc test.c -l库名

在这里插入图片描述

但是我们可以看到,-lmyc指明了要链接哪一个库,却找不到这个库;

这是因为gcc只会在指定路径下去寻找库,而我们要链接的库myc在当前路径下,并不在系统的指定路径下;

所以我们要使用gcc-L选项来指明我们要链接的库的路径

gcc test.c -l库名 -L库的路径

在这里插入图片描述

如上图所示,我们要链接第三方库,带-l选项指明库的名称;如果要链接的库博主系统路径下,带-L选项指明库的路径。

补充:gcc -I选项

在上述操作中,我们的头文件都在当前路径下,如果头文件不在当前路径下呢?

在这里插入图片描述

我们把静态库和头文件分别放在./bin/lib./bin/include路径下;

在这里插入图片描述

在编译时gcc在当前路径下找不到头文件,就会报错;

解决方法:

  • gcc编译时带-I选项,指明头文件的路径。
  • 在源文件引用头文件时,指明路径;#include "./bin/include/mystdio.h"

在这里插入图片描述

动态库

动态库:程序在运行时才会去链接动态库的代码,多个程序可以共享;

一个可执行文件和动态库链接仅仅包含它用到的函数入口地址的一个表。

可执行文件在开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中拷贝到内存中;这一过程称为动态链接

动态库可以被多个程序共享,所以动态链接的可执行文件更下,节省了磁盘空间。

动态库的制作

我们知道了静态库是.o的归档文件,那动态库呢?

动态库又是如何生成的呢?

还是上述的代码mystd.cmystring.cmystdio.hmystring.h

首先生成动态库,也是要先将所有的.c文件编译形成.o文件,与生成静态库不同的是,生成动态库在编译形成.o文件是需要带-fPIC选项,产生位置无关码。

在这里插入图片描述

其次,就是将这些.o文件形成动态库,这里使用的是gcc-shared选项

gcc -o libmyc.so *.o -shared

在这里插入图片描述

动态库的使用

动态库的使用和静态库使用,可以说一模一样的了;

这里就直接演示使用了:

在这里插入图片描述

这里我们发现一个问题,我们gcc链接libmyc.so库,编译链接形成了可执行程序a.out,在运行时它找不到libmyc.so库?

在这里插入图片描述

通过ldd查看a.out可执行程序依赖的库,可以发现确实找不到libmyc.so库。

这是为什么呢?我们在gcc编译时,使用-L选项不是指明libmyc.so的路径了吗?

这是因为我们gcc编译是-L选项指明libmyc的路径,这是告诉gcc我们要链接的库在哪,但是系统并不知道我们的库在哪里;

因为这里是动态链接,在可执行程序执行时,系统就会去找库libmyc.so,就会发现系统找不到这个库。

运行时搜索路径

那我们知道了动态链接我们自己的库,在可执行程序运行时,系统找不到我们的库,那如何解决这一问题呢?

这里解决方案有很多,我们一一来看:

首先,我们要知道,系统为什么找不到我们自己的库,却可以找到C语言标准库?

因为我们C语言标准库在系统的指定目录下,可执行程序在运行时,系统会在指定路径下去寻找,所以C语言标准库就可以被系统找到。

1. 将我们的库拷贝到系统指定路径下,系统指定路径一般指/usr/lib/usr/local/lib/lib64

在这里插入图片描述

2. 在系统指定文件中建立软链接

这里我们库比较小,如果我们的库比较大,拷贝到系统指定路径下很不现实;

所以我们就可以在系统指定路径下建立同名软链接。

在这里插入图片描述

3. 更改环境变量LD_LIBRARY_PATH

上面两种方法,都是将我们的库放入(拷贝/软链接)系统指定文件中;

我们还可以通过修改环境变量LD_LIBRARY_PATH,让我们的库能够被系统找到

在这里插入图片描述

这里,博主自己的系统配置过vim,没有配置的该环境变量可能就是空了

在这里插入图片描述

我们可以修改这个环境变量,把我们库的路径加上去,这样系统就可以找到我们的库libmyc.so了。

在这里插入图片描述

4. ldconfig配置

除了上述三种方法之外呢,我们还可以进行配置/etc/ld.so.conf.d/,并更新ldconfig

这样系统也可以找到我们的库libmyc.so

在这里插入图片描述

本篇文章的大致内容到这里就结束了,感谢各位大佬的支持

简单总结:

静态库制作:ar -rc将所有.o位置归档。

动态库制作:gcc-shared选项,将所有.o文件形成动态库

库的使用:gcc-l指定链接某些库,-L指明要链接库所在的路径,-I指明头文件所在的路径

可执行程序在运行时,系统找到我们自己库的方法:将我们的库(拷贝/创建同名软链接)在系统指定路径中、修改环境变量LD_LIBRARY_PATH、配置/etc/ld.so.conf.d/中的文件,并更新ldconfig

相关文章:

  • IBM DB2数据库管理工具IBM Data Studio
  • Unity QFramework 简介
  • Git 教程 | 如何将指定文件夹回滚到上一次或某次提交状态(命令详解)
  • 基于多尺度卷积和扩张卷积-LSTM的多变量时间序列预测
  • Orcad 修复Pin Name重复问题
  • MonoPCC:用于内窥镜图像单目深度估计的光度不变循环约束|文献速递-深度学习医疗AI最新文献
  • 5.3.1_2二叉树的层次遍历
  • Relooking:损失权重λ 、梯度权重α、学习率η
  • http传输协议的加密
  • 【C/C++】线程安全初始化:std::call_once详解
  • VoltAgent 是一个开源 TypeScript 框架,用于构建和编排 AI 代理
  • 【题解-洛谷】B4278 [蓝桥杯青少年组国赛 2023] 简单算术题
  • Java 注解与反射(超详细!!!)
  • React从基础入门到高级实战:React 生态与工具 - React 国际化(i18n)
  • Mac系统下,利用wget批量下载ICESat-2测高内陆水位高数据ALT13
  • SpringBoot整合RocketMQ--实例
  • RTX腾讯通停服后,有哪些兼容Linux及移动端的升级途径?
  • SQL(Database Modifications)
  • 杏仁海棠花饼的学习日记第十四天CSS
  • Windows 11 全角半角切换方法
  • wordpress网站的配置文件/一个新手怎么做电商
  • 江苏常州网/seo技术优化技巧
  • 帝国做的网站怎么上传/百度关键词搜索排名
  • 海外网入口/快速排名优化
  • 网站开发公司总汇/专业的推广公司
  • 大理建设工程信息网站/合肥百度搜索优化