软链接 | 硬链接 | 动态库 | 静态库 | 制作和使用

1.软链接和硬链接

Linux 中可以通过硬链接(Hard Link) 和软链接(Symbolic Link) 给文件起别名,而硬链接和软链接的本质区别是没有独立的inode。

硬链接指向的是同一个inode,但是 inode 是不可能跨越文件系统的,每个文件系统都有各自的 inode 数据结构和列表,所以硬链接是不可用于跨文件系统的

软链接相当于重新创建一个文件,这个文件有独立的 inode,但是这个文件的内容是另外一个文件的路径,所以访问软链接的时候,实际上相当于访问到了另外一个文件,所以软链接是可以跨文件系统的

在一个空目录ln中创建一个test.txt文件和一个目录dir1:

xiyan@VM-20-5-ubuntu:~/ln$ touch test.txt
xiyan@VM-20-5-ubuntu:~/ln$ mkdir dir1
xiyan@VM-20-5-ubuntu:~/ln$ ll -i
656053 drwxrwxr-x 2 xiyan xiyan 4096 Mar 21 14:22 dir1/
656052 -rw-rw-r-- 1 xiyan xiyan    0 Mar 21 14:22 test.txt

文件的引用计数是1,而目录的引用计数是2。为什么呢? 文件就是代表一个文件名就对应一个inode而目录中的 .和目录名都指向同一个inode(656053)。

xiyan@VM-20-5-ubuntu:~/ln$ cd dir1/
xiyan@VM-20-5-ubuntu:~/ln/dir1$ ll -i
total 8
656053 drwxrwxr-x 2 xiyan xiyan 4096 Mar 21 14:22 ./
656051 drwxrwxr-x 3 xiyan xiyan 4096 Mar 21 14:22 ../

在dir1中在创建一个d1目录,dir1对应的引用计数变为3

xiyan@VM-20-5-ubuntu:~/ln/dir1$ mkdir d1
xiyan@VM-20-5-ubuntu:~/ln/dir1$ cd ..
xiyan@VM-20-5-ubuntu:~/ln$ ll -i
656053 drwxrwxr-x 3 xiyan xiyan 4096 Mar 21 14:29 dir1/
656052 -rw-rw-r-- 1 xiyan xiyan    0 Mar 21 14:22 test.txt

进入d1目录下发现..也指向dir1,代表了上一级目录,在dir1中,有一个.会有一个引用计数,创建一个目录中..也代表上一级目录,而dir1的引用计数为3可以知道有1个目录。 这里也说明了...都是一个文件名。

xiyan@VM-20-5-ubuntu:~/ln$ cd dir1/d1/
xiyan@VM-20-5-ubuntu:~/ln/dir1/d1$ ll -i
656054 drwxrwxr-x 2 xiyan xiyan 4096 Mar 21 14:29 ./
656053 drwxrwxr-x 3 xiyan xiyan 4096 Mar 21 14:29 ../

软硬链接的创建

指令格式:

xiyan@VM-20-5-ubuntu:~$ ln [选项] 源文件 目标文件
-s:建立软链接文件。如果不加 "-s" 选项,则建立硬链接文件

注意:观察创建软硬链接的inode和引用计数

xiyan@VM-20-5-ubuntu:~/ln$ pwd
/home/xiyan/ln
xiyan@VM-20-5-ubuntu:~/ln$ tree
.
├── dir1
│   └── d1
│       └── a.out
└── test.txt
xiyan@VM-20-5-ubuntu:~/ln$ ./dir1/d1/a.out 
hello world!
xiyan@VM-20-5-ubuntu:~/ln$ ln -s ./dir1/d1/a.out hello
xiyan@VM-20-5-ubuntu:~/ln$ ll -i
656053 drwxrwxr-x 3 xiyan xiyan 4096 Mar 21 14:29 dir1/
656056 lrwxrwxrwx 1 xiyan xiyan   15 Mar 21 14:50 hello -> ./dir1/d1/a.out*
656052 -rw-rw-r-- 1 xiyan xiyan    0 Mar 21 14:22 test.txt
xiyan@VM-20-5-ubuntu:~/ln$ ./hello 
hello world!
xiyan@VM-20-5-ubuntu:~/ln$ ln ./dir1/d1/a.out Hello1
xiyan@VM-20-5-ubuntu:~/ln$ ln ./dir1/d1/a.out Hello2
xiyan@VM-20-5-ubuntu:~/ln$ ll -i
656053 drwxrwxr-x 3 xiyan xiyan  4096 Mar 21 14:29 dir1/
656056 lrwxrwxrwx 1 xiyan xiyan    15 Mar 21 14:50 hello -> ./dir1/d1/a.out*
656055 -rwxrwxr-x 3 xiyan xiyan 15952 Mar 21 14:46 Hello1*
656055 -rwxrwxr-x 3 xiyan xiyan 15952 Mar 21 14:46 Hello2*
656052 -rw-rw-r-- 1 xiyan xiyan     0 Mar 21 14:22 test.txt

