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

【Linux】软硬连接 | 静动态库

🪐🪐🪐欢迎来到程序员餐厅💫💫💫

          主厨:邪王真眼

主厨的主页:Chef‘s blog  

所属专栏:青果大战linux

总有光环在陨落,总有新星在闪烁


你说得对,但是这就是期末临近,一遍学操作系统,一边琢磨怎么复习自己的专业课,还有六级!!!!!  

软链接

 使用下面的指令即可生成软链接文件

基本语法:ln -s [目标文件或目录路径] [软链接文件名]

概念 

可以看到我们生成了一个软链接文件,文件后缀可以随便写,因为linux解析大多数文件中不会考虑文件后缀,但是为了方便我们自己认识还是规范写比较好。

上图红框的第一个字母是l,表示这是一个软链接文件

软链接生成的是一个独立文件,因为他有自己独立的inode

软链接的文件内容是所指向的目标文件的路径,可以理解为windows中的快捷方式,你可以通过该软链接文件打开目标文件。

如上图,我们在一个文件中输入字符串,之后可以通过该文件的软链接文件访问它。 

请注意输入目标文件的路径时建议用用绝对路径,因为软链不会解析那个相对路径,举个例子,

[qingguo@host project23_link]$ sudo ln -s ./t1 /usr/bin/t3

 我通过相对路径在usr/bin目录下建立t1的软链接,那么软链接链接的路径就不是此时的./即/home/qingguo/project23_link/,而是链接过去之后的./即usr/bin。

可以看到链接后的文件表示找不到目标文件

 让后我把目标文件移动到了 软链接文件的目录即./usr/bin下,此时就表示可以使用了。


用途

  •  1.对文件

就像我们在window中使用快捷键一样,要使用一个文件但是他藏在很深的目录里,找起来太麻烦了,于是你可以写个软链接把该软连接文件统一放到一个地方,使用就方便了(比如桌面)。

  •  2.对目录 

同样的加入有个目录下的东西你经常需要看,但是目录很长,输入起来很麻烦,你可以可以对该目录进行软链接,这样就不用输入那一长串目录,只用输入软链接的文件名了.

[qingguo@host ~]$ ln -s /usr/bin ub
[qingguo@host ~]$ sudo ll ub

  • 3.伪装指令

通过这种方式你也可以把自己的可执行程序放到usr/bin目录下,就可以当指令用了

删除软链接文件 

 要删除软链接文件可以直接rm,也可以使用unlink+软链接文件(带路径)


硬链接

基本语法:ln  [目标文件或目录路径] [硬链接文件名]

概念

可以看出生成方式上,软硬链接只差了一个-s

可以看出生成的硬链接文件的inode和原文件一样 ,并且硬链接后红框圈住的数字加了1

我们不认为硬链接文件是个独立的文件,毕竟他没有独立的inode,他本质就是所处目录下新增的一组已存在的文件名与inode的映射关系。

而那个红框圈的数字就是硬链接数,表示有多少文件名指向该文件的inode,所以要删除一个文件不是删一个文件就够了,而是要把和该文件有映射的所有文件都删掉,这里采用的就是引用计数

 我们删掉了原文件,此时软链接失效,但是我们依据可以依靠硬链接访问该文件的内容,这就是引用计数删除的体现。

可以发现,一个独立的文件没有对他使用硬链接时硬链接数为1,但是文件夹的硬连接数却是2

因为目录有一个隐藏文件".",该文件也是指向该文件夹的,所以硬链接数为2

接着我在该dir1里有新建了一个文价夹,dir1的硬连接数加1了。

 

因为新建的文件夹里有隐藏文件"..",它指向上级目录即dir1,

这些"."和".."采用的就是硬链接。

 这里我们就可以解释为什么根目录再去cd  ..   就不能继续前进了,因为他的".." 指向的文件就是自己本身,和"."是一样的。看下图根目录下的“.”和“..”的inode都是2。

用途

  • 1.备份文件

显然我们直前学的备份就是cp指令,这个指令的备份是新建了一个文件,这显然增加了空间开销,现在我们就可以使用硬链接进行备份,空间开销约等于0,优雅、真是太优雅了。

链接目录 

硬链接不可以链接目录,原因是硬链接目录会形成环状路径,

这样的路径,请问A-hard.link的上级目录算是C还是根目录,他的下一级目录是B还是E和F,这就没法解析目录了啊,所以OS禁止用户硬链接目录,这时候就有人问了:

我们不是刚讲了“.”和“..”这两个隐藏文件就是硬链接,而且是对目录的硬链接,这不矛盾了吗

没错,OS就是这样,在这个硬链接文件目录上,只许州官放火不许百姓点灯,因为他自己其实还加了一些特殊处理,我们知道这个事就行。


软链接则不然,我们可以tree一下

显然,OS对软链接的文件不会直接展开他链接的文件,而是就先把他当作一个普通文件看待 ,这样就可以链接目录啦。


静态库

ldd指令可以查看一个文件链接的库

  

准备工作

首先我们先完成源码,自己写俩头文件以及函数实现,等下把他们封装成库来使用

  • mystdio.c 
