【ONE·Linux || 基础IO(二)】

news2024/11/15 8:31:27

总言

  文件系统与动静态库相关介绍。

文章目录

  • 总言
  • 2、文件系统
    • 2.1、背景知识
    • 2.2、磁盘管理
      • 2.2.1、磁盘文件系统图
      • 2.2.2、inode与文件名
    • 2.3、软硬链接
  • 3、动静态库
    • 3.1、站在编写库的人的角度:如何写一个库?
      • 3.1.1、静态库制作
      • 3.1.3、动态库制作
    • 3.2、站在使用库的人的角度:如何用别人提供的库?
      • 3.2.1、使用静态库
      • 3.2.2、使用动态库

  
  

2、文件系统

2.1、背景知识

在这里插入图片描述

  
  说明一:
  掉电易失存储介质:内存
  永久性存储介质:磁盘、SSD、U盘、flash卡、光盘、磁带
  
  磁盘是外设,且还是计算机中唯一一个机械设备,与OS等相比其操作效率很慢,因此OS会有一定的提速方式。
  
  
  说明二:
  CHS与LBA之间的转换:
在这里插入图片描述
  
  
  说明三:
  虽然硬件层面扇区通常为512bit,但操作系统(文件系统)与磁盘进行IO的基本单位是4kb,原因如下:
  1、若IO交互的基本单位太小,有可能导致多次IO,降低效率。
  2、使得硬件和软件解耦合。若IO交互使用和磁盘一样的单位,当磁盘基本单位变大时,OS也要随之修改。
  
  
  

2.2、磁盘管理

2.2.1、磁盘文件系统图

  1)、解释磁盘文件系统图各小块含义
在这里插入图片描述
  整体说明: 磁盘是典型的块设备,硬盘分区被划分为一个个的block。上图为磁盘文件系统图(Linux ext2文件系统,不同内核内存映像有所不同)。一个block的大小是由格式化的时候确定的,并且不可以更改,例如mke2fs的-b选项可以设定block大小为1024、2048或4096字节。上图中启动块(Boot Block)的大小是确定的。
  
  1、数据区(Data block):多个4KB(扇区×8)大小的集合,通常用于存放文件内容。
  PS:文件=内容+属性,Linux在磁盘上存储文件时,是将内容和属性分开存储的。
  
  2、i节点表(inode Table):inode是大小为128字节的空间,保存着对应文件的属性,如文件大小、所有者、最近修改时间等。inode table是该组块(block group)内所有文件的inode空间的集合,为了标识每个inode的唯一性,会为其附一个inode编号,也存储在各自的inode空间中。
  PS:一般而言,一个文件,对应一个inode,用于记录其文件属性,同时该inode有一个标识编号(inode编号)。

[wj@VM-4-3-centos T0730]$ ls -li //加-i选项,可查看每个文件的inode编号
total 24 
789948 -rw-rw-r-- 1 wj wj   51 Jul 30 21:45 log.txt
790002 -rw-rw-r-- 1 wj wj   65 Jul 30 12:24 makefile
790001 -rw-rw-r-- 1 wj wj 2929 Jul 30 21:45 myfile.c
789573 -rwxrwxr-x 1 wj wj 8568 Jul 30 21:45 myfile.o
[wj@VM-4-3-centos T0730]$ 

  
  3、块位图(Block Bitmap):Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用。将bit位与特定的data block中数据块一一对应,若比特位为1,则该数据块被占用,为0表示未被占用。
  
  4、inode位图(inode Bitmap):每个bit表示一个inode是否空闲可用。同理,将比特位与inode一一对应,为1表示占用,为0表示未被占用。
  PS:block bitmap和inode bitmap是用于管理信息的,扫描这两区域,即可查看该块组内inode和数据块使用程度。
  
  5、块组描述符(Group Descriptor Table):GDT,用户描述块组属性信息,如该块组多大,已经使用多少空间,有多少个inode/data block,占用和未占用情况。
  
  
  格式化说明: 如上述,将块组分割成上述内容,并写入相关的管理数据,在磁盘内就能让一个文件的信息可追溯、可管理。将每个块组统一规定为如上格式,那么整个分区就被写入 了文件系统信息。将这种操作称之为格式化。
  
  
  2)、其它说明
  1、一个文件对应一个inode编号、inode属性节点,那么,一个文件只能有一个block吗?
  回答:不一定。data block大小有限,当文件内容很大时,一个数据块不足以存储所有文件内容,此时就需要多个数据块支持。
  
  2、哪些block属于同一个文件?如何找到它们?
  3、文件=内容+属性,通过inode编号可以找到文件inode属性集合,那么怎么找到文件内容呢?
  
  回答:inode中,除了保存文件的属性(大小、权限、inode编号等),还有一个其它属性,用于保存同块组内对应文件的数据块编号。
在这里插入图片描述
  
  
  4、当这个文件特别大时,inode中的blocks也不够存储对应data blocks的量,又该怎么办?
在这里插入图片描述

  
  
  