软硬接有独立的inode创建了新文件,而硬链接没有创建真正的文件;软链接相对于Windows的快捷方式,而硬链接就是建立了文件名和指定inode的映射关系。

rm unlink都是删除文件,当引用计数变为0,没有文件名和inode关联,系统认为用户不管了这个文件了会删除。unlink有对应的系统调用接口。

2.动态库和静态库
2.1.C/C++编译过程

C/C++程序编译过程分为四个阶段:预处理、编译、汇编、链接。

预处理(进行宏替换)

gcc语法格式:gcc [选项] 要编译的文件 [选项] [目标文件]

处理以 # 开头的指令,产生 .i 文件。处理宏定义、头文件展开、处理条件编、去掉注释。使用gcc

指令预处理hello.c源文件:gcc -E hello.c -o hello.i

编译(生成汇编)

在这个阶段,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言。

词法分析:将源代码的字符序列分割成一系列的记号。

语法分析:对记号进行语法分析,生成语法树

语义分析:判断表达式是否有意义。

代码优化:如C++中连续的构造和拷贝构造的优化(注:这里只是举个例子!)

例如:gcc –S hello.i –o hello.s

汇编(生成机器可识别代码)

汇编阶段是把编译阶段生成的".s"文件转成目标文件。例如:gcc –c hello.s –o hello.o

链接(生成可执行文件或库文件)

在成功编译之后,就进入了链接阶段。例如:gcc hello.o –o hello

注意:C/C++程序是隔离编译,一起链接的!

在这里插入图片描述

gcc选项:

记忆 :使用选项ESc生成对应的iso(会网络的OSI模型反过来)后缀的文件

选项:

  • -E 只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面

  • -S 编译到汇编语言不进行汇编和链接

  • -c 编译到目标代码

  • -o 文件输出到 文件

  • -static 此选项对生成的文件采用静态链接

  • -g 生成调试信息。GNU 调试器可利用该信息。

  • -shared 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库.

  • -O0

  • -O1

  • -O2

  • -O3 编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高

  • -w 不生成任何警告信息。

  • -Wall 生成所有警告信息。

2.2.动静态库的制作和使用

函数库分为静态库和动态库(没有main函数),静态库是指编译链接时,把库文件的代码全部加入到可执行文件中。因此生成的文件比较大,但不在依赖库文件,后缀名一般为.a。动态库与之相反在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销,一般后缀名为.so

gcc默认生成的二进制程序,是动态链接的,可以使用file命令验证。静态库通过将地址以绝对映射的方式跟随进程加载到对应的地址空间当中,而动态库则通过相对地址编址,加载到文件映射区中,进程通过相对位置加上偏移就能在运行时链接到动态库。

样例代码

// 1.mymath.h
#pragma once
#include <stdio.h>
extern int sum(int x,int y);

// 2.mymath.c
#include"mymath.h"
int sum(int x,int y)
{
    return x + y;
}

// 3.test.c
#include "mymath.h"

int main()
{
    int x = 5;
    int y = 5;
    printf("%d + %d = %d\n",x,y,sum(x,y));
    
    return 0;
}

静态库的制作和使用:

静态库就是将编译好的.o文件和头文件使用ar打包成静态库,可以将对应的头文件和库放到gcc默认的搜索路径(不推荐),也可以指定路径或将其配置成环境变量(LIBRARY_PATH)或者配置脚本(.bashrc)。也可以创建软链接,来避免路径过深的问题。

