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

news2025/5/31 18:38:58

什么是库?

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

就比如我们使用的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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2391714.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《软件工程》第 13 章 - 软件维护

知识思维导图 13.1 软件维护与进化的概念 1. 核心概念 软件维护&#xff1a;软件交付使用后&#xff0c;为纠正错误、改善性能或其他属性而进行的修改过程软件进化&#xff1a;随着时间推移&#xff0c;软件系统为适应环境变化和用户需求而不断演变的过程 2. 维护类型&#…

2024 CKA模拟系统制作 | Step-By-Step | 12、创建多容器Pod

目录 免费获取题库配套 CKA_v1.31_模拟系统 一、题目 二、考点分析 1. 多容器 Pod 的理解 2. YAML 配置规范 3. 镜像版本控制 三、考点详细讲解 1. 多容器 Pod 的工作原理 2. 容器端口冲突处理 3. 资源隔离机制 四、实验环境搭建步骤 总结 免费获取题库配套 CKA_v…

python:selenium爬取网站信息

关注我&#xff0c;精彩不错过&#xff01; 前言 使用python的requests模块还是存在很大的局限性&#xff0c;例如&#xff1a;只发一次请求&#xff1b;针对ajax动态加载的网页则无法获取数据等等问题。特此&#xff0c;本章节将通过selenium模拟浏览器来完成更高级的爬虫抓…

满天星之canvas实现【canvas】

展示 文章目录 展示Canvas 介绍【基础】简介兼容性关键特性注意事项应用场景&#xff1a;基本示例 满天星代码实现【重点】代码解释 全量代码【来吧&#xff0c;尽情复制吧少年】html引入JS代码 参考资源 Canvas 介绍【基础】 简介 Canvas是一个基于HTML5的绘图技术&#xff0…

【开源解析】基于PyQt5+Folium的谷歌地图应用开发:从入门到实战

&#x1f310;【开源解析】基于PyQt5Folium的谷歌地图应用开发&#xff1a;从入门到实战 &#x1f308; 个人主页&#xff1a;创客白泽 - CSDN博客 &#x1f525; 系列专栏&#xff1a;&#x1f40d;《Python开源项目实战》 &#x1f4a1; 热爱不止于代码&#xff0c;热情源自每…

在 Ubuntu 22.04 LTS 上离线安装 Docker

在 Ubuntu 22.04 LTS 上离线安装 Docker 一、准备工作 1.1 获取目标系统信息 在目标 Ubuntu 22.04 LTS 系统上&#xff0c;先执行以下命令确认架构信息&#xff1a; uname -m lsb_release -a一般返回如下信息&#xff1a; 1.2 需要一台可联网的机器 准备一台可以连接互联网…

python调用langchain实现RAG

一、安装langchain 安装依赖 python -m venv env.\env\Scripts\activatepip3 install langchainpip3 install langchain-corepip3 install langchain-openaipip3 install langchain-communitypip3 install dashscopepip3 install langchain_postgrespip3 install "psyc…

触控精灵 ADB运行模式填写电脑端IP教程

•ADB模式&#xff0c;如果你手机已经root则可以直接运行&#xff0c;无需安装电脑端。 •ADB模式&#xff0c;如果你手机没有root&#xff0c;那你可以windows电脑下载【极限投屏】软件&#xff0c;然后你的手机和电脑的网络要同一个wifi&#xff0c;然后把你电脑的ip地址填写…

uniapp|实现多端图片上传、拍照上传自定义插入水印内容及拖拽自定义水印位置,实现水印相机、图片下载保存等功能

