10 分钟学会 Linux 动静态库


哥
道具阿明 2023-11-22 14:19:02 50234
分类专栏: 资讯

静态库和动态库比较

linux下有两种库,静态库和动态库,它们分别以 .a  和  .so  为后缀名,链接时指定静态库文件,编译器会将静态库的目标代码嵌入到可执行文件中,所以可执行文件的体积较大,共享库的代码是在程序运行时才载入内存的,而且可以实现多个程序共享,在编译过程中仅简单的引用,因此代码体积较小

另外,静态库是将目标代码嵌入到可执行程序,所以,后续库的升级需要重新编译可执行程序,而动态库则只需要更新库文件即可,不需要重新编译可执行程序,它的升级相对方便

下面分别介绍静态库和动态库的生成步骤和使用的方法

静态库

当前目录是 sotest,  b.h 和 b.cpp 位于 sotest/lib 目录下

// sotest/lib/b.h

#include <stdint.h>
#include <string>
#include <iostream>
using namespace std;


const std::string &UserName();
const std::string &UserPwd();

// sotest/lib/b.cpp
#include "b.h"
std::string g_username = "mytest";
std::string g_userpwd = "654321";
const std::string &UserName()
{
    return g_username;
}
const std::string &UserPwd()
{
    return g_userpwd;
}
  • 1、将源文件编译成目标文件 进入 sotest/lib 目录,执行下面的编译命令,编译完成之后,sotest/lib 目录下会生成一个 b.o 的目标文件
图片
  • 2、将目标文件打包成 静态库文件,以 .a 作为文件扩展名 进入 sotest/lib 目录,执行下面的命令,将上一步骤中的 b.o 目标文件打包成 libb.a 文件,libb.a 就是静态库文件
图片

关于 ar 命令见下方的说明

命令格式: ar rcs libxxx.a file1.o file2.o表示生成一个名为 libxxx.a 的静态库文件

r - 插入目标文件到库中

c - 创建库文件

s - 创建库文件的索引

  • 3、使用静态库 生成静态库以后,使用下面的测试代码进行测试
// sotest/btest.cpp
#include "lib/b.h"

int main(int argc, const char *argv[])
{
    cout << UserName() << ", "<< UserPwd() << endl;
    return 0;
}

使用下面的命令编译代码,编译成功之后执行 ./mytest , 结果如下

图片

动态库

还是以上面 sotest/lib 目录下的 b.h 和 b.cpp 以及 sotest/btest.cpp 为例来说明动态库的生成和使用方法

  • 1、将源文件编译成动态库

进入 sotest/lib 目录,执行下面的编译命令,编译完成之后,sotest/lib 目录下会生成一个 libb.so 的动态库文件

图片

编译说明:-fPIC 告诉编译器产生与位置无关代码,也就是说,产生的代码中,没有绝对地址,全部使用相对地址,所以代码可以被加载到内存的任意位置上,都可以正确的执行。这一点非常重要,也是动态库要求的

  • 2、使用动态库

还是使用上面的测试代码,进入 sotest 目录,使用下面的命令编译,并运行,结果如下

图片

命令说明:-L 表示指定动态库的路径,如果没有指定表示使用系统默认的搜索路径(一般是 /lib 或 /usr/lib ), -lb 表示引用 libb.so 库,引用的时候省略了前面的 lib 以及 .so 后缀

我们发现编译成功之后,直接运行可执行程序会报错:加载共享库出错,没有这个文件或者目录,这是由于动态链接器加载时找不到动态库

可能有同学会说,上面编译时,不是用 -L 指定了动态库的路径吗,为什么运行的时候还是提示找不到动态库呢?

这是其实是编译链接和运行加载的区别,上面编译时用 -L 指定的路径,仅指定了编译链接阶段的库文件搜索路径,它无法决定运行时加载库文件的搜索路径,要确保编译通过,只要在 -L 指定的路径中找到了库文件就可以了,但运行与具体的运行环境有关,在编译时无法确定运行时库的搜索路径

所以,运行时提示 libb.so 未找到,一般有下面几个原因

1、libb.so 库文件本身不存在,需要确保已生成该库文件

2、 库文件存在,但不在默认搜索路径中,需要将库文件的路径添加到环境变量 LD_LIBRARY_PATH 中,或者将库拷贝到标准路径 /lib 或 /usr/lib 下

