Bootstrap

linux动态库与静态库

目录

引言

静态库

静态库的制作

 使用

意料之外的结果

总结1

更简单的使用第三方静态库

动态库(只需编译器指令)

-fPIC -c指令得到.o

-shared -o 得到.so

动静态库的联合发布

编译

执行

总结2

动静态库在链接阶段怎么使用的

总结3


引言

在Linux系统的编程领域,库(Library)扮演着至关重要的角色,它们为开发者提供了可重用的代码片段,从而提高开发效率,减少重复劳动。库分为两种类型:动态库(Dynamic Library)和静态库(Static Library)。这两种库在程序的构建和运行过程中发挥着不同的作用,各有其特点和适用场景。接下来,让我们深入探讨Linux环境下的动态库与静态库,了解它们的定义、区别以及在实际开发中的应用,从而为高效编程奠定坚实的基础。

本文将从:库的制作者、库的使用者与库的加载三个角度去解读库文件

静态库

将我们提供的方法给别人用有如下方式:1.将源文件直接暴露 2.将源代码打包成库 + .h的形式

显然第二种方式是更好的,这样可以保护源文件的安全性,也可以提供更便捷的使用方式

流程:

静态库的制作

写好源文件与头文件。第二步是库的打包

建立一个lib变量

.a依赖.o        .o依赖.cpp

cr表示创建与替换(不存在创建,存在就替换)

当然,库写好了需要发布

放在写好的文件中。

当别人想用它的时候,只需要获得lib文件就可以。

 使用

由于我们打开的.cpp文件与lib在同一目录下,所以直接lib开头就可以。

但是这种书写方式才是我们更喜欢的书写。

在我们编译进行头文件的展开时,前提是先找到头文件。默认路径:系统默认目录/usr/include

虽然我们包含了头文件,但是发现编译失败,1.找不到头文件(这个math.h头文件能找到的原因是:优先去本地查找,本地找不到用官方库) 2.找不到对应的函数

解决:

1.-I指令找到头文件(I就是iclude)

2.-L指令找到库的目录(L就是lib)

这是链接时报错

3. -l点名哪个库(l就是link)

点名库时,需要去掉lib开头,.a结尾,紧连在-l指令后

这样就得到了我们需要的结果。

意料之外的结果

myerrno并没有得到想要的结果,这是因为形参的实例化是从右到左进行的。

所以尽量不要在打印语句中进行结果的计算。

总结1

1.g++编译的时候,查找库和头文件只会去默认的路径中查找

在Ubuntu系统中,C++的库文件(也称为共享库或动态链接库)通常位于以下目录之一

/usr/lib/x86_64-linux-gnu/ (对于64位系统)

使用第三方库,必须得

-I包含头文件路径 

-L包含库文件路径(不含库文件本身)

-l包含库文件(并去掉多余的格式)

2.上述的编译默认是进行动态链接,但是由于只存在静态库,所以只能进行静态链接

更简单的使用第三方静态库

1.可以将静态库的头文件与库文件安装(只需要安装头、库文件即可)

库文件:/usr/lib/一般在这个里面

头文件:/usr/include/一般的话头文件是在这个地方

对于C++的第三方库一般来说,需要.a文件安装到/usr/lib,把.h安装到/usr/include

这其实就是安装

就算是我们安装好第三方库之后,虽然可以省略-I -L指令,但是只要是第三方库,就得用-l点名需要链接哪个库

2.建立软链接

软链接就相当于是快捷方式,将头文件的目录(不包含头文件)安装到本地

这样使用快捷方式 + 头文件就可以完成查找

其实系统在查找的时候,如果不指明 -I选项,那么会默认进行 默认路径(如:/usr/include) + 头文件的方式进行查找

这样会自动替换为/usr/include/myinc/math.h,其中/usr/include/myinc/会被替换为原来的地址

库文件建立软链接,库文件建立软链接的时候,需要将具体到某个库进行链接。

这样我们-lmymath的时候,才能去默认路径/lib64查找libmymath.a

但是不推荐软链接,不如直接进行安装

动态库(只需编译器指令)

静态库的后缀是.a,动态库的后缀是.so(shared o)

