Linux下静态库和动态库(讲解 | 制作 | 发布)

it2025-04-28  11

Linux下de静态库和动态库

这篇文章会介绍: 1.库的作用(库的运用情景) 2.什么是库 3.静态库和动态库 4.库的制作和发布 5.库的使用(用户) 6.其他相关

1.库的作用

相信大家看了很多文章关于库的介绍,以及制作它的方法,但是大家有可能还不清楚为什么要制作库以及什么情况下要制作库。 一般来说,如果有人需要使用你写的项目代码,在不告知源码的情况下他仍然可以使用你的项目代码,这时你就可以把需要使用到的一些项目代码封装在一个库里,然后提供一些接口就可以供他使用了。具体怎么发布和使用后面还会介绍。

linux系统有几个重要的目录存放系统的函数库,如/lib、/usr/lib

2.什么是"库"

从本质上说,"库"是一种可执行代码的二进制形式,可以被操作系统载入内存执行。

我们知道程序的执行会经过预处理、编译、汇编、链接四个步骤,而"库"里面存放的就是汇编后形成的目标文件(即.o文件), 它是不能直接运行的。这里我的理解是"库"就是一堆.o文件的集合,他们在程序链接的时候根据用户需求加入进来进而形成 可执行文件。只不过加入的方式有两种:静态加载和动态加载

下次再讲讲程序编译链接的详细过程吧 ^ - ^

3.静态库和动态库

3.1静态函数库

这类库的名字一般是" libxxx.a ",其中xxx是库的名字,用户可以自己定义。利用静态函数库编译成的文件较大,因为静态库在编译过程中会被整合进目标代码中。(理解:并不是整个库都被整合进目标代码中了,而是使用到了的函数代码会被整合进最终的可执行程序中,该程序在被执行时这些代码就会被装入到该进程的虚拟地址空间中(代码段) ,所以编译后即使删除了静态库对程序的运行也不会有影响 )

"优点":编译后的程序无需外部的函数库支持就能直接运行,发布程序的时候,不需要再提供对应的库。同时加载库的速度快 "缺点":编译生成的文件体积较大。再一个,如果静态库改变了,程序就必须重新编译。

可以理解为使用静态库编译时链接的最小单位是" .o “文件,即用户程序里使用到了的函数,静态库里的对应的” .o "文件就会被整合进最终的可执行文件中。

3.2动态函数库

动态库又称为共享库,这类库的名字一般是" libxxx.so ",其中xxx是库的名字,用户可以自己定义。相对于静态库,动态库在编译过程中不会被整合进目标代码中,而是程序执行到相关函数才调用该库里的函数,因此利用动态函数库编译成的文件较小。

"优点":编译生成的文件体积较小,节约磁盘空间。动态库的改变并不影响程序,更新升级也比较方便。 而如果有多个应用程序要使用同一函数库,动态库就非常适合。 "缺点":发布程序的时候,需要将动态库提供给用户。相对于静态库而言,加载速度较慢。

实际上,动态链接器的本质也是一个库。

4.库的制作和发布

4.1静态库的制作

①准备相应的操作的" .c “文件,然后将” .c "文件转化至汇编文件 " .o "文件 (gcc -c xxx.c -o xxx.o)

注:如果有很多" .c "文件,可以使用命令:gcc -c *.c一键生成所有对应的" .o "文件。

②创建静态库:执行命令 ar -cr libxxx.a xxx.o(xxx分别为用户自定义的库名和上一步生成的汇编文件名)

关于" ar "命令: ar命令可以用来创建、修改库,也可以从库中提出单个模块。ar是archiver的缩写。 -r:将文件插入库文件中,如果已经存在会直接替换。 -t:显示库中所包含的.o 文件。 -c:表示create,创建。 注:同样,如果有多个" .o "文件,直接使用命令: ar -cr libxxx.a *.o一键生成对应的库文件。

此时,静态库就创建好了

4.2动态库的制作

①准备相应的操作的" .c “文件,然后将” .c "文件转化至汇编文件 " .o "文件 (gcc -fPIC -c xxx.c -o xxx.o)

注:如果有很多" .c "文件,可以使用命令:gcc -fPIC -c *.c一键生成所有对应的" .o "文件。

②创建动态库:执行命令 gcc -shared -o libxxx.so xxx.o(xxx分别为用户自定义的库名和上一步生成的汇编文件名)

注:同样,当有多个" .o "文件,直接使用命令: gcc -shared -o libxxx.so *.o一键生成对应的库文件。

