【Linux】静态库与动态库的制作

版权声明:本文为博主原创文章,未经博主允许不得转载。Copyright (c) 2018, code farmer from sust. All rights reserved. https://blog.csdn.net/sustzc/article/details/82734377

man 2 stat   stat函数
stat  day12.txt 查看文件状态信息
    struct stat sbuf;
    求文件大小 sbuf.st_size
ls -i test.txt   可以查找inode号

注意:指针前面没有加const,就表示该指针是个传出型参数。

存储文件时,除了文件本身以外,还会存储文件的属性(权限,拥有者,时间)等基本信息。


文件系统
文件系统是OS管理持久性数据的子系统,提供数据存储和访问的功能。
文件系统中的基本单位就是数据块。
    超级块(磁盘分区以及文件系统描述信息)、索引块(inode,访问权限,拥有者,大小)、目录项构成一棵目录树、  磁盘上的数据块
    索引块中保存数组下标就是inode号,inode指向文件所使用的数据块列表(链表存放),这样就可以在数据区查找数据。
    我们查看文件信息时,是按照文件名去查找的,而OS会先查找文件所在的目录,通过目录中保存的表格查找到文件的inode号,
    然后OS再通过文件名对应的inode号去索引块中查找inode号对应的数据区的编号。
    
    实际上,每个目录就是一张表,这张表中存储了文件名和其对应的inode号之间的映射关系,最终构成了一棵目录树。
一些文件系统提供文件锁,用于协调多进程的文件访问。
    强制
        根据锁保持情况和访问需求确定是否拒绝访问
    劝告
        进程可以查找锁的状态来决定该怎么做
索引分配
    为每个文件创建一个索引数据块,指向文件数据块的指针列表,文件头包含了索引数据块指针
    
当文件小时,采用直接索引的方式,当文件大时,采用多级链式索引的方式.
根分区是采用了硬编码的方式写进去的
    ls -ldi /    是2    根分区的索引是采用硬编码的方式写死的。
硬链接:  ln 源文件名 硬链接文件名  eg: ln abc abc.h
    执行ls -l命令后,出现在权限后面的数字就是硬链接数 (有几个文件名对应着同一个inode)
    文件所有者的权限,文件所属组的权限 和 其他用户对文件的权限
        目录的硬链接数至少是2(一个在当前目录的父目录中保存,一个在当前目录下面保存)
    如果删除硬链接,那么数字减1,直到数字减为0后,磁盘才会删除掉这个文件。(引用计数)
硬链接应用
    备份 只是inode指向同一个文件,并不是真正的拷贝文件,不占用磁盘空间。        cp需要分配空间去复制
        ln Makefile .Makefile   创建一个硬链接(并且是隐藏文件.),这时如果删除了Makefile,也没事,最多只是引用计数减去1。
    需要注意的是,Windows上没有硬链接,有软链接,而Linux上既有硬链接还有软链接(也就是快捷方式)。
                  例如不能ln haha mnt/hgfs/shared/hehe
    硬链接不能跨分区  
        也就是说C盘不能访问D盘的硬链接  例如不能ln haha mnt/hgfs/shared/hehe
软链接:ln -s 源文件名 软链接文件名
    软链接可以跨分区,实际上软链接就是个路径。
    
acm
    Access 最后访问时间
    Change 属性最后修改时间
    Modify 文件内容最后修改时间

库:
静态库 对一系列.o文件打包
    交给客户 .o以及.h文件
    需要进行编译。
    首先生成.o文件(gcc -c )
    接着生成静态库 ar -cr lib库名.a  *.o (文件)            库名 :去头掐尾留中间
    最后使用静态库 gcc main.c -L . -l库名   (.表示当前路径)         非官方的写法  gcc main.c libmath.a
                    (.表示库路径)
    寻找库/lib  –> /usr/lib  –> /usr/local/lib

    将生成的库放在上述路径下面也可以。
    安装软件时需要root权限,是因为要把相关软件的库放在上述路径下面,只有root权限才允许这样做。
    如果删除了已经生成的静态库,并不会影响到可执行文件的运行,查看机器码即可发现代码已经被插进去了。
    
    objdump命令是用来查看目标文件或者可执行的目标文件的构成的gcc工具。
    objdump -dS a.out  查看a.out的反汇编机器码
    
    使用静态库的好处:运行速度快。
    静态库的缺陷:
        当多个进程都要使用到某个静态库时,那么每一次都会在物理内存中开辟一片空间来存放(相同的机器码),这样会造成极大的资源浪费。
    
动态库(共享库 shared library)   共享存储映射区
    需要注意的是:
        将库中的机器码(只读)或者说符号信息存到物理内存中,只需要存储一份即可,哪个进程需要使用该库,
        就将存储的内容通过三级映射最后映射到进程的虚拟内存中。
            使用动态库好处:节省内存空间,可以实现平滑升级。
        动态库没有添加代码进去,nm查看没有地址,动态库只是将符号信息存进去。
        如果同时有静态库和动态库,优先选择动态库。
        运行时才添加动态库