本文以基础视角,详细讲解如何在uni-app中实现图片上传→水印动态编辑→图片下载的全流程功能。 目录 引言应用场景分析(社交媒体、内容保护、企业素材管理等)uniapp跨平台开发优势核心功能实现​图片上传模块多来源支持:相册选择(`uni.chooseImage`)与拍照(`sourceType:…

linux有效裁剪视频的方式(基于ffmpeg,不改变分辨率,帧率,视频质量,不需要三方软件)

就是在Linux上使用OBS Studio录制一个讲座或者其他视频&#xff0c;可能总有些时候会多录制一段时间&#xff0c;但是如果使用剪映或者PR这样的工具在导出的时候总需要烦恼导出的格式和参数&#xff0c;比如剪映就不支持mkv格式的导出&#xff0c;导出成mp4格式的视频就会变得很…

服务器密码安全运维解决新思路:凭据管理SMS+双因素SLA认证结合的方案

引言&#xff1a;云服务器安全成本困局 在云计算渗透率突破60%的今天&#xff0c;中小企业正面临严峻的安全悖论&#xff1a;某权威机构数据显示&#xff0c;72%的云上数据泄露事件源于凭据管理不当&#xff0c;而传统安全解决方案的采购成本往往超过中小企业年利润的8%。这种…

论文阅读笔记——In-Context Edit

ICEdit 论文阅读笔记 指令图像编辑现有方法的局限&#xff1a; 微调类方法&#xff08;InstructPix2Pix、Emu Edit、 Ultra Edit&#xff09;&#xff1a;需要大规模数据和算力、精度高但效率低且泛化性低&#xff1b;免训练方法&#xff08;Prompt-to-Prompt、 StableFlow&am…

【后端高阶面经:MongoDB篇】41、MongoDB 是怎么做到高可用的?

一、MongoDB高可用核心架构&#xff1a;副本集&#xff08;Replica Set&#xff09;设计 &#xff08;一&#xff09;副本集角色与拓扑结构 1. 三大核心角色 角色职责描述资源占用选举权重数据存储Primary唯一接收写请求的节点&#xff0c;将操作日志&#xff08;Oplog&…

DMBOK对比知识点整理(4)

1.常见数据质量维度 常见数据质量维度(DMBOK-P353)质量维度

day12 leetcode-hot100-21(矩阵4)

240. 搜索二维矩阵 II - 力扣&#xff08;LeetCode&#xff09; 1.暴力法O(m*n) 思路&#xff1a;两层for循环即可。 2.二分查找O(m*logn) 思路&#xff1a;每行都用二分查找,因为每行都是排好序的 class Solution {public boolean searchMatrix(int[][] matrix, int targe…

提问:鲜羊奶是解决育儿Bug的补丁吗?

在育儿这个"系统工程"中&#xff0c;过度提醒就像冗余代码&#xff1a;"快写作业"&#xff08;重复调用&#xff09;、"多穿衣服"&#xff08;异常捕获&#xff09;、"别玩手机"&#xff08;进程阻断&#xff09;。羊大师技术育儿实验…

关于数据仓库、数据湖、数据平台、数据中台和湖仓一体的概念和区别

我们谈论数据中台之前&#xff0c; 我们也听到过数据平台、数据仓库、数据湖、湖仓一体的相关概念&#xff0c;它们都与数据有关系&#xff0c;但他们和数据中台有什么样的区别&#xff0c; 下面我们将围绕数据平台、数据仓库、数据湖和数据中台的区别进行介绍。 一、相关概念…

什么是可重组机器人?

可重组机器人是一种具有高度灵活性和适应性的新型机器人系统&#xff0c;能够根据不同任务需求&#xff0c;快速改变自身结构和功能。下面我从概念、结构、特点、应用领域、发展趋势等方面&#xff0c;为你详细介绍&#xff1a; 概念&#xff1a;可重组机器人是由多个标准化、模…

4、docker compose

1、介绍 Docker Compose 是 Docker 官方提供的容器编排工具&#xff0c;用于简化多容器应用的开发、部署和管理。它通过声明式配置文件&#xff08;YAML格式&#xff09;定义容器化应用的服务、网络、存储等组件及其依赖关系&#xff0c;使用户能够通过单一命令快速启动、停止…

SQL里几种JOIN连接

数据信息&#xff1a; 员工表EMP 部门表DEPT 一、INNER JOIN&#xff08;内连接&#xff09; 作用&#xff1a;只返回两个表中完全匹配的行&#xff0c;相当于取交集。 场景&#xff1a;查询「有部门的员工信息」。 示例&#xff1a; SELECT 员工.姓名, 部门.部门名称 FR…