上面两步其实也可以合并成一步:gcc -fPIC -shared -o libxxx.so xxx.c

-PIC(Position-Independent Code):告诉编译器产生于位置无关的代码,产生的代码中没有绝对地址,全部使用 相对地址,故而代码可以被加载到内存的任意位置,都可以正确的执行。这正符合共享库所要求的,因为共享库被 加载时,在内存的位置是不固定的。 -shared:表示动态库(共享库)

此时,动态库就制作好了

4.3库的发布

发布库的时候只需提供库和对应的头文件(即函数接口),如果只发布函数库,用户不知道怎么使用,头文件中就可以定义一些函数申明和用法介绍等等之类的。

5.库的使用(用户)

5.1静态库的使用

①用户使用静态库编译main.c 程序(gcc -o main main.c -L. -lxxx)

-L. ---->告知gcc链接库的存放路径," . "表示当前目录,即创建好的库存放在当前目录下,这个路径取决于你的库放在 哪里。如果你制作的库放在/lib、/usr/lib等目录下,可以不需要该选项,因为这些是gcc的默认搜索路径。 -I. ---->告知gcc用户自定义的头文件的存放路径," . "表示当前路径,这个路径同样取决于你之前创建的头文件放在 哪里。如果你制作的头文件放在/include、/usr/include等目录下,可以不需要该选项,因为这些是gcc的默认搜索路径。 -lxxx ---->xxx即你创建的库的名称(仅仅是名称)

②此时,使用静态库编译就完成了,可以直接执行生成的可执行文件main(命令是 ./main)

5.2动态库的使用

①编译main.c 程序(gcc -o main main.c -L. -lxxx) ②执行./main 这里会出错:提示找不到运行时依赖的动态库

前面提到过:gcc默认只会到/lib、/usr/lib等目录去搜索库,虽然这里我们指定了搜索路径,但是链接时需要借助动态 链接器的帮助,它找不到。。。如果我们把制作的动态库放在默认目录下,执行./main就不会出错。但总觉得这样不好, 毕竟那是系统目录,不想去修改它,以免引起一些不必要的麻烦。 ----->解决办法: 1.将动态库放在系统的库目录下(\lib) {不建议使用} 2.设置LD_LIBRARY_PATH环境变量,即先执行命令:export LD_LIBRARY_PATH=".""."表示当前目录,你的动态库放在哪里就填什么路径,然后再执行./main,就可以了。)

注意: ① LD_LIBRARY_PATH是一个环境变量,它的作用是告诉链接器ld 库的搜索路径,而且LD_LIBRARY_PATH指定的搜索路径优先于/lib等默认搜索路径目录 ② export LD_LIBRARY_PATH = "."是临时设置环境变量,重启或打开新的Shell,一切设置将不复存在 永久性添加方法: 1.在家目录的 .bashrc文件中添加export LD_LIBRARY_PATH = 动态库目录的绝对路径,然后需要重启终端,才能生效 2.将export LD_LIBRARY_PATH = 绝对路径 写入系统文件中,(/etc/ld.so.conf) 添加完后,保存退出,更新(sudo ldconfig -v)让环境变量生效。

6.其他相关

6.1如何判断一个程序有没有链接动态库?

1. file命令:file是用来判断文件类型的。 2. ldd命令:查看可执行程序所依赖的动态库。

ldd命令下所显示的内容:可以看到可执行文件test依赖libdong.so(自己创建的),libc.so.6(标准C库)等动态库,而最后一行的ld -linux x86 -64.so.2则是上面所说的动态链接器,他负责把他前面的一些动态库加载进来

6.2 -static选项

gcc编译都是时默认都是动态链接,如果要指定优先连接静态库,需要指定 -static选项。

例如:gcc -o main main.c -L. -static -ltest 这样,如果ltest.so和ltest.a同时存在的话,会连接ltest.a

6.3静态动态混合连接

默认情况下,GCC/G++连接时优先连接动态库,若没有动态库,连接相应的静态库。同时,GCC/G++也提供相应的链接选项:-Wl,-Bstatic和-Wl,-Bdynamic -Wl,-Bstatic后用于链接静态库 -Wl,-Bdynamic后用于链接动态库

例如:-Wl,-Bstatic -ljing -Wl -Bdynamic -ldong

最后,有不对的地方欢迎大家在评论区指出,谢谢大家!!^ - ^

最新回复(0)