2.2.2、inode与文件名

  1)、问题引入:如何找到一个文件?
  回答:找到一个文件,首先要找到其inode编号,根据inode编号获取特定的块组block group ,在块组内的inode table中找到对应的inode,从而能够获取到文件的属性与内容。
  
  那么,如何获取到文件的inode编号呢?
  
  
  2)、文件inode编号与文件名说明
  1、inode属性中并不存储文件名称,文件名称实则是由该文件隶属的目的来保存的。
  
  2、目录也是文件,其内部可以具有多个文件,同一个目录下的文件不能有重名。对于一个目录而言,既然它是文件,就具有自己的inode,也有对应的data blocks。而根据1可知,inode中不保存文件名称,因此,文件的文件名称实则是与其inode编号建立映射关系,保存在目录的data blocks中的。
  
  3、上述内容也解释了进入目录、创建文件、显示文件名与属性中权限需求说明。如创建一个文件,需要把文件的inode编号和文件名称建立映射关系并保存在目录的data blocks中,因此需要目录有w权限。读取文件时也需要先找到对应的inode编号,就需要访问目录的data blocks,因此目录要有r权限。
  
  
  3)、根据上述内容可回答三个问题

  问题1、创建文件,系统做了什么?

[root@localhost linux]# touch abc
[root@localhost linux]# ls -i abc
263466 abc

  回答:创建一个新文件主要有以下四个操作:
    ① 存储属性 :内核先找到一个空闲的i节点(这里是263466),内核把文件的属性信息记录到其中。
    ② 存储数据 :假设该文件需要存储在三个磁盘块,内核需要找到了三个空闲的数据块:300,500,800。将内核缓冲区的第一块数据复制到300,下一块复制到500,以此类推。
    ③ 记录分配情况:将文件内容按顺序300、500、800存放。内核在inode上的磁盘分布区记录了上述块列表。
    ④添加文件名到目录:新的文件名abc。内核将入口(263466,abc)添加到目录文件。文件名和inode之间的对应关系将文件名和文件的内容及属性连接起来。
在这里插入图片描述
  
  
  问题2、删除文件,系统做了什么?
  回答:以文件名索引inode编号,置零inode bitmap,置零data bitmap,断开目录中记录的映射关系。PS:对应文件内容和inode table中的属性,可以不用清除。(类比参考数据结构阶段学习的各类删除接口)
  
  延伸:删除的文件能够恢复吗?
  回答:可以,恢复找到inode编号就能找对对应文件。前提是对应位置的inode、data block没有被重复占用。
  
  
  问题3、查看文件,系统做了什么?
  回答:以文件名为索引,找到inode编号,显示对应的文件信息。例如ls 只显示目录下的所有文件名称,加各项选项会显示其它属性信息。
  
  
  4)、周边问题
  1、组块中,分区中各小块是由谁来划分的?
  回答:格式化操作的过程,就是在磁盘中写入文件系统的过程。
  
  
  2、创建文件,写入失败,或者直接创建文件失败,分析可能的原因?
  回答:inode table大小固定,data blocks大小固定。以下情况可能导致创建文件失败:
    ①inode已满,data block未满;
    ②inode未满,data block已满。
  
  
  

2.3、软硬链接

  1)、如何建立软硬链接?
  相关指令如下:
  ln -s:创建软链接,如ln -s testlink1.txt soft.link
  ln:创建硬链接,如ln testlink2.txt hard.link
  
  代码演示如下:

[wj@VM-4-3-centos T0804]$ mkdir dir
[wj@VM-4-3-centos T0804]$ touch testlink1.txt
[wj@VM-4-3-centos T0804]$ touch testlink2.txt
[wj@VM-4-3-centos T0804]$ touch testlink3.txt

[wj@VM-4-3-centos T0804]$ ls -li
total 4
790036 drwxrwxr-x 2 wj wj 4096 Aug  4 15:21 dir
790037 -rw-rw-r-- 1 wj wj    0 Aug  4 15:21 testlink1.txt
790038 -rw-rw-r-- 1 wj wj    0 Aug  4 15:21 testlink2.txt
790039 -rw-rw-r-- 1 wj wj    0 Aug  4 15:21 testlink3.txt

[wj@VM-4-3-centos T0804]$ ln -s testlink1.txt soft.link
[wj@VM-4-3-centos T0804]$ ln testlink2.txt hard.link

[wj@VM-4-3-centos T0804]$ ls -li
total 4
790036 drwxrwxr-x 2 wj wj 4096 Aug  4 15:21 dir
790038 -rw-rw-r-- 2 wj wj    0 Aug  4 15:21 hard.link
790040 lrwxrwxrwx 1 wj wj   13 Aug  4 15:25 soft.link -> testlink1.txt
790037 -rw-rw-r-- 1 wj wj    0 Aug  4 15:21 testlink1.txt
790038 -rw-rw-r-- 2 wj wj    0 Aug  4 15:21 testlink2.txt
790039 -rw-rw-r-- 1 wj wj    0 Aug  4 15:21 testlink3.txt
[wj@VM-4-3-centos T0804]$ 

  结果观察:
在这里插入图片描述

  PS:unlink XXXX可删除链接关系。

[wj@VM-4-3-centos uselib]$ ln -s  main.c main.so #建立软链接
[wj@VM-4-3-centos uselib]$ ll
total 28
-rw-rw-r-- 1 wj wj  157 Aug  4 21:57 main.c
-rwxrwxr-x 1 wj wj 8440 Aug  5 17:54 main.out
lrwxrwxrwx 1 wj wj    6 Aug  5 18:57 main.so -> main.c
-rw-rw-r-- 1 wj wj   35 Aug  5 16:13 makefile
drwxrwxr-x 5 wj wj 4096 Aug  5 16:07 output
drwxrwxr-x 4 wj wj 4096 Aug  5 10:55 staticlib