xiyan@VM-20-5-ubuntu:~/code/lib$ tree
.
├── src
│   ├── mymath.c
│   └── mymath.h
└── test.c
xiyan@VM-20-5-ubuntu:~/code/lib/src$ gcc -c mymath.c -o mymath.o
xiyan@VM-20-5-ubuntu:~/code/lib/src$ ar -rc libmymath.a *.o
ar是gnu归档工具,rc表示(replace and create)
xiyan@VM-20-5-ubuntu:~/code/lib/src$ mkdir math
xiyan@VM-20-5-ubuntu:~/code/lib/src$ cp ./libmymath.a mymath.h ./math
xiyan@VM-20-5-ubuntu:~/code/lib/src/math$ ar -tv libmymath.a
-t:列出静态库中的文件
-v:verbose 详细信息
xiyan@VM-20-5-ubuntu:~/code/lib$ tree
.
├── src
│   ├── libmymath.a
│   ├── math
│   │   ├── libmymath.a
│   │   └── mymath.h
│   ├── mymath.c
│   ├── mymath.h
│   └── mymath.o
└── test.c
xiyan@VM-20-5-ubuntu:~/code/lib$ gcc test.c 
xiyan@VM-20-5-ubuntu:~/code/lib$ gcc test.c -I ./src/math/  -L ./src/math/ -l mymath
-I:表示头文件要查找的目录。gcc一般默认头文件查找:/usr/include,/usr/local/include
-L:表示库要查找的路径。gcc库查找路径:/lib,/usr/lib,/usr/local/lib
-l:表示库的名称
xiyan@VM-20-5-ubuntu:~/code/lib$ ln -s src/math math
xiyan@VM-20-5-ubuntu:~/code/lib$ gcc test.c -I math -L ./src/math/ -l mymath

动态库的制作和使用:

xiyan@VM-20-5-ubuntu:~/code/lib/src$ gcc -fPIC -c mymath.c
xiyan@VM-20-5-ubuntu:~/code/lib/src$ gcc -shared -o libmymath.so *.o
xiyan@VM-20-5-ubuntu:~/code/lib$ ln -s ./src/math/include
xiyan@VM-20-5-ubuntu:~/code/lib$ tree
.
├── include -> ./src/math/include
├── src
│   ├── math
│   │   ├── include
│   │   │   └── mymath.h
│   │   └── lib
│   │       ├── libmymath.a
│   │       └── libmymath.so
│   ├── mymath.c
│   ├── mymath.h
│   └── mymath.o
└── test.c
$ gcc test.c -I include -L ./src/math/lib/ -lmymath
-rwxrwxr-x  1 xiyan xiyan 15992 Mar 26 10:26 a.out*
动静态库连接名字相同,默认使用动态链接
$ gcc test.c -I include -L ./src/math/lib/ -lmymath --static
-rwxrwxr-x  1 xiyan xiyan 900368 Mar 26 10:24 a.out*
--static确认使用静态库的链接方式

xiyan@VM-20-5-ubuntu:~/code/lib$ ./a.out 
./a.out: error while loading shared libraries: libmymath.so: cannot open shared object file: No such file or directory
- 为什么这里运行不了,gcc test.c -I include -L ./src/math/lib/ -lmymath只是告诉gcc
- 编译器库在哪里,程序一旦运行起来形成进程和gcc就没有关系了!!动态库和可执行程序是分批加
- 载的,要告诉操作系统(加载器)库的路径在哪里!!!

xiyan@VM-20-5-ubuntu:~/code/lib$ ldd a.out 
	linux-vdso.so.1 (0x00007ffd11bc5000)
	libmymath.so => not found
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fbbe5348000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fbbe5581000)

解决方法:

方式1:添加至LD_LIBRARY_PATH(临时性)
$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:~/code/lib/src/math/lib
$ ./a.out 
5 + 5 = 10
方式2:/usr/lib(ubuntu)
$ sudo ln -s ~/code/lib/src/math/lib/libmymath.so /usr/lib/libmymath.so
$ ldd a.out 
	linux-vdso.so.1 (0x00007ffd5f0b5000)
	libmymath.so => /lib/libmymath.so (0x00007fda9c9e1000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fda9c7b8000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fda9c9f6000)
$ ./a.out 
5 + 5 = 10

总结:静态库是将生成的.o.h打包形成.a,gcc编译的时候能找到对应的头文件和库,编译完成就能直接使用。而动态库(.so)还要告知系统加载器,动态库的位置。可以通过软链接(推荐)的方式放在如/usr/lib或/lib64路径下(根据系统),再或者配置.bashrc这样的配置文件,总之要让加载器能找到!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值