2. 静态库和动态库的生成与使用

第二部分 静态库和动态库

在C语言中,函数库文件分为两种类型,一种是静态库(库程序是直接注入目标程序的,不分彼此,库文件通常以.a结尾),另一种是动态库(库程序是在运行目标程序时(中)加载的,库文件通常以.so结尾)

img

2.1静态库

静态库,是因为在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接。

静态库可以简单看成是一组目标文件(.o文件)的集合,即很多目标文件经过压缩打包后形成的一个文件。

  • 在linux中静态库以lib 作为前缀,以**.a**作为后缀,中间库的名字自己指定,如libxxx.a
2.1.1静态库的生成
  1. 先对源文件进行汇编操作(-c参数),得到二进制格式的目标文件(.o格式)

  2. 使用 ar 工具将目标文件打包得到静态库文件(libxxx.a)

使用ar工具的时实用的三个参数

  1. c :创建一个库
  2. s创建目标文件索引,可以加快时间
  3. r: 在库职工插入(替换)模块,默认的新成员添加在库的结尾出,若模块名已经在库中存在,则替换同名的模块

演示如下

关于编译时的一些参数可以参考 1. GCC编译器的使用 g++生成可执行文件 编译参数的解析

文件目录:

Screenshot from 2023-08-18 11-45-41

  1. 生成 .o 文件
g++ -c *.cpp

-I 指定头文件路径

Screenshot from 2023-08-18 11-49-13

  1. 打包.o文件,得到静态库
ar rcs 静态库名称(libxxx.a) 材料(*.o)

Screenshot from 2023-08-18 11-56-29

  1. 静态库的发布使用

提供得到的libxxx.a文件和头文件

2.1.2 静态库的使用

-L 指定库的路径

-l 指定库的名称(即libxxx.axxx 部分)

Screenshot from 2023-08-18 12-04-59

得到可执行文件main

2.2 动态库

动态库是程序在运行的时候才去链接相应的动态库代码的,多个程序共享使用库的代码。一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码。

在可执行文件开始运行前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接。

2.2.1动态库的生成

使用g++或gcc命令,添加 -fpic 以及 -shared 参数

-fpic : 使得生成的代码与位置无关,即使用的是相对位置

-shared : 生成动态链接库

示例1:

# 分成两步
# 得到.o文件
g++ -c -fpic add.cpp sub.cpp -I ./Include/
# 将得到的.o文件打包成动态库
g++ --shared add.o sub.o -o libcal.so

Screenshot from 2023-08-18 14-22-57

示例2:

# 一步 生成 动态库 libcal.so
g++ add.cpp sub.cpp -I ./Include/ -fpic -shared -o libcal.so

Screenshot from 2023-08-18 14-15-51

2.2.2 动态库的使用
g++ main.cpp -I ./Include/ -L./ -lcal -o main

Screenshot from 2023-08-18 14-27-52

2.2.3 动态库无法加载

Screenshot from 2023-08-18 14-31-33

动态库的路径并未被记录到可执行程序中,对应的动态库文件也没有被打包到可执行程序中,只是在可执行程序中记录了库的名字。

当可执行程序执行时,会先检测需要的动态库是否可以被加载到,加载不到则会提示上述错误。

动态库的检测和内存的加载都是由动态链接器来实现的,的那个动态库中的函数被调用了,这个时候动态库才会加载到内存。

我们可以使用ldd 程序名 来检测动态库是否都能被检测到,如下图所示,可知,无法找到 libcal.so 库。

Screenshot from 2023-08-18 14-45-55

2.2.4动态链接器

动态链接器按照位置搜索顺序依次查找动态库,查找位置的优先级如下:

  1. 可执行文件的内部的DT_RPATH
  2. 系统的环境变量 LD_LIBRARY_PATH
  3. 系统的动态库的缓存文件 /etc/ld.so.cache
  4. 存储动态库/静态库的系统目录 /lib/, /usr/lib

按照上述顺序查找需要的动态库,若找不到则会提示上述错误。

  1. 第一种解决方案 -程序运行时指定动态库的搜索路径

    # 指定搜索路径为 /Desktop/C++\ Code/temp/
    
    LD_LIBRARY_PATH=~/Desktop/C++\ Code/temp/ ./main
    

    Screenshot from 2023-08-18 15-00-23

  2. 第二种解决方案 - 将库路径添加到环境变量

    • 用户级别: .bashrc 只对当前用户有效
    • 系统级别: /etc/profile 对所有用户生效

    示例:

    # 在 ~/.bashrc中添加
    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:'/home/dbb/Desktop/C++ Code/temp'
    

    Screenshot from 2023-08-18 15-09-39

然后使之生效,可以通过重新打开终端,或者使用 . ~/.bashrcsource ~/.bashrc 来更新环境变量,使之生效。

系统级别的设置与上述例子类似,需要使用管理员权限操作sudo ,可自行尝试。

  1. 第三种解决方案 - 更新 /etc/ld.so.cache 文件
  • 将动态库的绝对路径添加(不包含库的名字)到 /etc/ld.so.conf 文件中

    # 用vim打开文件
    sudo vim /etc/ld.so.cache
    # 添加路径后退出
    
  • 更新 etc/ld.so.conf 中数据到 /etc/ld.so.cache

    sudo ldconfig
    
  1. 第四种解决方案 - 拷贝动态库文件到库目录或者 创建软链接

    # 拷贝到 /lib 或者 /usr/lib 中
    sudo cp ./libxxx.so /usr/lib
    
    # 创建软链接(推荐)
    sudo ln -s ./libxxx.so /usr/lib/libxxx.so
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值