[wj@VM-4-3-centos uselib]$ unlink main.so #删除
[wj@VM-4-3-centos uselib]$ ll
total 28
-rw-rw-r-- 1 wj wj  157 Aug  4 21:57 main.c
-rwxrwxr-x 1 wj wj 8440 Aug  5 17:54 main.out
-rw-rw-r-- 1 wj wj   35 Aug  5 16:13 makefile
drwxrwxr-x 5 wj wj 4096 Aug  5 16:07 output
drwxrwxr-x 4 wj wj 4096 Aug  5 10:55 staticlib

  
  
  2)、软硬链接有什么区别?

在这里插入图片描述软硬链接本质区别: 有无独立inode编号。

  回答:软链接有独立的inode,说明软链接是一个独立的文件。硬链接没有独立的inode,说明硬链接不是一个独立的文件。

  问题:它们之间的这种独立性的差距有什么意义?
  
  

在这里插入图片描述对软链接:

  特性:软链接的文件内容指向被链接文件的对应路径。因此,删除软链接文件,被链接文件仍旧存在(相当于Windows下删除快捷键,但所指向程序仍旧存在)。

[wj@VM-4-3-centos test01]$ ls -li
total 0
790040 lrwxrwxrwx 1 wj wj 13 Aug  4 15:25 soft.link -> testlink1.txt
790037 -rw-rw-r-- 1 wj wj  0 Aug  4 15:21 testlink1.txt
790038 -rw-rw-r-- 1 wj wj  0 Aug  4 15:21 testlink2.txt

[wj@VM-4-3-centos test01]$ rm soft.link //删除软链接文件,实际被链接文件仍旧存在

[wj@VM-4-3-centos test01]$ ls -li
total 0
790037 -rw-rw-r-- 1 wj wj 0 Aug  4 15:21 testlink1.txt
790038 -rw-rw-r-- 1 wj wj 0 Aug  4 15:21 testlink2.txt
[wj@VM-4-3-centos test01]$ 

  
  
  相关应用:相当于Windows下的快捷方式
在这里插入图片描述

  
  

在这里插入图片描述对硬链接:

  硬链接的inode为被链接文件的inode,不是真正的创建新文件。创建硬链接时,只是在指定目录下,建立文件名与指定indoe的映射关系(相当于起别名)。
  
  属性中存在硬链接数:用于确定多少个文件名与该indoe关联。实际删除文件时,并不是把该文件真正删除,而是减少其硬链接数,直到其为0,该文件才真正删除。
在这里插入图片描述
  
  
  
  默认创建一个普通文件、目录,其默认硬链接数说明:
  问题:如下,为什么默认创建一个普通文件,其硬链接数为1?为什么默认创建一个普通目录,其硬链接数为2?

[wj@VM-4-3-centos test01]$ mkdir dir
[wj@VM-4-3-centos test01]$ touch test.txt
[wj@VM-4-3-centos test01]$ ls -li
total 4
790037 drwxrwxr-x 2 wj wj 4096 Aug  4 19:11 dir
790038 -rw-rw-r-- 1 wj wj    0 Aug  4 19:11 test.txt
[wj@VM-4-3-centos test01]$ 

  对普通文件:创建一个普通文件,其自身文件名和自身inode建立关系,故硬链接数为1。如上述例子中的(790038,test.txt)
  
  对目录:创建一个空目录,除了自身目录名和inode建立关联,进入目录内,可看到隐藏目录.(代表当前路径),也与该inode关联,故而空目录的链接数2。PS:若目录内还有其它子目录,则子目录中隐藏文件..也和该inode关联。
在这里插入图片描述

[wj@VM-4-3-centos test01]$ ls
dir  test.txt
[wj@VM-4-3-centos test01]$ ls -ali
total 12
790036 drwxrwxr-x 3 wj wj 4096 Aug  4 19:11 .
790035 drwxrwxr-x 4 wj wj 4096 Aug  4 15:47 ..
790037 drwxrwxr-x 2 wj wj 4096 Aug  4 19:11 dir
790038 -rw-rw-r-- 1 wj wj    0 Aug  4 19:11 test.txt
[wj@VM-4-3-centos test01]$ cd dir
[wj@VM-4-3-centos dir]$ ls -ali
total 8
790037 drwxrwxr-x 2 wj wj 4096 Aug  4 19:11 .
790036 drwxrwxr-x 3 wj wj 4096 Aug  4 19:11 ..
[wj@VM-4-3-centos dir]$ 

  
  
  
  

3、动静态库

3.1、站在编写库的人的角度:如何写一个库?

3.1.1、静态库制作

  1)、准备工作
  为了方便演示,此处写头文件与方法实现分离,写一两个演示代码:

[wj@VM-4-3-centos test03]$ cat accum.h
#pragma once 
#include<stdio.h>

extern void accum(int from, int to);

[wj@VM-4-3-centos test03]$ cat accum.c
#include "accum.h"

int accumulate(int from, int to)
{
    int sum = 0;
    int i = 0;
    for(i = from; i <= to; ++i)
    {
        sum+=i;
    }
    return sum;
}

[wj@VM-4-3-centos test03]$ cat print.h

#pragma once 
#include<stdio.h>
#include<time.h>

extern void print(const char* str);

[wj@VM-4-3-centos test03]$ cat print.c
#include "print.h"

void print(const char* str)
{
    printf("%s[%d]\n",str,(int)time(NULL));
}

  假设以上两个为待封装库的相关内容实现,这里我们分别使用两个目录,用以演示库制作与库使用。注意:制作库时,库中不能存在main函数。

[wj@VM-4-3-centos test03]$ ls
mklib  uselib
[wj@VM-4-3-centos test03]$ tree
.
|-- mklib
|   |-- accum.c
|   |-- accum.h
|   |-- print.c
|   `-- print.h
`-- uselib