#include"mystdio.h"
#include<unistd.h>
#include<stdio.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<stdlib.h>
#include<string.h>
mFILE* mfopen(const char*filename,const char*mode){
  int fd=-1;
    if(*mode=='r'){
   fd= open(filename,O_RDONLY);
}
   else if(*mode=='w'){
   fd= open(filename,O_WRONLY|O_CREAT|O_TRUNC,0666);
}
else if(*mode=='a'){
    fd=open(filename,O_WRONLY|O_CREAT|O_APPEND,0666);
}
mFILE*f=(mFILE*)malloc(sizeof (mFILE));
if(!f){
    close(fd);
    return NULL;
}
f->fd=fd;
f->flag=FLUSH_FULL;
f->cap=1024;
f->size=0;
return f;
}
int  mfwrite(char*str,int num,mFILE*stream){
   memcpy(stream->buffer+stream->size,str,num);
  stream->size+=num;
 int flag=1;
  if(stream->flag==FLUSH_LINE){
    if(stream->size>0&&stream->buffer[stream->size-1]=='\n'){
   flag=write(stream->fd,stream->buffer,stream->size);
      stream->size=0;
      } 
  }
  else if(stream->flag==FLUSH_FULL){
      if(stream->size>stream->cap*9/10){
   flag=write(stream->fd,stream->buffer,stream->size);
   printf("%d",stream->size); 
   stream->size=0;
      }
  }
  return flag;
}
void mfflush(mFILE*stream){
    write(stream->fd,stream->buffer,SIZE);
}
int mfclose(mFILE*stream){
 mfflush(stream);
    return  close(stream->fd);
}
  • mystdio.h
#pragma once
#define SIZE 1024
#define FLUSH_NODE 0
#define FLUSH_LINE 1
#define FLUSH_FULL 2
struct mFILE{
    int fd;
    int flag;//文件刷新方式
    char buffer[SIZE];
    int cap;
int size;
};
typedef struct mFILE mFILE;
mFILE* mfopen(const char*filename,const char*mode);
int  mfwrite(char*str,int num,mFILE*stream);
void mfflush(mFILE*stream);
int mfclose(mFILE*stream);
  •  mystring.h
#include"mystring.h"
int mstrlen(const char*arr){
    int i=0;
    while(arr[i])
        i++;
    return i;
}
  • mystring.c
#pragma once
int mstrlen(const char*arr);
  • main.c 
#include<mystdio.h>
#include<stdio.h>
#include<mystring.h>
int main(){
    printf("%d",mstrlen("aaa"));
   mFILE*p=mfopen("t1.txt","w");
   mfclose(p);
}


 介绍

 【基本语法】

ar -rc libname.a [要打包的.o文件]
  1. ar事archive的缩写,意思是把。。归档
  2. -r表示repalce,即若库中已有同名文件则进行替代
  3. -c表示creat,若库中没有该文件则创建

什么是静态库

 静态库(Static Library),在计算机编程领域,是一种将多个目标文件(通常是编译后的代码)打包在一起的文件格式。它的扩展名在不同的操作系统和编译器下可能有所不同,例如在 Unix/Linux 系统中常为.a(archive 的缩写),在 Windows 系统中常为.lib。静态库就像是一个代码仓库,里面包含了一系列可以被其他程序调用的函数和变量的编译后版本

在理解这些后,我们可以写一个makefile,它可以创建一个库,把库和头文件放到目标路径,以及清理所有数据  

%.o:%.c
	gcc -c $<//.o文件的实现方法写哪里都可以,如果在执行某条命令时发现依赖文件没有生成,系统会自动检查makefile中的所有指令看有没有用于生成该依赖文件的
libmystdio.a:mystdio.o mystring.o
	ar -rc $@ $^
.PHONY:clean
clean:
	rm -rf *.a *.o stdc
.PHONY:output
output:
	mkdir -p stdc/include//注意要先写mkdir,再写cp指令,这里是按照顺序执行的
	mkdir -p stdc/lib
	cp -rf *.c stdc/include
	cp -rf *.a stdc/lib
	tar -czf stdc.tgz stdc//顺带打个包压缩一下,可以直接发给需要的同学(太优雅了)

使用方法

  • 1.头文件和库都在标准路径下

把头文件放到usr/bin目录下,库文件放到/lib64

直接gcc编译链接

gcc -o main main.c

好了,不出意外就会报错,我来给你分析一下

对于头文件如果是以<>的方式包含,那么系统会自动去标准路径及usr/bin目录下挨个找该头文件是否存在,

对于库,OS会在默认标准路径即/lib64下查找,但是你要告诉他要找的库名字! 

-l +库名字表示去找该库

注意库的名字是去掉.a或.so的后缀,去掉lib前缀

gcc -o main main.c -l mystdio

也可以这么写 

gcc -o main main.c -lmystdio

这时候就有人问了,为什么我们平常用gcc编译链接标准库就不用-l+库名字

老弟,你猜猜他为什么叫gcc?

