linux 当前目录动态库加载找不到文件,静态库和动态库,为什么找不到动态库.so文件...

本文详细介绍了静态库和动态库的概念及它们的区别,包括如何创建和使用这两种类型的库文件。此外,还深入探讨了在Linux环境下动态链接过程中遇到的问题及其解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

静态库和动态库,为什么找不到动态库.so文件

静态库和动态库,为什么找不到动态库.so文件

什么是库?

所谓“库”,就是稳定成熟的可以复用的代码;库从本质上来说是一种可执行代码的二进制形式,可以被操作系统载入内存执行。

库有两种:静态库(.a(linux)、.lib(windows))和动态库(.so(linux)、.dll(windows))。

所谓静态、动态是指链接,可以看下编译链接的过程:

fabedbece69590abd87d9a5a8617645e.png

库与可执行文件区别:

库文件无法直接执行,从生产库的源码中可以查看出,源码是没有main函数,都是一些函数模块的定义和实现,由于没有主入口,所以无法直接运行库。

静态库是什么?

静态库实际就是一些目标文件(一般以.o结尾)的集合,静态库一般以.a结尾,只用于链接生成可执行文件阶段。这里注意区分下linux环境下是以.a结尾的,而windows环境下是以.lib结尾的(我这里就使用linux版本进行,文章就主要以linux环境进行撰写)

在链接步骤中,连接器将从静态库文件(.a文件)取得所需的代码,复制到生成的可执行文件中(生成的文件会比较大)。这种库称为静态库;

特点:

可执行文件中包含了库代码的一份完整拷贝

缺点:

缺点就是被多次使用就会有多份冗余拷贝。

静态库对程序的更新、部署和发布也会带来麻烦。如果静态库libxxx.lib更新了,所以使用它的应用程序都需要重新编译、发布给用户;

静态库生成

创建静态库的步骤:

写源文件,通过 g++ -c xxx.cpp 生成目标文件。

用 ar 归档目标文件,生成静态库。(ar cr libhello.a hello.o)

使用静态库中函数的头文件。

使用静态库时,在源码中包含对应的头文件,链接生成的静态库。

生成静态库案例

文件:aLibTest.h aLibTest.cpp main.cpp

[email protected]:~/20201019# ls

aLibTest.cpp aLibTest.h main.cpp

aLibTest.h内容:

#include 

using namespace std;

int getParam();

aLibTest.cpp内容:

#include "aLibTest.h"

int getParam()

{

int iparam = 10;

iparam++;

return iparam;

}

制作动态库:

先编译生成.o链接文件

[email protected]:~/20201019# g++ aLibTest.cpp -c

[email protected]:~/20201019# ls

aLibTest.cpp aLibTest.h aLibTest.o main.cpp

归档,生成静态库

[email protected]:~/20201019# ar cr libaLibTest.a aLibTest.o

[email protected]:~/20201019# ls

aLibTest.cpp aLibTest.h aLibTest.o libaLibTest.a main.cpp

main函数调用 main.cpp

#include "aLibTest.h"

int main()

{

int res = getParam();

cout<

return 0;

}

链接

[email protected]:~/20201019# g++ main.cpp -L. -laLibTest

[email protected]:~/20201019# ./a.out

res:11

7b1e629ac533803ab17e1a52b05abf3c.png

通过使用makefile做到自动化

#注意makefile的编写规范,构建规则开头必须是tab,不能是空格,也就是下面的格式不能修改

CXX=g++

build : libaLibTest.a

libaLibTest.a : aLibTest.o

ar cr [email protected] aLibTest.o

aLibTest.o : aLibTest.cpp

$(CXX) -c aLibTest.cpp

target: aLibTest

aLibTest: main.cpp

$(CXX) main.cpp -o [email protected] -L. -laLibTest

使用make build会构建出libaLibTest.a,使用make target生成可执行文件;

1fc99e30d7dd7b812daaffd401f24b88.png

上面看到生成libaLibTest.a大小为2.7k,而a.out为18k。

动态库是什么?

Linux下动态库文件的文件名称如 libxxx.so,其中so是 Shared Object 的缩写,即可以共享的目标文件。

动态库在链接阶段没有被复制到程序中,而是程序在运行时由系统动态加载到内存中供程序调用。

特点:

使用动态库的优点是系统只需载入一次动态库,不同的程序可以得到内存中相同的动态库的副本

优点:

节省了内存

动态库生成

创建动态库的步骤:

编写源文件。

将一个或几个源文件编译链接,生成共享库。

通过 -L -lxxx 的gcc选项链接生成的libxxx.so。

把libxxx.so放入链接库的标准路径,或指定 LD_LIBRARY_PATH,才能运行链接了libxxx.so的程序。

生成动态库案例

还是上面的代码,这里直接使用上面的代码进行动态库的生成和使用

制作动态库:

先编译生成.o链接文件 -fPIC 创建与地址无关的编译程序(pic,position independent code),是为了能够在多个应用程序间共享。

[email protected]:~/20201019/sharedtest# g++ -fPIC -c aLibTest.cpp

[email protected]:~/20201019/sharedtest# ls

aLibTest.cpp aLibTest.h aLibTest.o main.cpp

生成动态库(链接器选项-shared)

[email protected]:~/20201019/sharedtest# g++ -shared -o libaLibTest.so aLibTest.o

[email protected]:~/20201019/sharedtest# ls

aLibTest.cpp aLibTest.h aLibTest.o libaLibTest.so main.cpp

其实可以一步就生成:

g++ -fPIC -shared -o libaLibTest.so aLibTest.cpp