常见的ELF文件
    a.out  .o文件  coredump产生的core文件  .so文件
        可重定位文件(relocatable)  : linux下的.o文件,windows下的.obj文件
        可执行文件(executable) : linux下的/bin/bash文件或者a.out,windows下的.exe文件
        共享目标文件(shared object) : linux下的.so文件,windows下的.dll文件
        核心转储文件(core dump) :linux下的core dump 段错误
    生成动态库
        1》gcc -fPIC -shared -o lib库名.so xxx.c   (PIC 位置无关的代码)如果不加上PIC可能会导致在其他机器上运行出错。
                -shared -o后面加的是动态库文件名
            file XXX.so查看文件类型
            file libmath.a  该文件是个归档文件
    链接动态库
        2》gcc main.c -L. -lmymath
    使用动态库
    如果没有配置的话,会出现下面的问题
        ldd a.out 动态库文件找不到      
        ldd命令用来查看都装了哪些动态库
        ldd -u a.out查看不需要链接的so文件
    linux-vdso.so.1 =>  (0x00007ffe625d2000)
    libmath.so => not found
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fcbe0612000) 标准C库链接
    /lib64/ld-linux-x86-64.so.2 (0x00007fcbe09dc000)  动态链接器
        3》
        1./lib
          /usr/lib
        
        2. LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
        export LD_LIBRARY_PATH
        
        export LD_LIBRARY_PATH=.
        执行结果 ldd a.out
            libmath.so => ./libmath.so (0x00007f255461f000)
            
        3.推荐使用
        /etc/ld.so.conf.d/xxx.conf   文件中将动态库的路径写入
        
        echo `pwd` > /etc/ld.so.conf.d/my.conf  将当前路径写入动态库 (``命令替换)
        
        4. ldconfig  使用该命令可以让动态链接库为系统所共享。  必须在root权限下使用
            -p输出缓存文件/etc/ld.so.cache中的动态链接库列表,同时也会输出共享库的名字及其绝对路径。
            -v显示正在扫描的目录及搜索到的共享库。
        执行结果 ldd a.out
            libmath.so => /home/zc/C_test/mk_test/lib/libmath.so (0x00007fb7a7d3f000)

    qq平滑升级正是利用了动态库,替换掉之前的动态库文件即可。
    升级过程中不能中断,如果替换动态库文件出了问题,就会导致升级失败。
    
    动态库的运行时处理
    dlopen()    

进程间通信(IPC)
    目的:
        数据传输  (消息队列)
        资源共享  (共享内存)
        通知事件  kill pid(信号量)
        进程控制  gdb
    管道
        最古老的进程间通信方式(半双工)
        单工  :广播
        半双工  : 对讲机
        全双工  : 打电话
            | 管道,本质,内核中开辟的一块缓存
        特点:一个进程可以往里面写 另外一个进程可以从里面读 读写必须同时进行
        int pipe(int fds[2]);
        fds:文件描述符数组,其中fds[0]表示读端(读取数据来自管道), fds[1]表示写端(将数据写到管道里面)
        成功返回0,失败返回-1
            子进程往管道里面写数据,由于fork出子进程后,引用计数会加1,那么在写数据时,就需要关掉一个,并且写的时候不能读。
            父进程从管道里面读数据,由于fork出子进程后,引用计数会加1,那么在读数据时,就需要关掉一个,并且读的时候不能写。
            
            过程讲解:首先,内核会开辟出来一个管道缓存用来临时存放数据(pipe(fds)),由于管道中读写数据必须同时进行,
            而父进程fork出一个子进程,刚好满足这种需求。
                子进程要往管道里面写数据,
            那么就需要保证子进程不能在管道中读取数据close(fds[0]),然后子进程往管道中写入数据write(fds[1], "123", 3),
            子进程写完数据后,暂时不再需要写入数据,就把子进程的写端关闭close(fds[1])。
                父进程从管道里面读取数据,
            那么就需要保证父进程不能在管道中写数据close(fds[1]),然后父进程开始从管道中读取数据read(fds[0], buf, 100),
            父进程读取完数据后,暂时不会再读取数据,就把父进程的读端关闭close(fds[0])。
        
    硬盘中真实存在的文件:普通文件、目录文件、软链接文件(快捷方式)
      |
    SystemV IPC
        消息队列(数据传输)
        共享内存(数据共享)
        信号量(事件通知)
      |
    POSIX IPC
        消息队列
        共享内存
        互斥量
        条件变量
        信号量
        读写锁
        
    介绍下进程间通信的方式
        管道、读写文件 网络通信

猜你喜欢

转载自blog.csdn.net/sustzc/article/details/82734377