2 directories, 4 files
[wj@VM-4-3-centos test03]$ 

  使用一个makefile来完成上述内容的编译过程。(PS:该文件后续还会改动)

[wj@VM-4-3-centos mklib]$ cat makefile 
.PHONY:all
all:print.o accum.o

print.o:print.c
	gcc -c print.c -o print.o
accum.o:accum.c
	gcc -c accum.c -o accum.o

.PHONY:clean
clean:
	rm -rf *.o
	
[wj@VM-4-3-centos mklib]$ 

  
  
  
  2)、制作一个静态库

在这里插入图片描述1、问题:直接将.o文件和.h文件给别人,是否能形成可执行程序以供使用?

  一点准备工作:如下,将形成的accum.oaccum.hprint.oprint.h拷贝一份放入uselib目录中,用以演示:

[wj@VM-4-3-centos mklib]$ ll //当前文件
total 24
-rw-rw-r-- 1 wj wj  165 Aug  4 21:44 accum.c
-rw-rw-r-- 1 wj wj   75 Aug  4 21:44 accum.h
-rw-rw-r-- 1 wj wj  153 Aug  4 21:42 makefile
-rw-rw-r-- 1 wj wj   96 Aug  4 21:07 print.c
-rw-rw-r-- 1 wj wj   88 Aug  4 21:07 print.h

[wj@VM-4-3-centos mklib]$ make
gcc -c print.c -o print.o
gcc -c accum.c -o accum.o

[wj@VM-4-3-centos mklib]$ ll //生成.o文件
total 28
-rw-rw-r-- 1 wj wj  165 Aug  4 21:44 accum.c
-rw-rw-r-- 1 wj wj   75 Aug  4 21:44 accum.h
-rw-rw-r-- 1 wj wj 1280 Aug  4 21:44 accum.o
-rw-rw-r-- 1 wj wj  153 Aug  4 21:42 makefile
-rw-rw-r-- 1 wj wj   96 Aug  4 21:07 print.c
-rw-rw-r-- 1 wj wj   88 Aug  4 21:07 print.h
-rw-rw-r-- 1 wj wj 1576 Aug  4 21:42 print.o


  在ueslib目录中创建一个main.c文件,在该文件中使用这两个拟库。

[wj@VM-4-3-centos mklib]$ mv *.h *.o ../uselib //相关指令
[wj@VM-4-3-centos mklib]$ cd ../uselib/ //转到uselib文件中
[wj@VM-4-3-centos uselib]$ ls 
accum.h  accum.o  print.h  print.o  main.c
[wj@VM-4-3-centos uselib]$ cat main.c //写一个main.c,在其中用到这两个文件
#include "print.h"
#include "accum.h"

int main()
{
    print("hello main:");
    int ret = accumulate(1,50);
    printf("result:%d\n",ret);
    return 0;
}

  如下:我们能成功使用:

[wj@VM-4-3-centos uselib]$ gcc -o main.out main.c print.o accum.o
[wj@VM-4-3-centos uselib]$ ls
accum.h  accum.o  main.c  main.out  print.h  print.o
[wj@VM-4-3-centos uselib]$ ./main.out 
hello main:[1691157514]
result:1275
[wj@VM-4-3-centos uselib]$ 

在这里插入图片描述

  如上方式虽然能够演示成功, 一旦用于制作的库文件过多,这样交给方式有些繁琐,属于一种野生级别的方式。因此我们还需要将库进行打包归档。
  
  
  

在这里插入图片描述2、静态库制作:使用ar指令整理打包库(archive files:归档文件)

  相关指令:
  ①gcc -c XXX.c -o XXX.o ,获取.o二进制目标文件;
  ②ar -rc libXXX.a XXX.o XXX.o将库归档处理。
  此处要注意 libXXX.a中,lib.a为语法格式,中间名称可任意取。后面要打包几个.o文件就跟几个。
  
  
  
  演示如下:

[wj@VM-4-3-centos mklib]$ ll //mklib中的文件
total 28
-rw-rw-r-- 1 wj wj  165 Aug  4 21:44 accum.c
-rw-rw-r-- 1 wj wj   75 Aug  4 21:44 accum.h
-rw-rw-r-- 1 wj wj 1280 Aug  4 21:46 accum.o
-rw-rw-r-- 1 wj wj  153 Aug  4 21:42 makefile
-rw-rw-r-- 1 wj wj   96 Aug  4 21:07 print.c
-rw-rw-r-- 1 wj wj   88 Aug  4 21:07 print.h
-rw-rw-r-- 1 wj wj 1576 Aug  4 21:46 print.o

[wj@VM-4-3-centos mklib]$ ar -rc libstatic.a accum.o print.o //对.o文件进行归档打包

[wj@VM-4-3-centos mklib]$ ll
total 32
-rw-rw-r-- 1 wj wj  165 Aug  4 21:44 accum.c
-rw-rw-r-- 1 wj wj   75 Aug  4 21:44 accum.h
-rw-rw-r-- 1 wj wj 1280 Aug  4 21:46 accum.o
-rw-rw-r-- 1 wj wj 3074 Aug  5 10:13 libstatic.a //新生成的静态库
-rw-rw-r-- 1 wj wj  153 Aug  4 21:42 makefile
-rw-rw-r-- 1 wj wj   96 Aug  4 21:07 print.c
-rw-rw-r-- 1 wj wj   88 Aug  4 21:07 print.h
-rw-rw-r-- 1 wj wj 1576 Aug  4 21:46 print.o
[wj@VM-4-3-centos mklib]$ 

  
  使用makefile生成:

libstatic.a:print.o accum.o //形成静态库:step2
	ar -rc libstatic.a accum.o print.o

print.o:print.c //形成静态库:step1
	gcc -c print.c -o print.o
accum.o:accum.c //形成静态库:step1
	gcc -c accum.c -o accum.o

.PHONY:clean
clean:
	rm -rf *.o libstatic.a

[wj@VM-4-3-centos mklib]$ make clean
rm -rf *.o libstatic.a
[wj@VM-4-3-centos mklib]$ ls
accum.c  accum.h  makefile  print.c  print.h
[wj@VM-4-3-centos mklib]$ make
gcc -c print.c -o print.o
gcc -c accum.c -o accum.o
ar -rc libstatic.a accum.o print.o
[wj@VM-4-3-centos mklib]$ ll
total 32
-rw-rw-r-- 1 wj wj  165 Aug  4 21:44 accum.c
-rw-rw-r-- 1 wj wj   75 Aug  4 21:44 accum.h
-rw-rw-r-- 1 wj wj 1280 Aug  5 10:29 accum.o
-rw-rw-r-- 1 wj wj 3074 Aug  5 10:29 libstatic.a //所形成的静态库
-rw-rw-r-- 1 wj wj  230 Aug  5 10:20 makefile
-rw-rw-r-- 1 wj wj   96 Aug  4 21:07 print.c
-rw-rw-r-- 1 wj wj   88 Aug  4 21:07 print.h
-rw-rw-r-- 1 wj wj 1576 Aug  5 10:29 print.o
[wj@VM-4-3-centos mklib]$ 

  
  
  3)、发布库
  说明:该静态库目录分为两部分,其一为头文件目录include,其二为打包的库目录lib,这里我们仍旧使用makefile生成。
  在上述的makefile中再加入这段指令:

.PHONY:staticlib
staticlib:
	mkdir -p staticlib/include
	mkdir -p staticlib/lib 
	cp -rf *.h staticlib/include
	cp -rf *.a staticlib/lib 

  由此我们就得到一个staticlib静态库目录,其中.h头文件和.a静态库分开存放:

[wj@VM-4-3-centos mklib]$ make staticlib
mkdir -p staticlib/include
mkdir -p staticlib/lib 
cp -rf *.h staticlib/include
cp -rf *.a staticlib/lib 

[wj@VM-4-3-centos mklib]$ ll
total 36
-rw-rw-r-- 1 wj wj  165 Aug  4 21:44 accum.c
-rw-rw-r-- 1 wj wj   75 Aug  4 21:44 accum.h
-rw-rw-r-- 1 wj wj 1280 Aug  5 10:32 accum.o
-rw-rw-r-- 1 wj wj 3074 Aug  5 10:32 libstatic.a
-rw-rw-r-- 1 wj wj  373 Aug  5 10:42 makefile
-rw-rw-r-- 1 wj wj   96 Aug  4 21:07 print.c
-rw-rw-r-- 1 wj wj   88 Aug  4 21:07 print.h
-rw-rw-r-- 1 wj wj 1576 Aug  5 10:32 print.o
drwxrwxr-x 4 wj wj 4096 Aug  5 10:43 staticlib //静态库目录文件