在编译 C 程序时,GCC(GNU Compiler Collection)对于 C 标准库有隐式链接的机制。C 标准库是非常基础且常用的库,几乎每个 C 程序都会用到其中的一些函数,如stdio.h中的printfscanf等。为了方便开发者,GCC 编译器默认会自动链接 C 标准库

g++也是同理 


  • 2.库不放到标准路径下

-L +路径表示除了系统路径,也要去这个路径下找库

gcc -o main main.c -lmystdio -L ./my
  • 库和头文件.h都不在标准路径下

-I +路径表示除了系统路径,也要去这个路径下找头文件

gcc -o main main.c -lmystdio -L ./my -I ./include


动态库

生成动态库

gcc -o 动态库名称 [依赖的.o文件] -shared

生成需要的.o文件

gcc -fPIC  -o .o文件名称 -c 源文件名称

显然我们这次多了一个-fPIC(Position - Independent Code)选项,翻译一下就是位置无关代码,他的作用是使得生成的.o文件代码是位置无关的,这是因为动态库在内存中的加载位置是不确定的,需要代码能够在任何位置正确执行。关于这个问题我们下节课会细讲。

 libmystdio.so:mystdio.o mystring.o                                                                                                                                                                                              
       gcc -o $@ $^ -shared
   %.o:%.c
       gcc -fPIC -o $@ -c $<
   .PHONY:clean
   clean:
       rm -rf *.o *.so

有了动态库我们就可以gcc编译链接了,方法和静态库是一样的,还是

  • 1.头文件和库都在标准路径下

  • 2.库不放到标准路径下

  • 3.库和头文件.h都不在标准路径下

在生成了可执行文件后直接./main执行会报错,ldd查看 会发现我们main找不到库的路径    

  

但是我们gcc的时候不是给他指定路径了吗。

因为gcc是用来生成可执行文件的,我们给的路径也是生成可执行文件的时候才会被看到,现在已经到了执行可执行文件的时候了,操作系统会默认到lib/64链接需要的库,显然我们的库不在这里,那么我们就要再告诉OS这个库的路径了。  

  • 解决方法1.

把我们的动态库拷贝到lib64目录,可以cp,也可以软链接(记得用绝对路径)  

  • 解决方法2.

修改环境变量

系统会到LD_LIBRARY_PATH这个环境变量存储的路径下找库,我们把我们自己的库的路径加进来就好了

LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/qingguo/project23_link/other/stdc/lib/

环境变量在退出shell后就重置了,为了保存效果我们可以去该用户的根目录下,先cd ~到用户的根目录,再找到.bashrc,

 

修改里面的LD_LIBRARY_PATH即可

此时就可以找到库的路径了 

就可以运行了。 


  •   解决方法3

修改配置文件

在/etc路径下,有一个ld.so.conf.d的文件夹

我们在这里touch一个后缀为.conf的文件,在里面写入我们的库的路径(不带最后的库名称)即可

要用root,貌似sudo提权 也不好使,建议直接su

通过以上方法,我们就成功让库=文件找到了对应的库的路径 

链接规则 

现在我们的可执行文件包含四个库,三个是标准库ABC,一个是我们自己实现的库D,并且ABC库既有动态库也有静态库。

  1. 当D库动静态库都有的时候,默认gcc链接优先使用动态库链接ABCD
  2. 当D有静态库并且想使用静态库就加-static选项,此时链接ABCD都会用静态库

  3. D只有动态库但是加了-static选项则会报错

  4. D只有静态库即使没有指定-static,此时ABC会链接动态库,但是D会使用静态库 


http://www.kler.cn/a/430495.html

相关文章:

  • C++的第一个程序
  • Linux快速入门-一道简单shell编程题目
  • 解决pycharm无法识别miniconda
  • Edge如何获得纯净的启动界面
  • SVM分类-支持向量机(Support Vector Machine)
  • 基于Svelte 5的体检查询系统前端设计与实现探究
  • onnx文件转pytorch pt模型文件
  • 【Spark】Spark Join类型及Join实现方式
  • 使用 electron 把 vue 项目打包成客户端
  • liunx docker 部署 nacos seata sentinel
  • TCP/IP协议配置与网络实用命令
  • uniapp 弹出软键盘后打开二级页面,解决其UI布局变动
  • 同城到家预约上门服务解决方案:家政预约同城服务小程序
  • React Native 速度提升 550%
  • 流网络等价性证明:边分解后的最大流保持不变
  • vue3 setup有什么用?
  • 【优选算法篇】剥洋葱式探索:用二分查找精准定位答案(下篇)
  • 一些硬件知识【2024/12/6】
  • 【PX4飞控】二次开发1—加速度转期望姿态算法修改
  • 前端实现复制功能,Uncaught TypeError: Cannot read property ‘writeText‘ of undefined
  • CUDA编程 | 5.5 常量内存
  • Web游戏开发指南:在 Phaser.js 中读取和管理游戏手柄输入
  • 图的割点、割边(Tarjan算法)
  • 第4章:颜色和背景 --[CSS零基础入门]
  • 20241209给Ubuntu20.04系统的的交换分区增加为20GB的步骤
  • wsl2子系统ubuntu发行版位置迁移步骤