如何进行电子商务网站推广?,珠海网站建设公司哪个好,wordpress推荐主题,惠州建设银行行号查询网站目录
0. 前言
1. 文件存储设备—磁盘
1.1 文件及存储介质
1.2 磁盘结构
1.3 磁盘存储结构
1.4 磁盘的抽象#xff08;虚拟、逻辑#xff09;结构
1.5 磁盘分区管理
2. 理解文件系统
2.1 Linux磁盘文件管理
2.2 文件inode属性及Data block数据追溯
2.3 inode编号及… 目录
0. 前言
1. 文件存储设备—磁盘
1.1 文件及存储介质
1.2 磁盘结构
1.3 磁盘存储结构
1.4 磁盘的抽象虚拟、逻辑结构
1.5 磁盘分区管理
2. 理解文件系统
2.1 Linux磁盘文件管理
2.2 文件inode属性及Data block数据追溯
2.3 inode编号及文件名
2.4 创建、删除及查看文件filesystem运作
3. 软硬链接
3.1 创建软硬链接
3.2 软硬链接的区别
4. 动静态库
4.1 动态链接和静态链接
4.2 静态库的制作
4.3 动态库的制作
4.3 静态库的使用方法
4.3.1不太建议方法一安装第三方静态库到系统路径下
4.3.2 方法二硬链接静态库
4.4 动态库的使用方法
4.4.1 动态库的加载过程
4.4.2 不太建议方法一安装第三方动态库到系统路径下
4.4.3 方法二设置环境变量$LD_LIBRARY_PATH
4.4.4 方法三修改配置文件/etc/ld.so.conf.d/
4.4.5 推荐方法三在系统路径下建立软连接
4.4.6 其他方法设置登录脚本
4.5 为什么要有库推荐库 0. 前言 有关上篇文章 基础IO(1) 问题遗留解答及总结 问题如下 1. 如下述代码重定向后使用C标准库函数写入后使用系统调用接口close关闭文件后运行后其重定向文件内部没有数据而在close之前使用C标准库提供的fflush函数后文件内部便有了数据作何解释 #includeiostream
#includecstdio
#includeunistd.h
#includecstring
#includesys/stat.h
#includesys/types.h
#includefcntl.hint main(){close(1);int fd open(log.txt, O_CREAT | O_TRUNC | O_WRONLY, 0666);if(fd -1){perror(open);return 1;}printf(hello printf\n);close(fd);return 0;
} 运行结果 [customerVM-4-10-centos 2review]$ ./myfile
[customerVM-4-10-centos 2review]$ ll
total 20
-rw-rw-r-- 1 customer customer 0 Aug 24 15:45 log.txt
-rw-rw-r-- 1 customer customer 76 Aug 24 15:43 Makefile
-rwxrwxr-x 1 customer customer 8856 Aug 24 15:43 myfile
-rw-rw-r-- 1 customer customer 355 Aug 24 15:43 myfile.cc
[customerVM-4-10-centos 2review]$ cat log.txt
[customerVM-4-10-centos 2review]$ 而当加入fflushC标准库函数后其文件内部有结果 [customerVM-4-10-centos 2review]$ clear
[customerVM-4-10-centos 2review]$ ./myfile
[customerVM-4-10-centos 2review]$ ll
total 24
-rw-rw-r-- 1 customer customer 14 Aug 24 15:47 log.txt
-rw-rw-r-- 1 customer customer 76 Aug 24 15:47 Makefile
-rwxrwxr-x 1 customer customer 9008 Aug 24 15:47 myfile
-rw-rw-r-- 1 customer customer 375 Aug 24 15:47 myfile.cc
[customerVM-4-10-centos 2review]$ cat log.txt
hello printf
[customerVM-4-10-centos 2review]$ 解释如下由上篇文章可知用户级缓冲区是由C标准库提供和维护的向显示器刷新策略为行刷新向磁盘文件内部刷新策略为全刷新由于重定向stdout为磁盘文件因此数据被保存在缓冲区而系统调用接口close及操作系统底层并不知道C所提供的缓冲区的概念因此必须在使用C标准库所提供的fflush函数刷新到内核缓冲区才会得到结果 2. 可知C语言C程序默认打开三个流Cstdinstdoutstderr Ccincoutcerrin out分别对应着标准输入和标准输出那么stderr和stdout都是对应显示器文件又有什么区别呢看下述代码 #includeiostream
#includecstdio
#includeunistd.h
#includecstring
#includesys/stat.h
#includesys/types.h
#includefcntl.hint main(){printf(hello printf 1\n);fprintf(stdout, hello fprintf 1\n);fprintf(stderr, hello fprintf 2\n);const char* s1 hello write 1\n;write(1, s1, strlen(s1));const char* s2 hello write 2\n;write(2, s2, strlen(s2));std::cout hello cout 1 std::endl;std::cerr hello cout 2 std::endl; return 0;
} 运行结果如下 [customerVM-4-10-centos 2review]$ ./myfile
hello printf 1
hello fprintf 1
hello fprintf 2
hello write 1
hello write 2
hello cout 1
hello cout 2有运行结果可知C语言stdout stderr C语言cout cerr都是往显示器打印进行如下测试结果 [customerVM-4-10-centos 2review]$ clear
[customerVM-4-10-centos 2review]$ ./myfileok.txt 2err.txt
[customerVM-4-10-centos 2review]$ cat ok.txt
hello write 1
hello printf 1
hello fprintf 1
hello cout 1
[customerVM-4-10-centos 2review]$ cat err.txt
hello fprintf 2
hello write 2
hello cout 2 解释如下stdin和stderr分别对应着显示器文件stdin封装文件描述符为1的被创建打开的显示器文件stderr封装文件描述符为2的被创建打开的显示器文件因此在运行程序时都会向显示器输出而重定向时默认重定向关闭的是stdin即1号文件描述符的文件当将2号文件描述符也进行重定向此时便可以将进程运行错误信息和成功信息分别根据其文件描述符不同重定向至不同的文本文档形成日志文件。 基础IO1总结如下 Linux一切皆文件是一种设计则学内核将文件的全部数据内容和属性包括操作方法使用函数指针形成运行时多态全部封装到struct file结构体当打开文件OS针对文件系统会根据所打开文件的进程的PCB创建相应的struct file将文件加载到内存并加载当文件管理的数据结构中并将struct file结构体的指针填入到对应进程PCB的struct files*所指向的struct files中的struct file* array[]从而对文件的操作底层调用文件file的操作方法进程创建时会继承父进程的文件描述符而缓冲区则是标准库所提供的用户级缓冲区可通过一般策略和特殊策略减少IO预备次数及频繁使用次数提高效率 1. 文件存储设备—磁盘 在计算机上除了被打开的文件有没有没有被打开的文件 磁盘——磁盘级文件 学习磁盘文件侧重点 单个文件系统 —— 这个文件在哪里这个文件的其他属性是什么... 站在系统角度 —— 一共有多少个文件各自属性在哪里如何快速找到我们还可以存储多少个文件如何快速找到指定的文件 ... 如何进行对磁盘文件分门别类的存存储用来支持更好的存取 1.1 文件及存储介质 内存 —— 掉电易失存储介质 磁盘 —— 永久性存储介质 - SSD、光盘、U盘、磁带、flash 服务器主流的依然是磁盘性价比高存储容量大价格便宜 磁盘是一个外设磁盘还是计算机中唯一的机械设备速度慢OS一定会有提速方式 1.2 磁盘结构 磁盘具有磁盘盘片磁头伺服系统音圈马达...等各种硬件组成 音圈马达运行盘片旋转磁头左右快速摇摆便是寻址过程 一个磁盘如一个 1T 的机械硬盘由多个盘片如下图中的 0 号盘片叠加而成。 盘片的表面涂有磁性物质这些磁性物质用来记录二进制数据。因为正反两面都可涂上磁性物质故一个盘片可能会有两个盘面。 物理性质 盘面上会存储数据 —— 计算机只认识二进制两态 —— 磁铁物质正负极 —— 盘面上存在大量的磁性介质 —— 向磁盘写入本质就是改变盘片上的正负性磁头上电子信号放电改变 1.3 磁盘存储结构 每个盘片被划分为一个个磁道每个磁道又划分为一个个扇区。 下图显示的是一个盘面盘面中一圈圈灰色同心圆为一条条磁道从圆心向外画直线可以将磁道划分为若干个弧段每个磁道上一个弧段被称之为一个扇区图践绿色部分。扇区是磁盘的最小组成单元通常是512字节。由于不断提高磁盘的大小部分厂商设定每个扇区的大小是4096字节 硬盘通常由重叠的一组盘片构成每个盘面都被划分为数目相等的磁道并从外缘的“0”开始编号具有相同编号的磁道形成一个圆柱称之为磁盘的柱面。磁盘的柱面数与一个盘面上的磁道数是相等的。由于每个盘面都有自己的磁头因此盘面数等于总的磁头数。 如下图 存储容量 磁头数 × 磁道(柱面)数 × 每道扇区数 × 每扇区字节数 上图最后一例图中磁盘是一个 3个圆盘6个磁头7个柱面每个盘片7个磁道 的磁盘图3中每条磁道有12个扇区所以此磁盘的容量为 存储容量 6 * 7 * 12 * 512 258048 每个磁道的扇区数一样是说的老的硬盘外圈的密度小内圈的密度大每圈可存储的数据量是一样的。新的硬盘数据的密度都一致这样磁道的周长越长扇区就越多存储的数据量就越大。 每个盘面对应一个磁头。所有的磁头都是连在同一个磁臂上的因此所有磁头只能“共进退”。所有盘面中相对位置相同的磁道组成柱面 其中最内侧磁道上的扇区面积最小因此数据密度最大。 磁盘的物理地址 由上可用柱面号盘面号扇区号来定位任意一个“磁盘块”。 在“文件的物理结构”中经常提到文件数据存放在外存中的几号块逻辑地址这个块号就可以转换成柱面号盘面号扇区号的地址形式。 可根据该地址读取一个“块”操作如下 ① 根据“柱面号”移动磁臂让磁头指向指定柱面 ② 激活指定盘面对应的磁头 ③ 磁盘旋转的过程中指定的扇区会从磁头下面划过这样就完成了对指定扇区的读/写。 上述论述部分参考文章 硬盘基本知识磁头、磁道、扇区、柱面 - js王 - 博客园 (cnblogs.com) 在物理上如何把数据写入到指定的扇区里如何找到一个指定扇区 1. 在哪一个磁道上柱面上cylinder 2. 在哪一个面上盘面对应的就是那个磁头head 3. 在哪一个扇区上sector 上述寻址方式成为CHS寻址 如果有CHS寻址方式就能找到任意一个扇区上的任意位置那么所有的位置就都可以找到了 1.4 磁盘的抽象虚拟、逻辑结构 磁带中的圆形结构 可以转换为 线性结构 因此磁盘盘片就可以想象成线性结构 因此想要访问某个扇区本质就转换为数组下标只需要知道下标即可 上述这种寻址方式称为LBA寻址 逻辑区块寻址Logical Block Addressing 此时访问扇区本质就是将LBA转换为CHS 操作系统访问磁盘 —— LBA寻址 —— CHS寻址 1.5 磁盘分区管理 可知磁盘内容容量大如何进行有效管理磁盘 采用分区管理 —— 分而治之方法相同 对将每个分区划分为更小的分区 最终对磁盘文件的管理 就转化为 对块组的管理 2. 理解文件系统
2.1 Linux磁盘文件管理 Linux ext2文件系统上图为磁盘文件系统图内核内存映像肯定有所不同磁盘是典型的块设备硬盘分区被划分为一个个的block。一个block的大小是由格式化的时候确定的并且不可以更改。例如mke2fs的-b选项可以设定block大小为1024、2048或4096字节。而上图中启动块Boot Block的大小是确定的 虽然磁盘的基本单位是扇区512byte但是操作系统文件系统和磁盘进行IO的基本单位是4kb块大小4 * 1024byte —— 为什么不以512byte为单位呢 1. 太小了会导致多次IO进而导致效率的降低 2. 如果操作系统使用和磁盘一样的大小万一磁盘的基本大小改变了OS源码要不 要改变呢会导致强耦合将硬件和软件进行解耦 文件 内容 属性 而Linux存储是将内容和属性分开进行存储的 超级块Super Block存放文件系统本身的结构信息。记录的信息主要有bolck 和 inode的总量 未使用的block和inode的数量一个block和inode的大小最近一次挂载的时间最近一次写入数据的时间最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏可以说整个 文件系统结构就被破坏了Date Blocks存储文件内容一个数据块为4kbinode Tableinode是一个大小为128字节的空间保存的是对应文件的属性如文件大小所有者最近修改时间等而inode Table该块组内是所有文件inode属性空间的集合因为需要标识唯一性所以每一个inode块都有一个编号及每个文件inode属性空间内都有一个唯一标识inode编号一般而言一个文件一个inode一个inode编号Block Groupext2文件系统会根据分区的大小划分为数个Block Group。而每个Block Group都有着相同的结构组成GDTGroup Descriptor Table块组描述符描述块组属性信息这个块组多大已经使用多少了有多少个inode已经占用了多少还剩多少一共有多少个block使用了多少block......块位图Block BitmapBlock Bitmap中记录着Data Block中哪个数据块已经被占用哪个数据块没有被占用inode位图inode Bitmap每个bit表示一个inode是否空闲可用 我们将块组分割成上面内容并且写入相关的管理数据每一个块组同样如此整个分区就被写入了文件系统信息格式化过程 2.2 文件inode属性及Data block数据追溯 可知一个文件只对应一个inode属性节点inode编号 一个文件只能有一个Data block吗答案是不一定 哪些Data block属于同一个文件找到文件只要找到对应的inode编号就能找到该文件的inode属性集合可是文件的内容如何找到呢如下图 只要知道inode编号便可以通过inode Table找到其属性集合而属性集合中包含了其使用的Data block便可以找到文件的内容 对于大型文件其inode属性中block全部使用仍不够其数据如何存储呢 答案是 不是所有的Data block只能用于存储文件数据也可以存储其他块的块号使用间接索引的方式就可以找到大量的Data block 2.3 inode编号及文件名 找到文件 - 找到文件inode编号 - 找到特定分区 - 根据inode Table找到inode属性 - 根据inode属性找到Data block 怎么知道inode编号文件名和inode的关系 Linux中inode属性里没有文件名这样的说法 [rootlocalhost linux]# touch hello
[rootlocalhost linux]# ls -ia hello
131023 . 131055 .. 131074 hello 如上图目录及inode的映射关系 1. 一个目录下可以保存很多文件但是这些文件没有重复的文件名 2. 目录是文件因此目录需要有自己的inode有自己的Data block而目录的Data block存储的是文件名和对应inode编号的映射关系都具有唯一性互为Key值 进入目录需要x权限而在目录下创建文件需要w权限必须要有w权限才能将映射关系写入到目录的Data block内才能创建文件显示文件名和属性需要具有r权限要拿到目录下文件的inode及属性必须得到目录Data block内的映射关系因此必须具备r权限得到目录下的文件名和对应的inode进而找到inode属性进行显示 总 找到inode编号一定是依托目录结构的在目录Data block保存了对应的inode编号及文件名映射 2.4 创建、删除及查看文件filesystem运作 创建一个新文件主要有一下4个操作 存储属性 内核先在inode Bitmap中找到一个空闲的inode节点这里是131074将其inode Bitmap中的0置为1。拿到inode编号内核把文件信息属性记录到inode Table中。存储数据 该文件需要存储在三个磁盘块内核在Block Bitmap找到了三个空闲块300500800。将内核缓冲区的第一块数据复制到300下一块复制到500以此类推。记录分配情况 文件内容按顺序300,500,800存放。内核在inode上的磁盘分布区记录了上述块列表。建立目录映射 添加文件名及inode来自filesystem映射到目录的Data Block中 删除一个文件主要操作 找到目录对应的Data Block找到文件名映射的inode找到对应inode Table属性将其对应数据块Block Bitmap置为零并不将数据清除下次写入直接覆盖将inode Bitmap置为零inode Table也不清楚下次使用直接覆盖将目录映射关系去除完成删除 因为只是将inode对应的Block Bitmap、inode Bitmap置为0目录Data Block清除映射关系所以在文件数据及inode属性未被覆盖的情况下获取到已删除文件的inode可以进行数据恢复 查看一个文件主要操作 ls显示文件名直到找到当前目录的inode及Data Block便可以找到该目录下各个文件的映射关系便可以找到各个文件的inode属性 注意 文件系统是在分区或格式化时被写入的进而分成对应的块其中inode Bitmap128kb 及 Data Block是固定的 Linux下创建文件失败的原因 1. 文件分区下Data Block已经被全部使用而inode Bitmap未被全部使用 2. 文件分区下inode Bitmap全部被使用Data Block未被全部使用 3. 软硬链接
3.1 创建软硬链接 软链接指令ln -s 链接文件 新文件 硬链接指令ln 链接文件 新文件 [customerVM-4-10-centos 3review]$ ln -s testLink1.txt soft.txt
[customerVM-4-10-centos 3review]$ ln -s /usr/bin/ls bySearch
[customerVM-4-10-centos 3review]$ ln testLink2.txt hard.txt
[customerVM-4-10-centos 3review]$ ls -il
total 0
1317283 lrwxrwxrwx 1 customer customer 11 Aug 25 16:41 bySearch - /usr/bin/ls
1317280 -rw-rw-r-- 2 customer customer 0 Aug 25 16:39 hard.txt
1317282 lrwxrwxrwx 1 customer customer 13 Aug 25 16:39 soft.txt - testLink1.txt
1317279 -rw-rw-r-- 1 customer customer 0 Aug 25 16:39 testLink1.txt
1317280 -rw-rw-r-- 2 customer customer 0 Aug 25 16:39 testLink2.txt 3.2 软硬链接的区别 1. 软链接具有独立的inode - 软链接是一个独立的文件 特性可以理解为软链接的文件内容是指向文件对应的路径 应用软链接相当于windows下的快捷方式 2. 硬链接没有独立inode - 硬链接不是一个独立的文件 特性其inode属性中有一个数字表示硬链接数每删除硬链接数减一直至0 硬链接不是真正的创建新文件就是在指定的目录下建立了文件名和指定的inode的映射关系仅此而已硬链接相当于对同一个文件起别名在inode属性中有一个引用计数记录硬链接数当硬链接数为0此文件才会被真正删除 因此删除文件 除了rm命令也可以使用unlink命令 为什么新建一个目录它的硬链接数为2 因为在目录内部有隐藏文件 . 其inode和dir的inode相同记录了该dir目录的路径因此在执行cd .命令时就相当于 cd dir而..是上级目录的硬链接 cd .. 就相当于 cd 上级绝对路径 4. 动静态库 在这里涉及到一个重要的概念:函数库 我们的C程序中并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而 没有定义函数的实现,那么,是在哪里实现“printf”函数的呢? 最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用 4.1 动态链接和静态链接 函数库一般分为静态库和动态库 动态链接 DLL将库中我要的方法的地址填入我的可执行程序中建立关联节省资源。静态链接SLL将库中方法的实现直接拷贝到我们的可执行程序中占用资源。 静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为“.a” 动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。 动态库一般后缀名为“.so”,如前面所述的 libc.so.6 就是动态库。 gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件 gcc默认生成的二进制程序是动态链接的这点可以通过 file 命令验证。 gcc 和 g 默认生成的可执行程序默认是动态连接的 -static 表明使用静态链接的方式形成可执行程序 yum install -y glibc-static #C语言静态库安装 yum install -y libstdc-static #C静态库安装 4.2 静态库的制作 静态库制作库是要提供给别人使用的因此库中没有main函数库的发布文件一般为一个目录其目录下包括include主要保存头文件lib主要保存.a文件 静态库文件.a的创建ar -rc libxxx.a xxx.o xxx.o 其中形成的.a文件名开头必须是lib 生成静态库
[rootlocalhost linux]# ar -rc libmymath.a add.o sub.o
ar是gnu归档工具rc表示(replace and create)
查看静态库中的目录列表[rootlocalhost linux]# ar -tv libmymath.a
rw-r--r-- 0/0 1240 Sep 15 16:53 2017 add.o
rw-r--r-- 0/0 1240 Sep 15 16:53 2017 sub.o
t:列出静态库中的文件
v:verbose 详细信息 如下 myprint.h #pragma once
#includestdio.h
#includetime.hextern void Print(const char* str); myprint.c #includemyprint.hvoid Print(const char* str){printf(%s[%d]\n, str, (int)time(NULL));
} mymath.h #pragma once
#includestdio.hextern int addToTarget(int from, int to); mymath.c #includemymath.hint addToTarget(int from, int to){int sum 0;for(int i from; i to; i){sum i;}return sum;
} makefile libhello.a:mymath.o myprint.oar -rc $ $^
mymath.o:mymath.cgcc -c $^ -o $ -stdc11
myprint.o:myprint.cgcc -c $^ -o $ -stdc11
.PHONY:lib
lib:mkdir mylib mylib/include mylib/libcp mymath.h myprint.h mylib/include/rm mymath.o myprint.omv libhello.a mylib/lib/
.PHONY:clean
clean:rm mylib -rf 4.3 动态库的制作 静态库的加载是将代码拷贝进我们的可执行程序内而程序具有地址空间因为静态库的使用需要拷贝到指定地址空间的位置静态库在编制的时候必须按照程序以绝对地址的方式编址 动态库采用相对编址方案不需要考虑程序的地址空间因此动态库是由与地址无关的目标二进制文件形成段地址 偏移方式 makfile libhello.so:mymath.o myprint.ogcc -shared $^ -o $
mymath.o:mymath.cgcc -fPIC -c $^ -o $ -stdc11
myprint.o:myprint.cgcc -fPIC -c $^ -o $ -stdc11
.PHONY:lib
lib:mkdir mysolib mysolib/include mysolib/libmv libhello.so mysolib/lib/cp myprint.h mymath.h mysolib/include/rm mymath.o myprint.o
.PHONY:clean
clean:rm mysolib -rfv运行结果 [customerVM-4-10-centos mylib_so]$ ls
makefile mymath.c mymath.h myprint.c myprint.h mysolib
[customerVM-4-10-centos mylib_so]$ tree mysolib/
mysolib/
|-- include
| |-- mymath.h
| -- myprint.h
-- lib-- libhello.so2 directories, 3 files 4.3 静态库的使用方法 静态库的使用三种方法 测试代码main.c #includemymath.h
#includemyprint.hint main(){Print(hello Linux!);int res addToTarget(1, 100);printf(res : %d\n, res);return 0;
}4.3.1不太建议方法一安装第三方静态库到系统路径下 关于gcc头文件的默认搜索路径是/usr/include库文件的默认搜索路径是/lib64 or /usr/lib64 将需要使用的静态库拷贝到系统默认路径下就叫做库的安装 [customerVM-4-10-centos usrlib]$ clear
[customerVM-4-10-centos usrlib]$ sudo cp ./mylib/include/*.h /usr/include/
[sudo] password for customer:
[customerVM-4-10-centos usrlib]$ sudo cp ./mylib/lib/*.a /usr/lib64/
[customerVM-4-10-centos usrlib]$ ls /usr/lib64/libhello.a
/usr/lib64/libhello.a 此时重新编译main.c发现扔报错
[customerVM-4-10-centos usrlib]$ gcc main.c -stdc11
/tmp/ccp2na2X.o: In function main:
main.c:(.text0xe): undefined reference to Print
main.c:(.text0x1d): undefined reference to addToTarget
collect2: error: ld returned 1 exit status
[customerVM-4-10-centos usrlib]$ 因为对于自己写的库属于第三方库不是语言提供的也不是系统自带的使用第三方库必须要告诉其链接的库属于哪一个库 库取名字去掉前缀lib去掉后缀.a剩下的为名字 [customerVM-4-10-centos usrlib]$ gcc main.c -l hello
[customerVM-4-10-centos usrlib]$ ./a.out
hello Linux![1693036772]
res : 50504.3.2 方法二硬链接静态库 可知编译器搜索头文件首先在系统路径下/usr/include/进行搜索其次在当前路径下搜索而静态库文件的头文件在其自己icnlude目录下因此必须告诉编译器头文件include的位置同时库也没有在系统路径下安装且属于第三方库因此也需要告诉编译器库文件library的位置而库文件lib路径下可能具有大量的库因此最后还指明我们要引入的库 [customerVM-4-10-centos usrlib]$ ls
main.c mylib
[customerVM-4-10-centos usrlib]$ gcc main.c -I ./mylib/include/ -L ./mylib/lib/ -l hello
[customerVM-4-10-centos usrlib]$ ls
a.out main.c mylib
[customerVM-4-10-centos usrlib]$ ./a.out
hello Linux![1693037426]
res : 50504.4 动态库的使用方法 测试代码仍为静态库中的main.c文件 当使用硬链接动态库的方式进行链接时若库目录下lib文件夹具有动静态库且库名字相同都为hello那么默认链接的是静态库还是动态库呢 [customerVM-4-10-centos usrlib]$ gcc main.c -I ./mysolib/include/ -L ./mysolib/lib/ -l hello
[customerVM-4-10-centos usrlib]$ tree mysolib/
mysolib/
|-- include
| |-- mymath.h
| -- myprint.h
-- lib|-- libhello.a-- libhello.so2 directories, 4 files
[customerVM-4-10-centos usrlib]$ GCC默认使用动态库 [customerVM-4-10-centos usrlib]$ 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]e26ad8b59222f53ba2bdf91d719bc49aa1ddd4e8, not stripped
[customerVM-4-10-centos usrlib]$ ./a.out
./a.out: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory
[customerVM-4-10-centos usrlib]$ c 但是通过硬链接使用动态库发现运行错误动态链接失败 把动态库移除再次使用硬链接方式进行链接ldd [customerVM-4-10-centos usrlib]$ mv mysolib/lib/libhello.so ./
[customerVM-4-10-centos usrlib]$ gcc main.c -I ./mysolib/include/ -L ./mysolib/lib/ -l hello
[customerVM-4-10-centos usrlib]$ ./a.out
hello Linux![1693040732]
res : 5050
[customerVM-4-10-centos usrlib]$ ldd a.out linux-vdso.so.1 (0x00007ffd969f0000)libc.so.6 /lib64/libc.so.6 (0x00007f25e53df000)/lib64/ld-linux-x86-64.so.2 (0x00007f25e57ad000)
[customerVM-4-10-centos usrlib]$
[customerVM-4-10-centos usrlib]$ gcc main.c -I ./mysolib/include/ -L ./mysolib/lib/ -l hello -static
l[customerVM-4-10-centos usrlib]$ ldd a.out not a dynamic executable
[customerVM-4-10-centos usrlib]$ 如果只有静态库默认使用静态库的静态链接方式将数据拷贝到可执行程序内如果还有动态库默认链接动态库带上-static优先使用静态库静态链接 4.4.1 动态库的加载过程 由上图分析可知此时动态库并没有加载到内存因此使用此动态库运行的进程在访问页表映射时找不到加载的动态库运行错误 虽然告诉了gcc库所链接位置但是运行加载的时候就和gcc没有关系了因此需要告诉操作系统加载器加载动态库为什么C语言C动态库没有告诉系统呢因为语言提供的动态库默认在系统路径下安装系统通过配置文件自动加载静态库不存在加载问题 [customerVM-4-10-centos usrlib]$ 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]e26ad8b59222f53ba2bdf91d719bc49aa1ddd4e8, not stripped
[customerVM-4-10-centos usrlib]$ ./a.out
./a.out: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory
[customerVM-4-10-centos usrlib]$
[customerVM-4-10-centos usrlib]$ ldd a.out linux-vdso.so.1 (0x00007ffc42d86000)libhello.so not foundlibc.so.6 /lib64/libc.so.6 (0x00007f6082517000)/lib64/ld-linux-x86-64.so.2 (0x00007f60828e5000)
[customerVM-4-10-centos usrlib]$ 4.4.2 不太建议方法一安装第三方动态库到系统路径下 [customerVM-4-10-centos usrlib]$ gcc main.c -I ./mysolib/include/ -L ./mysolib/lib/ -l hello
[customerVM-4-10-centos usrlib]$ ldd a.out linux-vdso.so.1 (0x00007ffc42d86000)libhello.so not foundlibc.so.6 /lib64/libc.so.6 (0x00007f6082517000)/lib64/ld-linux-x86-64.so.2 (0x00007f60828e5000)
[customerVM-4-10-centos usrlib]$ ls
a.out main.c mylib mysolib
[customerVM-4-10-centos usrlib]$ sudo cp mysolib/lib/libhello.so /usr/lib64/
[sudo] password for customer:
[customerVM-4-10-centos usrlib]$ ./a.out
hello Linux![1693042665]
res : 5050
[customerVM-4-10-centos usrlib]$ ldd a.out linux-vdso.so.1 (0x00007ffdcb586000)libhello.so /lib64/libhello.so (0x00007f49a8942000)libc.so.6 /lib64/libc.so.6 (0x00007f49a8574000)/lib64/ld-linux-x86-64.so.2 (0x00007f49a8b44000)
[customerVM-4-10-centos usrlib]$ 系统路径下库文件会通过配置文件有操作系统进行自动加载将动态库加载到内存 4.4.3 方法二设置环境变量$LD_LIBRARY_PATH 设置环境变量$LD_LIBRARY_PATH 加载动态库其中表示拼接不会覆盖以前的环境变量 [customerVM-4-10-centos usrlib]$ ls /home/customer/LinuxLearn/second/28lesson/4review/usrlib/mysolib/lib/
libhello.a libhello.so
[customerVM-4-10-centos usrlib]$ ldd a.out linux-vdso.so.1 (0x00007fffe1beb000)libhello.so not foundlibc.so.6 /lib64/libc.so.6 (0x00007fa6eca0c000)/lib64/ld-linux-x86-64.so.2 (0x00007fa6ecdda000)
[customerVM-4-10-centos usrlib]$ export LD_LIBRARY_PATH$LD_LIBRARY_PATH:/home/customer/LinuxLearn/second/28lesson/4review/usrlib/mysolib/lib/
[customerVM-4-10-centos usrlib]$ echo $LD_LIBRARY_PATH
:/home/customer/.VimForCpp/vim/bundle/YCM.so/el7.x86_64:/home/customer/LinuxLearn/second/28lesson/4review/usrlib/mysolib/lib/
[customerVM-4-10-centos usrlib]$ ./a.out
hello Linux![1693043273]
res : 5050
[customerVM-4-10-centos usrlib]$ ldd a.out linux-vdso.so.1 (0x00007ffe31bce000)libhello.so /home/customer/LinuxLearn/second/28lesson/4review/usrlib/mysolib/lib/libhello.so (0x00007fda446ec000)libc.so.6 /lib64/libc.so.6 (0x00007fda4431e000)/lib64/ld-linux-x86-64.so.2 (0x00007fda448ee000)
[customerVM-4-10-centos usrlib]$ 此时设置的环境变量是内存级的环境变量因此一旦退出xshell此环境变量便会失效 4.4.4 方法三修改配置文件/etc/ld.so.conf.d/ /etc/ld.so.conf.d/ 此路径保存的是可以允许自定义配置搜索库路径的永久解决方案 因此可以再此文件夹内添加自己的配置文件将库的所在目录的绝对路径写入调用ldconfig重新加载配置文件此时便永久性的加载了动态库即使xshell重启也不会销毁 [customerVM-4-10-centos usrlib]$ ldd a.out linux-vdso.so.1 (0x00007ffd06b37000)libhello.so not foundlibc.so.6 /lib64/libc.so.6 (0x00007f709dccb000)/lib64/ld-linux-x86-64.so.2 (0x00007f709e099000)
[customerVM-4-10-centos usrlib]$ ls /etc/ld.so.conf.d/
bind-export-x86_64.conf dyninst-x86_64.conf kernel-3.10.0-1160.71.1.el7.x86_64.conf mariadb-x86_64.conf
[customerVM-4-10-centos usrlib]$ sudo touch /etc/ld.so.conf.d/testso.conf
[sudo] password for customer:
[customerVM-4-10-centos usrlib]$ ls /etc/ld.so.conf.d/
bind-export-x86_64.conf dyninst-x86_64.conf kernel-3.10.0-1160.71.1.el7.x86_64.conf mariadb-x86_64.conf testso.conf
[customerVM-4-10-centos usrlib]$ sudo vim /etc/ld.so.conf.d/testso.conf
[customerVM-4-10-centos usrlib]$ sudo cat /etc/ld.so.conf.d/testso.conf
/home/customer/LinuxLearn/second/28lesson/4review/usrlib/mysolib/lib/
[customerVM-4-10-centos usrlib]$ sudo ldconfig
[customerVM-4-10-centos usrlib]$ ./a.out
hello Linux![1693043789]
res : 5050
[customerVM-4-10-centos usrlib]$ ldd a.out linux-vdso.so.1 (0x00007ffd3c7e1000)libhello.so /home/customer/LinuxLearn/second/28lesson/4review/usrlib/mysolib/lib/libhello.so (0x00007fdbd86bf000)libc.so.6 /lib64/libc.so.6 (0x00007fdbd82f1000)/lib64/ld-linux-x86-64.so.2 (0x00007fdbd88c1000)
[customerVM-4-10-centos usrlib]$ echo $LD_LIBRARY_PATH
:/home/customer/.VimForCpp/vim/bundle/YCM.so/el7.x86_64
[customerVM-4-10-centos usrlib]$ 此时即使环境变量LD_LIARARY_PATH没有此路径也可以运行使用该库的程序 4.4.5 推荐方法三在系统路径下建立软连接 通过软链接方式是系统默认加载库文件时找到路径将第三方动态库load至内存 [customerVM-4-10-centos usrlib]$ sudo ln -s /home/customer/LinuxLearn/second/28lesson/4review/usrlib/mysolib/lib/libhello.so /usr/lib64/libhello.so
[customerVM-4-10-centos usrlib]$ ls /usr/lib64/libhello.so -l
lrwxrwxrwx 1 root root 80 Aug 26 18:08 /usr/lib64/libhello.so - /home/customer/LinuxLearn/second/28lesson/4review/usrlib/mysolib/lib/libhello.so
[customerVM-4-10-centos usrlib]$ ./a.out
hello Linux![1693044544]
res : 5050
[customerVM-4-10-centos usrlib]$ unlink删除链接文件或者删除文件u 4.4.6 其他方法设置登录脚本 本质还是设置环境变量在用户根目录下隐藏文件.bashrc导环境变量 和 .bash_profile其中.bash_profile调用.bashrc 4.5 为什么要有库推荐库 站在使用库的角度库的存在可以大大减少我们开发的周期提高软件本身的质量 站在写库的人的角度1. 使用简单 2. 代码安全 推荐的库 1. ncurses -- 字符的界面库 -- centos 7 yum 安装necurses 2. Boost -- C准标准库