为了得到动态库,同样是先得到.o,然后得到.so

-fPIC -c指令得到.o

当然,我们可以-o指定名称,否则就是默认的名称 + .o

-shared -o 得到.so

-o后面跟上库的名称

将各个.o文件打包为.so文件

动静态库的联合发布

为了一次性发布,可以建立伪目标all,依赖两个库。

编译

使用动态库,仍然需要-I -L -l指令

在我们举出的例子中

g++编译时,如果2个头文件不在相同的目录下,需要写2个-I……

执行

当执行的时候,发现找不到共享库,libDY.so发现找不到。

原因:编译阶段,告诉了编译器库在哪里。但是动态库在执行阶段也需要知道在哪里(加载器)

方法一:库安装到路径

这样就可以直接找到动态库的位置(不需要重新编译,因为编译器的工作已经完成,编译器与加载器是分开的)

这样就可以直接执行了。

并且安装到路径也是最常用的做法。

方法二:软链接

同样的,让默认路径下/lib64/

不需要重新编译(编译一次就可以)

方法三:环境变量

load  library path

这个是默认没有安装的,这个环境变量是专门给用户提供用户自定义的库路径的(加载器使用)

环境变量是shell启动时配置的,我们也可以通过编写shell脚本,将环境变量添加到这里面,这样就不是内存级的了。

环境变量是通过这个文件导入的

方法四:修改配置文件

这里面存放着一些配置文件

这些配置文件内部就是一些路径,加载器加载程序时,如果需要动态库,那么就去会这些路径内查找。

但是需要注意的是ubuntu禁止root直接登录,而只有root才有权限去管理(root不受权限的限制)。

用root登录之后,只需要

1.新建一个.conf文件

2.把动态库的路径放进去

3.重新加载一下配置(config)

这样就可以看到动态库的路径了(永久有效)

总结2

动静态库在链接阶段怎么使用的

在软件开发中,链接器是编译过程的一个阶段,它将一个或多个编译后的目标文件(.o或.obj文件)与所需的库文件相连接,生成可执行文件。动静态库在链接阶段的使用方式有所不同:

静态库(.a或.lib文件)

静态库在链接阶段的使用通常遵循以下步骤:

识别:链接器需要知道要链接哪些静态库。这通常通过编译器命令行参数(如gcc的-l和-L选项)指定。

解析符号:当链接器处理目标文件时,它会寻找未定义的符号(函数和全局变量)。链接器会检查静态库中是否有这些符号的定义。

包含:如果静态库中包含了所需的符号定义,链接器会将这些符号的实现从库中复制到最终的可执行文件中。这意味着每个使用静态库的可执行文件都有一份库代码的副本。

重定位:链接器会对复制到可执行文件中的代码进行重定位,确保地址引用正确。

生成:最后,链接器生成完整的、独立运行的可执行文件。

动态库(.so或.dll文件)

动态库在链接阶段的使用通常遵循以下步骤:

识别:和静态库一样,链接器需要知道要链接哪些动态库,这通常也是通过编译器命令行参数指定的。

解析符号:链接器检查目标文件中的未定义符号,并查找动态库中的符号定义。

记录引用:与静态库不同,链接器不会将动态库中的代码复制到可执行文件中。相反,它会记录下这些符号在哪个动态库中定义,并在生成的可执行文件的动态链接表中创建相应的条目。

延迟绑定:动态链接的符号实际上是在程序运行时(而不是链接时)解析的。这个过程称为动态加载,由操作系统的动态链接器(如Linux的ld-linux.so或Windows的ntdll.dll)在程序启动时进行。

生成:链接器生成可执行文件,这个文件在运行时需要动态库的支持。

总结3

静态库:在链接阶段,库的代码被直接包含进最终的可执行文件中。

动态库:在链接阶段,只记录对动态库的引用,实际链接发生在程序运行时。

使用哪种库取决于多种因素,包括程序的需求、部署环境、以及是否希望减小可执行文件的大小等。静态库会增加可执行文件的大小,但不需要担心运行时库的版本问题;动态库可以减少可执行文件的大小,并允许库的共享和更新,但可能带来运行时依赖的问题。

;