【Linux】系统部分——软硬链接动静态库的使用
18.软硬链接_动静态库的使用
文章目录
- 18.软硬链接_动静态库的使用
- 软硬链接
- 软链接
- 硬链接
- 软硬链接的作用
- 静态库
- 创建一个静态库
- 静态库的使用
- 1.将库安装到系统目录下
- 2.直接在当前目录下使用
- 3.使用指定路径下的库
- 动态库
- 制作一个动态库
- 动态库的使用
- 1.将库安装到系统目录下
- 2.直接在当前目录下使用
- 3.使用指定路径下的库(此操作前需要先把系统中安装的动态库删除)
- 总结一下
- 总结一下
软硬链接
软链接
[user@iZ7xvdsb1wn2io90klvtwlZ lession20]$ touch file.txt
[user@iZ7xvdsb1wn2io90klvtwlZ lession20]$ ln -s file.txt file-soft.link #对file.txt创建软链接
[user@iZ7xvdsb1wn2io90klvtwlZ lession20]$ ls -li
total 0
665991 lrwxrwxrwx 1 user user 8 Jul 18 13:54 file-soft.link -> file.txt
665990 -rw-rw-r-- 1 user user 0 Jul 18 13:53 file.txt
[user@iZ7xvdsb1wn2io90klvtwlZ lession20]$ echo hello linux > file.txt
[user@iZ7xvdsb1wn2io90klvtwlZ lession20]$ cat file.txt
hello linux
[user@iZ7xvdsb1wn2io90klvtwlZ lession20]$ cat file-soft.link
hello linux
-
软链接本质上是一个独立文件,他有自己的inode
-
在用户层使用软链接等同于使用目标文件
-
软链接的内容上,保存的是目标文件的路径,类似于Windows上的快捷方式
-
删除软链接有两种方法:
rm
、ulink
硬链接
我们看到,真正找到磁盘上⽂件的并不是⽂件名,⽽是inode。其实在linux中可以让多个⽂件名对应于同⼀个inode 。
[user@iZ7xvdsb1wn2io90klvtwlZ lession20]$ ln file.txt file-hard.link
[user@iZ7xvdsb1wn2io90klvtwlZ lession20]$ ls -li
total 8
665990 -rw-rw-r-- 2 user user 12 Jul 18 14:03 file-hard.link
665991 lrwxrwxrwx 1 user user 8 Jul 18 13:54 file-soft.link -> file.txt
665990 -rw-rw-r-- 2 user user 12 Jul 18 14:03 file.txt
[user@iZ7xvdsb1wn2io90klvtwlZ lession20]$ cat file.txt
hello linux
[user@iZ7xvdsb1wn2io90klvtwlZ lession20]$ cat file-hard.link
hello linux
-
硬链接与软链接不同,不是独立文件,硬链接没有属于自己的独立
inode
号,与原文件的inode
相同 -
当一个文件存在一个硬链接的时候,会发现执行
ls -l
命令后有一个数字从1变成的2,这个数字就是引用计数(硬链接数)存在硬链接之前:665990 -rw-rw-r-- 1 user user 0 Jul 18 13:53 file.txt
存在硬链接之后:665990 -rw-rw-r-- 2 user user 12 Jul 18 14:03 file.txt
-
硬链接本质上就是一组文件名和已经存在的文件的映射关系
-
通过之前的学习,我们已经知道了,文件系统中的
inode
不保存文件名,文件名与inode
的映射关系是由目录文件保存的,当没有一个文件名指向某一个inode
的时候,这个inode
对应的文件才会被删除,所以要想知道现在是否有文件名指向某个文件(某个文件是否可以被删除),inode
中存在一个叫引用计数的东西,记录当前有多少文件名指向这个ionde
,这也就是上面第二点提到的内容 -
当创建一个空目录的时候,这个空目录的引用计数默认是2,因为创建一个空目录时,在空目录中会自动创建两个隐藏目录**
./
和../
这两个文件就分别是当前目录和上级目录的硬链接**,所以不仅当前空目录的引用计数是2,上级目录的引用计数还要+1 -
Linux中不允许对目录创建硬链接,防止创建环状路径导致一系列问题
当我们删除被软硬连接的原文件之后:
- 硬链接
file-hard.link
并没有受到影响,但是软链接file-soft.link
失效 - 重新生成
file.txt
文件之后,软链接恢复,指向新建的file.txt
文件,但是file-hard.link
不再是新建的file.txt
的硬链接了
软硬链接的作用
硬链接:文件备份,以及每一个文件目录中的/.和/…都是硬链接
软链接:快捷方式
静态库
简单来说,库本质上是⼀种可执⾏代码的⼆进制形式,可以被操作系统载⼊内存执⾏。库有两种:动态库和静态库,分别有不同的后缀
- 静态库:
.a
[linux]、.lib
[windows] - 动态库:
.so
[linux]、.dll
[windows]
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ ls /lib64/libc-2.17.so -l
-rwxr-xr-x 1 root root 2151672 Jul 3 2019 /lib64/libc-2.17.so
[whb@bite-alicloud ~]$ ls /lib64/libc.a -l
-rw-r--r-- 1 root root 5105516 Jun 4 23:05 /lib64/libc.a
- 程序在编译链接的时候把库的代码链接到可执⾏⽂件中,程序运⾏的时候将不再需要静态库。
- ⼀个可执⾏程序可能⽤到许多的库,这些库运⾏有的是静态库,有的是动态库,⽽我们的编译默认为动态链接库,只有在该库下找不到动态.so的时候才会采⽤同名静态库。我们也可以使⽤ gcc 的 -static 强转设置链接静态库。
创建一个静态库
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ ls
main.c my_stdio.c my_stdio.h my_string.c my_string.h
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ gcc -c my_stdio.c
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ gcc -c my_string.c
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ ls
main.c my_stdio.c my_stdio.h my_stdio.o my_string.c my_string.h my_string.o
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ vim my_string.c
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ ar -rc libmystdio.a m
main.c my_stdio.c my_stdio.h my_stdio.o my_string.c my_string.h my_string.o
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ ar -rc libmystdio.a my_stdio.o my_string.o
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ ls
libmystdio.a main.c my_stdio.c my_stdio.h my_stdio.o my_string.c my_string.h my_string.o
把准备好的源文件编译为.o
文件(gcc -c
编译为同名.o
文件),使用ac -rc
创建静态库。
注意一下静态库的命名规范:前缀为lib
+名称+后缀为.a
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ ls -li
total 36
666002 -rw-rw-r-- 1 user user 4374 Aug 22 15:12 libmystdio.a
665998 -rw-rw-r-- 1 user user 488 Aug 21 11:06 main.c
665995 -rw-rw-r-- 1 user user 1496 Aug 21 11:06 my_stdio.c
665997 -rw-rw-r-- 1 user user 447 Aug 21 11:06 my_stdio.h
665996 -rw-rw-r-- 1 user user 2848 Aug 22 15:11 my_stdio.o
665989 -rw-rw-r-- 1 user user 133 Aug 21 11:13 my_string.c
665999 -rw-rw-r-- 1 user user 44 Aug 21 11:14 my_string.h
666000 -rw-rw-r-- 1 user user 1272 Aug 22 15:11 my_string.o
-
ar
在man中的解释为:创建、修改和从归档文件中提取内容。ar 是 gnu 归档⼯具, rc 表⽰ (replace and create) -
t: 列出静态库中的⽂件、v:verbose 详细信息
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ ar -tv libmystdio.a rw-rw-r-- 1001/1001 2848 Aug 22 15:11 2025 my_stdio.o rw-rw-r-- 1001/1001 1272 Aug 22 15:11 2025 my_string.o
静态库的使用
1.将库安装到系统目录下
- 我们可以把前面打包好的静态库安装到系统中,这样就可以在使用vim编写代码的时候直接使用我们自己的库了。如果要把库安装到系统中,需要把
.h
文件拷贝到/usr/include
目录下,把库拷贝到/lib64
目录下
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ sudo cp *.h /usr/include/
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ ls /usr/include/my_*
/usr/include/my_stdio.h /usr/include/my_string.h
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ sudo cp libmystdio.a /lib64/
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ ls /lib64/libmystdio.a
/lib64/libmystdio.a
- 除了将文件拷贝到系统当中,我们自己写的库为第三方库,gcc不能直接识别,所以我们在使用gcc编译使用这个库的代码的时候需要指明
[user@iZ7xvdsb1wn2io90klvtwlZ lession21]$ cat main.c
#include <my_stdio.h>
#include <my_string.h>
#include <stdio.h>int main()
{const char *s = "aaa";printf("%s, %d\n", s, my_strlen(s));mFILE *fp = mfopen("./text.txt", "w");if(fp == NULL) return 1;mfwrite(s, my_strlen(s), fp);mfwrite(s, my_strlen(s), fp);mfwrite(s, my_strlen(s), fp);mfwrite(s, my_strlen(s), fp);mfclose(fp);return 0;
}
[user@iZ7xvdsb1wn2io90klvtwlZ lession21]$ gcc -o main main.c -lmystdio
[user@iZ7xvdsb1wn2io90klvtwlZ lession21]$ ls
main main.c stdio
[user@iZ7xvdsb1wn2io90klvtwlZ lession21]$ ./main
aaa, 3
在指明的时候,库的前缀lib
和后缀.a
都不需要,在前面加上-l
(注意一下,不需要有空格,如果需要多个库,每个库都要按照这个格式写,包括-l
)
2.直接在当前目录下使用
gcc编译器默认只会在/usr/lib64
目录下寻找库是否存在,不会再当前路径下查找,如果要使用当前路径下的库,则在指明库的前面加上-L.
(L后面的.
表示在当前目录),告诉编译器,编译的时候,查找库,除了系统路径,也要在我指明的路径下找,还要注意,在代码中头文件的包含不能再使用<>
而是要用""
如果不修改会出现:
[user@iZ7xvdsb1wn2io90klvtwlZ lession21]$ gcc -o main main.c -L. -lmystdio
main.c:1:22: fatal error: my_stdio.h: No such file or directory#include <my_stdio.h>^
compilation terminated.
gcc使用:
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ gcc -o main main.c -L. -lmystdio
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ ls
libmystdio.a main main.c my_stdio.c my_stdio.h my_stdio.o my_string.c my_string.h my_strin.o
3.使用指定路径下的库
将编写好的库进行打包后交给其他人使用:
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ cat Makefile
libmystdio.a: my_stdio.o my_string.o@ar -rc $@ $^@echo "build $^ to $@ ... done"
%.o:%.c@gcc -c $<@echo "compling $< to $@ ... done".PHONY:clean
clean:@rm -f *.a *.o@echo "clean done".PHONY:output
output:@mkdir -p stdc/lib@mkdir -p stdc/include@cp -f *.h stdc/include @cp -f *.a stdc/lib@tar -czf stdc.tgz stdc @echo "output stdc ... done"
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ make
compling my_stdio.c to my_stdio.o ... done
compling my_string.c to my_string.o ... done
build my_stdio.o my_string.o to libmystdio.a ... done
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ make output
output stdc ... done
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ ll
total 64
-rw-rw-r-- 1 user user 4374 Aug 30 17:28 libmystdio.a
-rw-rw-r-- 1 user user 368 Aug 30 17:29 Makefile
-rw-rw-r-- 1 user user 1496 Aug 30 16:14 my_stdio.c
-rw-rw-r-- 1 user user 447 Aug 21 11:06 my_stdio.h
-rw-rw-r-- 1 user user 2848 Aug 30 17:28 my_stdio.o
-rw-rw-r-- 1 user user 133 Aug 21 11:13 my_string.c
-rw-rw-r-- 1 user user 44 Aug 21 11:14 my_string.h
-rw-rw-r-- 1 user user 1272 Aug 30 17:28 my_string.o
drwxrwxr-x 4 user user 4096 Aug 30 17:29 stdc
-rw-rw-r-- 1 user user 1719 Aug 30 17:29 stdc.tgz
使用:
[user@iZ7xvdsb1wn2io90klvtwlZ lession21]$ tar xzf stdc.tgz
[user@iZ7xvdsb1wn2io90klvtwlZ lession21]$ ls
main.c stdc stdc.tgz stdio
[user@iZ7xvdsb1wn2io90klvtwlZ lession21]$ gcc -o main main.c -Istdc/include -Lstdc/lib -lmystdio
[user@iZ7xvdsb1wn2io90klvtwlZ lession21]$ ls
main main.c stdc stdc.tgz stdio
[user@iZ7xvdsb1wn2io90klvtwlZ lession21]$ ./main
aaa, 3
- 使用
-I+路径
告知gcc额外要查找的头文件路径 - 使用
-L+路径
告知gcc额外要查找的静态库路径
动态库
制作一个动态库
与制作静态库不同,制作动态库不使用ar
命令,直接用gcc
命令但是带有-shared
用来制作动态库
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ cat Makefile
libmystdio.so: my_stdio.o my_string.ogcc -o $@ $^ -shared%.o:%.cgcc -fPIC -c $<.PHONY:clean
clean:rm -rf *.o *.so
- 制作动态库gcc命令需要带有
-share
选项 - 制作动态库的
.o
文件在生成时需要带有-fPIC
选项,表示生成位置无关码
动态库的使用
1.将库安装到系统目录下
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ sudo cp -f libmystdio.so /lib64
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ sudo cp -f *.h /usr/include/
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ ll /lib64/libmy*
-rwxr-xr-x 1 root root 8592 Aug 30 19:02 /lib64/libmystdio.so
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ ll /usr/include/my*
-rw-r--r-- 1 root root 447 Aug 30 19:02 /usr/include/my_stdio.h
-rw-r--r-- 1 root root 44 Aug 30 19:02 /usr/include/my_string.h
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ gcc -o main main.c -lmystdio
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ ls
libmystdio.so main main.c Makefile my_stdio.c my_stdio.h my_stdio.o my_string.c my_string.h my_string.o
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ ./main
aaa, 3
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ ldd mainlinux-vdso.so.1 => (0x00007ffe5376c000)libmystdio.so (0x00007fde939f9000)libc.so.6 => /lib64/libc.so.6 (0x00007fde9362c000)/lib64/ld-linux-x86-64.so.2 (0x00007fde93bfb000)
-
ldd
命令用于查看可执行程序依赖哪些动态库 -
如果动态库被删掉,可执行文件就无法执行了
2.直接在当前目录下使用
与静态库一致,这里就不重复了
3.使用指定路径下的库(此操作前需要先把系统中安装的动态库删除)
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ cat Makefile
libmystdio.so: my_stdio.o my_string.ogcc -o $@ $^ -shared%.o:%.cgcc -fPIC -c $<.PHONY:clean
clean:@rm -rf *.so *.o stdc*@echo "clean done".PHONY:output
output:@mkdir -p stdc/lib@mkdir -p stdc/include@cp -f *.h stdc/include @cp -f *.so stdc/lib@tar -czf stdc.tgz stdc @echo "output stdc ... done"
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ ls
main main.c Makefile my_stdio.c my_stdio.h my_string.c my_string.h text.txt
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ make
gcc -fPIC -c my_stdio.c
gcc -fPIC -c my_string.c
gcc -o libmystdio.so my_stdio.o my_string.o -shared
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ make output
output stdc ... done
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ ls
libmystdio.so main main.c Makefile my_stdio.c my_stdio.h my_stdio.o my_string.c my_string.h my_string.o stdc stdc.tgz text.txt
[user@iZ7xvdsb1wn2io90klvtwlZ stdio]$ cd ..
[user@iZ7xvdsb1wn2io90klvtwlZ lession21]$ ls
main.c stdio
[user@iZ7xvdsb1wn2io90klvtwlZ lession21]$ cp stdio/stdc.tgz .
[user@iZ7xvdsb1wn2io90klvtwlZ lession21]$ tar xzf stdc.tgz
[user@iZ7xvdsb1wn2io90klvtwlZ lession21]$ ls
main.c stdc stdc.tgz stdio
[user@iZ7xvdsb1wn2io90klvtwlZ lession21]$ gcc -o main main.c -Istdc/include -Lstdc/lib -lmystdio
[user@iZ7xvdsb1wn2io90klvtwlZ lession21]$ ./main
./main: error while loading shared libraries: libmystdio.so: cannot open shared object file: No such file or directory
[user@iZ7xvdsb1wn2io90klvtwlZ lession21]$ ldd mainlinux-vdso.so.1 => (0x00007ffc10de7000)libmystdio.so => not foundlibc.so.6 => /lib64/libc.so.6 (0x00007f3d4c56b000)/lib64/ld-linux-x86-64.so.2 (0x00007f3d4c938000)
我们会发现按照静态库的使用方法能够正常编译得到可执行文件,但是可执行文件不能正确执行,通过ldd
指令显示没有找到动态库。原因是虽然在gcc
命令中已经指定了动态库的路径和名称,但也只是在编译过程中指定的,所以可执行文件编译没有出错,但是执行可执行文件是系统的操作,对于操作系统来说,它仍然不知道你的动态库的路径,操作系统寻找库文件依赖于一个环境变量:LD_LIBRARY_PATH
[user@iZ7xvdsb1wn2io90klvtwlZ lession21]$ env
XDG_SESSION_ID=9332
HOSTNAME=iZ7xvdsb1wn2io90klvtwlZ
TERM=xterm
SHELL=/bin/bash
HISTSIZE=1000
SSH_CLIENT=218.77.77.245 59880 22
OLDPWD=/home/user/lession21/stdio
SSH_TTY=/dev/pts/1
USER=user
LD_LIBRARY_PATH=:/home/user/.VimForCpp/vim/bundle/YCM.so/el7.x86_64 #在这行
LS_COLORS=rs=#...................#
MAIL=/var/spool/mail/user
PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/user/.local/bin:/home/user/bin
PWD=/home/user/lession21
LANG=en_US.UTF-8
HISTCONTROL=ignoredups
SHLVL=1
HOME=/home/user
LOGNAME=user
SSH_CONNECTION=218.77.77.245 59880 172.18.20.98 22
LESSOPEN=||/usr/bin/lesspipe.sh %s
XDG_RUNTIME_DIR=/run/user/1001
_=/usr/bin/env
因此我们可以通过一下方法使可执行文件正常运行:
- 将动态库添加到
LD_LIBRARY_PATH
指定的路径——一般就是/lib64
路径下(拷贝) - 在
/lib64
路径下建立所需动态库的软链接 - 新增环境变量
LD_LIBRARY_PATH
的库文件路径,但要注意环境变量在每次服务器重启后会重新加载 - 在
/etc/ld.so.conf.d
路径下允许用户添加配置文件,在这个路径下添加一个任意名称的.conf
文件,文件内容为动态库的路径,系统就会自动找到这个路径下的动态库,ldconfig更新
总结一下
此时就需要清楚动态库与静态库的区别了,通过静态库形成的可执行文件不需要再找静态库的位置,不多解释。
如果同时提供动态库和静态库,则优先使用动态库,如果需要强制使用静态库,则在
gcc
命令后面添加-static
选项(这个之前讲过)如果需要强制静态链接,必须提供对应的静态库;如果只提供静态库,但是链接方式是动态的,gcc、g++没得选,只能针对提供的
.a
局部性采用静态链接
64路径下建立所需动态库的软链接 3. 新增环境变量
LD_LIBRARY_PATH的库文件路径,但要注意环境变量在每次服务器重启后会重新加载 4. 在
/etc/ld.so.conf.d路径下允许用户添加配置文件,在这个路径下添加一个任意名称的
.conf`文件,文件内容为动态库的路径,系统就会自动找到这个路径下的动态库,ldconfig更新
总结一下
此时就需要清楚动态库与静态库的区别了,通过静态库形成的可执行文件不需要再找静态库的位置,不多解释。
如果同时提供动态库和静态库,则优先使用动态库,如果需要强制使用静态库,则在
gcc
命令后面添加-static
选项(这个之前讲过)如果需要强制静态链接,必须提供对应的静态库;如果只提供静态库,但是链接方式是动态的,gcc、g++没得选,只能针对提供的
.a
局部性采用静态链接