• 【Linux】软硬链接与动静态库(理解软硬链接的特点及使用场景、如何建立动静态库与使用第三方库)


    一、软链接

    1.1 如何建立软链接
    1. //建立软链接 -s代表soft
    2. ln -s 目标文件名 链接文件名
    3. //删除软链接
    4. rm 链接文件
    5. unlink 链接文件

    1.2 软链接的特点与功能

    通过ls -i指令可以查看文件的inode编号

    可以看出目标文件与软链接文件各自有自己的inode,所以软链接是一个独立的文件

    查看目标文件与查看链接文件的内容是相同的,这个类似于快捷方式的功能

    所以在项目中当我们需要访问一个路径很深的文件时,我们可以建立一个软链接,这样访问文件就不需要每次都输入完整的路径了

    当我们删除目标文件时,会发现软链接失效了,这是因为软链接的内容保存的是目标文件对应的路径字符串,当目标文件被删除时,软链接也就失效了

    二、硬链接

    2.1 如何建立硬链接
    1. //建立软链接 ln默认为硬链接
    2. ln 目标文件名 链接文件名
    3. //删除软链接
    4. rm 链接文件
    5. unlink 链接文件

    2.2 硬链接的特点与功能

    可以发现硬链接与目标文件的inode编号是相同的,所以硬链接不是一个独立的文件,其使用的是目标文件的inode,并且我们发现当建立硬链接后,文件中间的有个数字从1变成了2,这个数字类似于引用计数,表示与该inode编号映射的文件的个数

    所以硬链接就是文件名与inode编号的一个映射关系,建立硬链接的本质就是在指定目录下,建立一个新用户名与inode编号的映射关系

    当删除目标文件时,硬链接还可以正常使用,只是引用计数会减1,对文件建立硬链接然后删除目标文件就相当于对文件重命名

    #硬链接的功能:

    1.构建Linux路径结构(.与..)

    当新建一个文件其引用计数是1,因为只有一个文件名与inode编号对应,而当建立一个目录,其引用计数是2,这是因为每个文件默认有两个名字为 . ..的文件,.对应的是当前目录,所以新建一个目录其引用计数必定是2,当在目录中创建子目录时(仅父子关系),父目录的引用计数也会加1,因为子目录的..对应父目录,所以我们也可以通过查看目录的引用计数,来判断该目录下有几个子目录

    2.做文件的备份

    当对目标文件建立硬链接后,若误删目标文件,我们也可以通过硬链接找回,所以硬链接可以做文件的备份

    三、动静态库

    3.1什么是动静态库

            静态库和动态库是计算机程序开发中两种不同的库类型,它们都是预先编译好的二进制代码集合,用于提供可重用的功能模块给其他程序调用。

    #静态库:
    静态库在链接阶段会被完整地加入到最终生成的可执行文件中。当编译器在创建一个程序时,如果程序引用了静态库中的函数或对象,那么静态库中的相关代码会被复制并整合到该程序内部。因此,静态链接后的可执行文件包含了程序运行所需的所有库代码,不需要在运行时依赖外部文件。静态库常见的扩展名有 `.a`(Unix/Linux 系统)或 `.lib`(Windows 系统)。

    #动态库:
    动态库(也称共享库或DLL - 动态链接库,在Windows系统中)则在程序运行时加载,并且多个程序可以共享同一份库代码。这意味着,动态库并不被直接合并到可执行文件中,而是作为独立的文件存在(扩展名为 `.so` 在Unix/Linux系统中,`.dll` 在Windows系统中)。当程序启动时,操作系统根据程序内存储的引用信息,将动态库加载到内存中,并让程序通过某种机制(如符号查找)来调用库中的函数或数据。这样做的好处是可以减少磁盘空间占用和内存开销,同时方便更新库文件而不必重新编译连接依赖它的所有程序。

    总结来说,静态库的特点是编译时链接、代码体积大但独立运行,而动态库的特点是运行时链接、节省资源但依赖环境,当库被删除时,程序就跑不起来了

    3.2 静态库

     如何建立与使用静态库

    以如下四个文件举例:

    Add.h:

    1. #pragma once
    2. #include
    3. int add(int a,int b)

    Add.c:

    1. int add(int a,int b)
    2. {
    3. return a+b;
    4. }

    Sub.h:

    1. #pragma once
    2. #include
    3. int sub(int a,int b)

    Sub.c:

    1. int sub(int a,int b)
    2. {
    3. return a-b;
    4. }

    当我们写了一份代码需要给别人,但是不想让他知道源代码是什么,我们可以将所有的.c文件先编译成.o的二进制文件,在给他提供相应的头文件信息,这样别人就可以使用我们的程序而不知道我们的代码了

    但是这样操作有很大的局限性,如果我们的代码有几百个头文件,几百个.o文件,用户必须将所有的.o文件放到他的目录下,少一个可能程序就跑不起来了,如果将头文件与实现封装成一个库,那这样的问题就解决了

    如何建立一个静态库:

    1.先将所有的.c文件以仅编译不链接的方式形成.o文件

    1. gcc -c xxx.c
    2. (会默认形成一个同名的.o文件)

    2.使用ar命令形成静态库,静态库名称一般以lib开头.a结尾

    ar -rc libmyc.a *.o

    ar:gnu归档工具

    -r(replace):若静态库中的文件有所更新,就替换为新文件

    -c(create):若静态库中的文件更新后,不存在某些文件,就建立这些文件

    3.第二步其实就已经形成静态库了,但是为了方便管理,可以将对应的头文件也封装到一个include目录(名字随意)下,并将libmyc.a与include在封装到一个mylib文件中,这样一个第三方静态库就建立好了

    如何使用第三方静态库:

    方法一:

    将第三方的头文件与库文件加载到系统的库搜索路径中

    1. zyq@iZf8z3j2ckkap6ybtz8qseZ:~/mydir$ sudo cp mylib/include/*.h /usr/include/
    2. zyq@iZf8z3j2ckkap6ybtz8qseZ:~/mydir$ sudo cp mylib/lib/*a /lib64

    若此时直接编译main文件,会发现找不到add与sub函数,这是因为gcc/g++默认认识系统原本的库,而libmyc.a是第三方库,gcc不认识它,所以就找不到库中方法的实现

    在使用第三方库时,需要用到 -l 选项标识自己用的库文件名(库文件名默认是去掉lib前缀和.a后缀)

    方法二:

    利用选项

    • -I:(大写的I) 指明用户自定义头文件的路径
    • -L:指明用户自定义库的路径
    • -l:(小写的L)指明引用到的库文件

    3.3 动态库

    如何建立动态库

    1.首先将.c文件编译为.o文件,与静态库的方式不同的是需要加一个 -fpic(产生位置无关码(position independent code) )的选项

    gcc -fpic -c Add.c Sub.c

    2.将.o文件封装成动态库

    • shared: 表示生成共享库格式
    • 库名规则:libxxx.so
    • 不需要使用ar指令,gcc/g++会默认生成动态库
    gcc -shared -o libmyc.so *.o
    
    如何使用动态库

    我们将形成的动态库与静态库放到一起,然后编译一下,会发现编译成功,但是可执行程序不能正常运行,如果我们加以一个-static的选项,强制使用动态库链接,发现程序可以正常执行,这说明当静态库与动态库同时存在时,编译优先使用动态库

    那为什么使用静态库程序就可以运行,使用动态库就不可以呢?

    【解释】:静态库在编译时就将代码加载到文件中了,运行时就与静态库没有关系了,我们通过-I -L等选项提供的路径告诉的是编译器,但是没有告诉操作系统我们的库在哪里,所以可以编译成功但是不能执行,动态库使用需要在运行时将库找到并加载

    解决方法:

    1.拷贝.so文件到系统共享库路径下, 一般指/usr/lib(不推荐,使用多了会造成污染)

    2.在系统共享库路径下创建动态库的软链接

    3.命令行导入环境变量:在LD_LIBRARY_PATH环境变量后加入动态库的绝对路径

    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/zyq/mydir/dir/mylib/lib
    

    ps.这种方法重启xshell就失效了

    4.修改.bashrc文件,加上动态库的绝对路径,让环境变量永久生效

    5.在/etc/ld.so.conf.d目录下配置文件,并加载

    以root身份进入/etc/ld.so.conf.d目录中,创建一个以.conf为后缀的文件,将动态库的路径保存到该文件中,并利用 ldconfig 指令让配置文件生效

  • 相关阅读:
    封装一个Element-ui生成一个可行内编辑的表格(vue2项目)
    Vue.js入门教程(七)
    Workplace Search 的演变:使用 Elasticsearch 搜索你的私人数据
    使用SpaceDesk实现iPad成为电脑拓展屏(保姆级教程)
    Unsafe概述
    JVM之对象的内存模型、创建过程、对象引用、生命周期
    经典双栈实现队列,注意遍历栈的判定条件修改。
    图论|841钥匙和房间
    高速公路安全监测预警系统的功能优势
    Rt-Thread 6-空闲线程
  • 原文地址:https://blog.csdn.net/m0_74910646/article/details/137975667