be77c9ef5bd47cd78c708d099e5c1405.png

main函数调用

[email protected]:~/20201019/sharedtest# g++ main.cpp -L. -o main -laLibTest

[email protected]:~/20201019/sharedtest# ls

aLibTest.cpp aLibTest.h aLibTest.o libaLibTest.so main main.cpp

[email protected]:~/20201019/sharedtest# ./main

./main: error while loading shared libraries: libaLibTest.so: cannot open shared object file: No such file or directory

我们发现,明明我们的动态库就在当前目录下,为什么会找不到呢? 当系统加载可执行代码时候,能够知道其所依赖的库的名字,但是还需要知道绝对路径。此时就需要系统动态载入器(dynamic linker/loader)。 对于elf格式的可执行程序,是由ld-linux.so*来完成的,它先后搜索elf文件的DT_RPATH段(不可控) -->  环境变量LD_LIBRARY_PATH --> /etc/ld.so.cache文件列表 --> /lib/和/usr/lib 目录找到库文件后载入内存。 如何让系统能够找到它: 如果安装在/lib或者/usr/lib下,那么ld默认能够找到,无需其他操作。 如果安装在其他目录,需要将其添加到/etc/ld.so.cache文件中,步骤如下: 编辑/etc/ld.so.conf文件,加入库文件所在目录的路径 运行ldconfig ,该命令会重建/etc/ld.so.cache文件

我们直接将我们生成的文件拷贝至/usr/lib下,再次运行:

[email protected]:~/20201019/sharedtest# cp libaLibTest.so /usr/lib

[email protected]:~/20201019/sharedtest# ./main

res:11

当然,加载动态库不止这一种方式,我们代码中往往使用的是一些函数,具体会出一篇文章,先做个插曲~

小插曲(常用参数)

-l参数就是用来指定程序要链接的库,-l参数紧接着就是库名,拿数学库来说,它的库名是m,它的库文件名是libm.so,很容易看出,把库文件名的头lib和尾.so去掉就是库名了。

-L参数跟着的是库文件所在的目录名。比如我们把libtest.so放在/tmp目录下,那链接参数就是-L/tmp -ltest另外,大部分libxxxx.so只是一个链接;

-include用来包含头文件,但一般情况下包含头文件都在源码里用#include xxxxxx实现,-include参数很少用。-I参数是用来指定头文件目录,/usr/include目录一般是不用指定的,gcc知道去哪里找,但是如果头文件不在/usr/include里我们就要用-I参数指定了,比如头文件放在/myinclude目录里,那编译命令行就要加上-I/myinclude参数了,如果不加你会得到一个"xxxx.h: No such file or directory"的错误。-I参数可以用相对路径,比如头文件在当前目录,可以用-I.来指定;

静态库和动态库,为什么找不到动态库.so文件相关教程

2020-10-25

2020-10-25 1.为什么在dos窗口输入javac -version显示’javac’ 不是内部或外部命令,也不是可运行的程序或批处理文件。 而输入java -version显示java版本成功 原因:来看看我们path中的环境变量中有这么一行配置 可以复制此路径查看里面有什么 这是因为我们

帆软实现动态背景

帆软实现动态背景 帆软实现动态星空背景的过程 帆软实现动态背景主要依靠以下三段代码。 需要对于body组块设置三个条件属性。 设置成初始化后。 条件1 // An highlighted blockFR.HtmlLoader.loadingEffect=function(){} 条件2 // An highlighted block$(body

项目【QT5.13频谱分析软件】(四)——数据动态波形显示

项目【QT5.13频谱分析软件】(四)——数据动态波形显示 当数据读取完毕后,我们要将数据描绘成波形并动态的显示出来。 线程读取完Excel表格数据后,发送request信号,触发槽函数showData(),此槽函数首先在chart上初始化前1024个点。 connect(m_thread,threa

静态内部类单例模式实现雪花算法

静态内部类单例模式实现雪花算法 静态内部类单例模式实现雪花算法 这是我网上看到的一篇很好的blog,在此记录一下用于学习(仅用于学习) 源blog地址:https://www.cnblogs.com/qdhxhz/p/11372658.html 在生成表主键ID时,我们可以考虑 主键自增 或者 UUID ,

动态规划——状态压缩DP——蒙德里安的梦想

动态规划——状态压缩DP——蒙德里安的梦想 #includebits/stdc++.husing namespace std;typedef long long LL;const int N = 12 , M = 1 N;//这里使用位运算,表示2的N次方 int n , m;//f[i][j]表示 i-1列的方案数已经确定,从i-1列伸出,并且第i列的状态是j

【Matlab实现】动态时间规划调整算法(DTW算法)——计算两个序

【Matlab实现】动态时间规划调整算法(DTW算法)——计算两个序列之间的相似度 【Matlab实现】动态时间规划调整算法(DTW算法)——计算两个序列之间的相似度 概述 算法原理与步骤 算法的实现 概述 DTW (Dynamic time warping)算法是可以度量两个独立时间序

02-链表

02-链表 链表 1.定义 链表是一种线性的动态数据结构,与动态数组,栈,队列的“动态”不同(这三种数据结构的底层都是静态数组,依托resize解决容量问题),链表是真正意义上的动态数据结构 链表与数组相比,失去了随机访问的能力,但却拥有动态的优点(不需

涉及简历

涉及简历 反射 反射概念:反射就是动态调用一个类/一个对象的成员变量/属性、方法、构造器的功能 定义测试的User:看到原类的构造器、成员属性、方法,想着怎么使用反射生成 package reflect;public class User { private int id=1; private String name=张三

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值