[wj@VM-4-3-centos mklib]$ tree staticlib/
staticlib/
|-- include
|   |-- accum.h
|   `-- print.h
`-- lib
    `-- libstatic.a

2 directories, 3 files
[wj@VM-4-3-centos mklib]$ 

  发布后,如何使用静态库见3.2.1部分。
  
  
  
  

3.1.3、动态库制作

  1)、准备工作
  此处使用静态库中的演示例子:accum.caccum.hprint.cprint.h,具体内部代码见上述。

[wj@VM-4-3-centos mklib]$ ll
total 24
-rw-rw-r-- 1 wj wj  165 Aug  4 21:44 accum.c
-rw-rw-r-- 1 wj wj   75 Aug  4 21:44 accum.h
-rw-rw-r-- 1 wj wj  373 Aug  5 10:42 makefile
-rw-rw-r-- 1 wj wj   96 Aug  4 21:07 print.c
-rw-rw-r-- 1 wj wj   88 Aug  4 21:07 print.h
drwxrwxr-x 4 wj wj 4096 Aug  5 10:43 staticlib

  
  
  2)、制作一个库
  相关指令:
  ①gcc -fPIC -c XXX.c -o XXX.o :fPIC形成一个与位置无关的二进制目标文件。
  ②gcc -shared XXX.o XXX.o -o libXXX.so :-shared用于表示所形成的是动态库而非可执行程序。
  
  
  演示如下:

[wj@VM-4-3-centos mklib]$ ll
total 24
-rw-rw-r-- 1 wj wj  165 Aug  4 21:44 accum.c
-rw-rw-r-- 1 wj wj   75 Aug  4 21:44 accum.h
-rw-rw-r-- 1 wj wj  373 Aug  5 10:42 makefile
-rw-rw-r-- 1 wj wj   96 Aug  4 21:07 print.c
-rw-rw-r-- 1 wj wj   88 Aug  4 21:07 print.h
drwxrwxr-x 4 wj wj 4096 Aug  5 10:43 staticlib

[wj@VM-4-3-centos mklib]$ gcc -fPIC -c print.c -o print_d.o #step1:生成一个与位置无关的二进制目标文件
[wj@VM-4-3-centos mklib]$ gcc -fPIC -c accum.c -o accum_d.o
[wj@VM-4-3-centos mklib]$ ls
accum.c  accum_d.o  accum.h  makefile  print.c  print_d.o  print.h  staticlib

[wj@VM-4-3-centos mklib]$ gcc -shared accum_d.o  print_d.o -o libdynamic.so #step2:生成一个动态库
[wj@VM-4-3-centos mklib]$ ll
total 40
-rw-rw-r-- 1 wj wj  165 Aug  4 21:44 accum.c
-rw-rw-r-- 1 wj wj 1280 Aug  5 14:36 accum_d.o
-rw-rw-r-- 1 wj wj   75 Aug  4 21:44 accum.h
-rwxrwxr-x 1 wj wj 8152 Aug  5 14:36 libdynamic.so #动态库
-rw-rw-r-- 1 wj wj  373 Aug  5 10:42 makefile
-rw-rw-r-- 1 wj wj   96 Aug  4 21:07 print.c
-rw-rw-r-- 1 wj wj 1624 Aug  5 14:35 print_d.o
-rw-rw-r-- 1 wj wj   88 Aug  4 21:07 print.h
drwxrwxr-x 4 wj wj 4096 Aug  5 10:43 staticlib
[wj@VM-4-3-centos mklib]$ 

  
  
  使用makefile生成:

dynamiclib.so:print_d.o accum_d.o
	gcc -shared print_d.o accum_d.o -o libdynamic.so

print_d.o:print.c
	gcc -fPIC -c print.c -o print_d.o
accum_d.o:accum.c
	gcc -fPIC -c accum.c -o accum_d.o

  
  
  3)、发布库
  这里我们直接生成动静态库两个版本:makefile中相关写法如下

.PHONY:all
all::libdynamic.so libstatic.a

##动态库##
libdynamic.so:print_d.o accum_d.o
	gcc -shared print_d.o accum_d.o -o libdynamic.so

print_d.o:print.c
	gcc -fPIC -c print.c -o print_d.o
accum_d.o:accum.c
	gcc -fPIC -c accum.c -o accum_d.o
####


##静态库##
libstatic.a:print.o accum.o
	ar -rc libstatic.a accum.o print.o

print.o:print.c
	gcc -c print.c -o print.o
accum.o:accum.c
	gcc -c accum.c -o accum.o
####


.PHONY:output
output:
	mkdir -p output/lib 
	mkdir -p output/include
	cp -rf *.h output/include
	cp -rf *.a *.so output/lib 

.PHONY:clean
clean:
	rm -rf *.o *.a *.so output

  
  演示结果:
在这里插入图片描述

  
  
  
  

3.2、站在使用库的人的角度:如何用别人提供的库?

3.2.1、使用静态库

  我们获取到别人归档后的库,并不能直接使用,还需要做一定操作,以下为几种使用静态库的方法介绍。
  
  
  1)、做法一:将我们所下载的库拷贝到系统库(系统默认路径)中
  前提认知:
  头文件gcc默认搜索路径:/usr/include
  库文件云服务器默认搜索路径:/lib64 或者 /usr/lib64
在这里插入图片描述
  
  相关指令:

  拷贝lib:sudo cp XXX/XXX/*.a /lib64 -rf

sudo cp ./staticlib/lib/*.a  /lib64 -rf

  拷贝头文件:sudo cp XXX/XXX/*.h /usr/include -rf

 sudo cp ./staticlib/include/*.h /usr/include -rf 

  第三方库编译方法:gcc XXX.c -lXXX,要加-l,后面跟的是库名称。libXXX.a中,去掉前缀和后缀,XXX为库的名称。

gcc main.c -lstatic -o main.out

  
  以下为演示过程及结果:将库拷贝到系统默认路径下,就叫做库的安装。

在这里插入图片描述
  
  
  
  问题说明:
  上述使用静态库的方法容易污染系统库,一般不建议这样使用。

[wj@VM-4-3-centos uselib]$ sudo rm /usr/include/accum.h
[sudo] password for wj: 
[wj@VM-4-3-centos uselib]$ sudo rm /usr/include/print.h
[wj@VM-4-3-centos uselib]$ sudo rm /lib64/libstatic.a

  
  
  
  
  2)、做法二:硬使用

  相关指令: gcc XXX.c -I ./XXX/include/ -L ./XXX/lib/ -lXXX

gcc main.c -I ./staticlib/include/ -L ./staticlib/lib/ -lstatic -o main.out

  -I:指定库的头文件搜索路径
  -L:指定搜索lib路径
  -lXXX:指定库名称
  
  相关演示如下:
在这里插入图片描述
  
  
  
  说明:
  上述方式中,a、若只有静态库,则只能静态链接。 b、动静态库同时存在时:默认使用动态库。

在这里插入图片描述

  
  
  c、动静态库同时存在,但非要使用静态库,如何操作?
  -static :强制静态链接。
  该选项的意义:摒弃默认优先使用动态库的原则,直接使用静态库。

在这里插入图片描述

  
  
  
  
  
  

3.2.2、使用动态库

  1)、整体说明
  1、同上述静态库中方法一,可以在系统默认路径对动态库进行安装、卸载操作,但同样不建议这样使用。
  
  2、针对方法二中动态库无法运行的问题说明:

[wj@VM-4-3-centos uselib]$ gcc main.c -I ./output/include -L ./output/lib2 -loutput #使用相关指令
[wj@VM-4-3-centos uselib]$ ls
a.out  main.c  makefile  output  staticlib

[wj@VM-4-3-centos uselib]$ file a.out
a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=41a35062c3b3113f93efd9ef58eeaf1f795adfb5, not stripped

[wj@VM-4-3-centos uselib]$ ./a.out #运行,发现运行失败
./a.out: error while loading shared libraries: liboutput.so: cannot open shared object file: No such file or directory
[wj@VM-4-3-centos uselib]$ 

  静态库将相应代码嵌入程序中,程序执行时就在自己所处的代码区域;动态库相应代码加载在共享区,程序执行时在共享区和代码区反复跳转。动态库只用加载一次,就能被多个进程同时使用,即共享库。
在这里插入图片描述

  我们使用gcc main.c -I ./output/include -L ./output/lib2 -loutput指令时,只是针对gcc说明需要动态库,但动态库运行加载是操作系统加载器来完成的,故需要给OS说明。
  
  
  
  1)、解决方案

在这里插入图片描述解决方案一:系统的环境变量

  LD_LIBRARY_PATH设置此环境变量:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/XXXXX/XXXXX

[wj@VM-4-3-centos uselib]$ echo $LD_LIBRARY_PATH
:/home/wj/.VimForCpp/vim/bundle/YCM.so/el7.x86_64

在这里插入图片描述
  
  1、上述方式关闭shell后,设置好的内存级的环境变量被清空,下次进入将重新设置。
  2、这里export导环境变量也可以使用相对路径:

[wj@VM-4-3-centos uselib]$ export LD_LIBRARY_PATH=LD_LIBRARY_PATH:./output/lib/
[wj@VM-4-3-centos uselib]$ echo $LD_LIBRARY_PATH
LD_LIBRARY_PATH:./output/lib/
[wj@VM-4-3-centos uselib]$ ldd main.out
	linux-vdso.so.1 =>  (0x00007fff066be000)
	/$LIB/libonion.so => /lib64/libonion.so (0x00007f9da91f4000)
	libdynamic.so => ./output/lib/libdynamic.so (0x00007f9da8ed9000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f9da8b0b000)
	libdl.so.2 => /lib64/libdl.so.2 (0x00007f9da8907000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f9da90db000)
[wj@VM-4-3-centos uselib]$ ./main.out
hello main:[1691230176]
result:1275
[wj@VM-4-3-centos uselib]$ 

  
  
  
  

在这里插入图片描述解决方案二:修改配置文件

  ls /etc/ld.so.conf.d/,相对方案一,该方案属于长久保存的一个方法。
  
  操作:在该目录下创建一个XXX.conf文件,在该文件内填入对应的动态库搜索路径
  ①sudo touch /etc/ld.so.conf.d/XXX.conf:创建文件
  ②sudo vim /etc/ld.so.conf.d/XXX.conf :填入路径
  ③sudo ldconfig:让配置文件更新生效
  
  具体演示:
在这里插入图片描述
  
在这里插入图片描述

  
  
  

在这里插入图片描述解决方案三:建立软链接

  sudo ln -s XXX/XXX /lib64/libXXX.so,注意使用绝对路径。
  
  
  相关演示:
在这里插入图片描述

  
  除了上述方法,还有其它方式可以支持。
  
  
  
  
  
  
  
  
  

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

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

相关文章

初识MySQL数据库之用户管理

目录 一、用户管理 二、用户 1. 用户信息 2. 创建用户 3. 用户登录测试 4. 删除用户 5. 设置用户远端登录 6. 修改密码 6.1 修改当前用户的密码 6.2 root用户修改指定用户的密码 三、权限 1. 数据库中的各个权限含义 2. 给用户授权 3. 查看用户拥有权限 4. 授权…

VSCode---通过ctrl+鼠标滚动改变字体大小

打开设置然后在右边输editor.mouseWheelZoo勾选即可实现鼠标滚动改变字体大小 4.这种设置的字体大小是固定的

Wordpress升级版本后插件和主题常见出错及处理方法整理【持续更新】

Wordpress报错怎么解决&#xff1f; 一般常用的排查方法&#xff1a; 暂时禁用所有插件&#xff1b;将主题更改为默认主题&#xff1b; 修改wp-config.php文件&#xff1b;更新固定链接设置&#xff0c;确保设置正确&#xff1b;检查.htaccess文件是否存在且是否可写&#xf…

IL汇编实现两数相加输出结果

话说前面没有实现IL汇编2数相加&#xff1b;鼓捣了一下&#xff0c;实现的代码如下&#xff1b; .assembly extern mscorlib {}.assembly Test{.ver 1:0:1:0}.module test.exe.method static void main() cil managed{.maxstack 8.entrypoint.locals init (int32 V_0, int3…

数据集成、类的派生树、算子、软件核化。

数据集成、类的派生树、算子、软件核化TOC 数据集成&#xff1a;数据集成首先需要对数据进行分类、组织、排序&#xff0c;然后按照一定的规则合成、展示数据&#xff08;可以是生成式网页数据&#xff09;。对于元宇宙、大数据、大模型、基于搜索的计算、数据集成都是提高效率…

SpringBoot中Redis报错:NOAUTH Authentication required

1、问题 org.springframework.dao.InvalidDataAccessApiUsageException: NOAUTH Authentication required.; nested exception is redis.clients.jedis.exceptions.JedisDataException: NOAUTH Authentication required. … 2、解决 如果提供了密码还没解决&#xff0c;那可能是…

2021-06-16 Multisim74LS161S设计13进制计数器!

缘由求&#xff01;74LS161S设计13进制计数器&#xff01;-其他-CSDN问答

从URL取值传给后端

从URL传值给后端 http://127.0.0.1:8080/blog_content.html?id8点击浏览文章详情&#xff0c;跳转至详情页面 从 url 中拿出文章 id&#xff0c;传给后端 首先拿到url然后判断是否有值&#xff0c;从问号后面取值params.split(&) 以 & 作为分割然后遍历字符数组 param…

SQL分类及通用语法数据类型(超详细版)

一、SQL分类 DDL: 数据定义语言&#xff0c;用来定义数据库对象&#xff08;数据库、表、字段&#xff09;DML: 数据操作语言&#xff0c;用来对数据库表中的数据进行增删改DQL: 数据查询语言&#xff0c;用来查询数据库中表的记录DCL: 数据控制语言&#xff0c;用来创建数据库…

在消费级GPU调试LLM的三种方法:梯度检查点,LoRA和量化

LLM的问题就是权重参数太大&#xff0c;无法在我们本地消费级GPU上进行调试&#xff0c;所以我们将介绍3种在训练过程中减少内存消耗&#xff0c;节省大量时间的方法:梯度检查点&#xff0c;LoRA和量化。 梯度检查点 梯度检查点是一种在神经网络训练过程中使动态计算只存储最…

瞄准产业应用,大模型加持的深兰科技AI虚拟数字人落地业务场景

伴随ChatGPT的问世&#xff0c;在技术与商业运作上都日渐发展成熟的AI数字人产业正持续升温。 目前的AI数字人不仅拥有超高“颜值”&#xff0c;同时还拥有更为丰富的、细腻的表情和动作。更有甚者&#xff0c;AI数字人已经具备自定义构建知识图谱、自主对话、不断学习成长的能…

day3-牛客67道剑指offer-JZ31、JZ32、JZ33、JZ34、JZ35、JZ36、JZ38、JZ39、JZ40、JZ42、链表中倒数第k个

文章目录 1. JZ31 栈的压入、弹出序列辅助栈原地栈 数组模拟 2. JZ32 从上往下打印二叉树迭代递归 3. JZ33 二叉搜索树的后序遍历序列递归迭代 递增栈 4. JZ34 二叉树中和为某一值的路径(二)5. JZ35 复杂链表的复制6. JZ36 二叉搜索树与双向链表递归迭代 7. JZ38 字符串的排列n…

SpringBoot复习:(18)@Value和@Autowired注解配置的属性是怎么注入到bean中的?

Value java doc文档指出&#xff0c;它是由AutowiredAnnotationBeanPostProcessor这个BeanPostProcessor处理的。 AutowiredAnnotationBeanPostProcessor的构造方法如下&#xff1a; 可见AutowiredAnnotationBeanPostProcessor用来处理Autowired和Value这两个注解。 具体的处理…

mongodb-win32-x86_64-2008plus-ssl-3.6.23-signed.msi

Microsoft Windows [版本 6.1.7601] 版权所有 (c) 2009 Microsoft Corporation。保留所有权利。C:\Users\Administrator>cd C:\MongoDB\Server\3.6\binC:\MongoDB\Server\3.6\bin> C:\MongoDB\Server\3.6\bin> C:\MongoDB\Server\3.6\bin>mongod --dbpath C:\Mongo…

STM32基础入门学习笔记:开发板 电路原理与驱动编程

文章目录&#xff1a; 一&#xff1a;触摸按键 1.触摸按键驱动程序&#xff08;点击&#xff09; touch_key.h touch_key.c main.c 2.按键双击和长按程序 touch_key.h touch_key.c main.c 3.触摸按键滑动程序 main.c 二&#xff1a;数码管显示 1.数码管RTC时钟LE…

丁香园:2023药品带量采购政策及趋势分析报告(附下载)

关于报告的所有内容&#xff0c;公众【营销人星球】获取下载查看 核心观点 化药&#xff1a;经多次集采&#xff0c;其规则与模式已比较成熟&#xff0c;是药品集采主要品种 中成药&#xff1a;由湖北牵头开展2 个批次&#xff0c;覆盖全国 31 省共 33产品组&#xff0c;此外…

谈谈对Android音视频开发的探究

在日常生活中&#xff0c;视频类应用占据了我们越来越多的时间&#xff0c;各大公司也纷纷杀入这个战场&#xff0c;不管是抖音、快手等短视频类型&#xff0c;虎牙、斗鱼等直播类型&#xff0c;腾讯视频、爱奇艺、优酷等长视频类型&#xff0c;还是Vue、美拍等视频编辑美颜类型…

【RL】Wasserstein距离-GAN背后的直觉

一、说明 在本文中&#xff0c;我们将阅读有关Wasserstein GANs的信息。具体来说&#xff0c;我们将关注以下内容&#xff1a;i&#xff09;什么是瓦瑟斯坦距离&#xff1f;&#xff0c;ii&#xff09;为什么要使用它&#xff1f;iii&#xff09; 我们如何使用它来训练 GAN&…

软件工程专业应该学什么?

昨天&#xff0c;我朋友的孩子报考了软件工程专业&#xff0c;问我软件工程到底学啥&#xff1f;所以我给他开列了一个书单。 现在高校开了一堆花名头的专业&#xff1a; 偏技术类&#xff1a;云计算、大数据、人工智能、物联网 偏应用类&#xff1a;电子商务、信息管理 但我个…

flink1.17 eventWindow不要配置processTrigger

理论上可以eventtime processtime混用,但是下面代码测试发现bug,输入一条数据会一直输出. flink github无法提bug/问题. apache jira账户新建后竟然flink又需要一个账户,放弃 bug复现操作 idea运行代码后 往source kafka发送一条数据 a,1,1690304400000 可以看到无限输出…