3、库文件依赖其他库文件,需要确保递归地将所有依赖的库路径添加正确

4、 库文件存在且路径正确,但文件名不匹配,例如库文件名是 libb.so.1,而程序在找 libb.so

5、 权限问题,导致无法读取库文件

6、 库文件版本不兼容导致读取失败

逐条对比下就会发现,我们这里是由于没有设置动态库的路径,设置路径有下面几种方法

1、把 libb.so 拷贝到 /lib 或者 /usr/lib

执行 cp 命令把动态库拷贝到 /lib 目录下,具体操作如下图所示

图片

可以看出,把 libb.so 拷贝到 /lib 目录之后,再编译运行,输出就正常了

注意:动态库拷贝到 /lib 或 /usr/lib 目录以后,需要再执行 sudo ldconfig 命令刷新 /etc/ld.so.cache 缓存

2、路径添加到环境变量 LD_LIBRARY_PATH

执行 export 命令把动态库路径 /home/smb/wl/mytst/sotest/lib/ 加入到环境变量 LD_LIBRARY_PATH中,然后再运行,从下图可以看到,最后输出正确

图片

注意:使用 export 把库路径导入环境变量 LD_LIBRARY_PATH  的方法,只针对当前 SSH 连接有效,新打开一个 SSH 连接的时候,又需要重新设置,比较好的方式是把 环境变量 LD_LIBRARY_PATH 加入到 ~/.bashrc中,这样就对当前用户有效,如果把它加到  /etc/bashrc 中,就对所有用户有效

3、路径添加到 /etc/ld.so.conf 中

如下图,打开 /etc/ld.so.config ,写入动态库路径

图片

执行 sudo ldconfig 命令刷新 /etc/ld.so.cache  缓存,然后运行可执行程序,结果如下图

图片

在上面打开 /etc/ld.so.config的时候,我们发现第一行是: include ld.so.config.d/*.conf ,它表示我们也可以把动态库路径放到一个自定义的配置文件中,然后把这个配置文件拷贝到  /etc/ld.so.conf.d/ 目录中即可,可执行程序加载动态库的时候,会自动去自定义配置中目录中搜索, 把库目录写入到自定义配置 my.conf 中

图片

把自定义配置 my.conf 拷贝到 /etc/ld.so.conf.d/ 目录中,并使用 ldconfig 命令刷新缓存

图片

最后,运行可执行程序,可以看出,打印正确

如何查看程序链接的动态库

使用 ldd btest_so 命令可以查看可执行程序加载了哪些动态库以及每个动态库的路径

图片

如上图所示,红框的部分是自己编写的动态库以及动态库的路径,如果加载动态库失败,则会显示 "not found" 的字样,如下图

图片

网站声明:如果转载,请联系本站管理员。否则一切后果自行承担。

本文链接:https://www.xckfsq.com/news/show.html?id=28789
赞同 0
评论 0 条
道具阿明L0
粉丝 0 发表 15 + 关注 私信
上周热门
如何使用 StarRocks 管理和优化数据湖中的数据?  2944
【软件正版化】软件正版化工作要点  2863
统信UOS试玩黑神话:悟空  2823
信刻光盘安全隔离与信息交换系统  2717
镜舟科技与中启乘数科技达成战略合作,共筑数据服务新生态  1251
grub引导程序无法找到指定设备和分区  1217
华为全联接大会2024丨软通动力分论坛精彩议程抢先看!  163
点击报名 | 京东2025校招进校行程预告  162
2024海洋能源产业融合发展论坛暨博览会同期活动-海洋能源与数字化智能化论坛成功举办  160
华为纯血鸿蒙正式版9月底见!但Mate 70的内情还得接着挖...  157
本周热议
我的信创开放社区兼职赚钱历程 40
今天你签到了吗? 27
信创开放社区邀请他人注册的具体步骤如下 15
如何玩转信创开放社区—从小白进阶到专家 15
方德桌面操作系统 14
我有15积分有什么用? 13
用抖音玩法闯信创开放社区——用平台宣传企业产品服务 13
如何让你先人一步获得悬赏问题信息?(创作者必看) 12
2024中国信创产业发展大会暨中国信息科技创新与应用博览会 9
中央国家机关政府采购中心:应当将CPU、操作系统符合安全可靠测评要求纳入采购需求 8

加入交流群

请使用微信扫一扫!