静态库和动态库

静态库和动态库的区别

当你在做一道菜的时候,你需要用到一些材料来完成。静态库就好像是你事先准备好的所有材料,你把这些材料都放在自己的厨房里,需要的时候直接从自己的材料库里取出来使用。因为材料是你自己的,你可以随意修改它们,但是会占用更多的空间。

而动态库就好像你和你的邻居共享一个大材料库。你们可以一起使用这个材料库,节省了空间和资源。当你做菜的时候,你只需要从共享材料库中取出你需要的材料,用完之后就放回去供其他人使用。这样多个人可以共享同一份材料,减少了重复使用和浪费,但是你无法修改材料本身,只能使用它们。

所以,静态库是将所有代码从库文件复制到最终的可执行文件中,而动态库则是在程序运行时加载并链接库文件。静态库可以让程序独立运行,而动态库可以让多个程序共享同一份库文件。就像使用自己的全部材料和和邻居共享大材料库之间的差别一样。

静态库的特点

  • 编译(链接)时把静态库中相关代码复制到可执行文件中
  • 程序中已包含代码,运行时不再需要静态库
  • 程序运行时无需加载库,运行速度更快
  • 占用更多磁盘和内存空间
  • 静态库升级后,程序需要重新编译链接

创建静态库

1. 编写一个c语言文件(库文件的前身)

#include 

void hello()
{
	printf("hello world!\n");
	return;
}

2. 编译生成目标文件

gcc -c hello.c -Wall

3. 创建静态库

ar -rsv libhello.a hello.o

ar命令

在Linux操作系统中,ar命令是一个用于创建、修改或提取静态库(Archive)文件的工具。这个命令通常被用来处理和管理一组编译好的目标文件,它能将这些目标文件打包成一个静态库文件,以供其他程序使用

ar命令的基本语法是:

ar [选项]  [member_file...]

其中:

  • 选项:一些可选的参数,可以用来指定ar命令的具体行为,比如-c用于创建一个新的静态库文件,-r用于向现有的静态库文件中添加目标文件等。
  • :要操作的静态库文件的名称。
  • [member_file...]:可选参数,要添加或提取的目标文件列表,可以是一个或多个文件。

下面是一些常用的ar命令选项:

  • -r:将指定的目标文件添加到静态库中。如果库中已经存在同名的成员,它将被替换。

  • -c:创建一个新的静态库文件。如果库文件已经存在,则先将其清空。

  • -t:列出静态库文件中的所有成员文件的名称。

  • -d:从静态库文件中删除指定的成员文件。

  • -x:提取静态库文件中的指定成员文件。

  • -s:用于在静态库中创建索引表。索引表可以提高目标文件在静态库中的访问速度。

  • -v:用于在执行ar命令时显示详细的操作信息,可以查看每一步具体的处理过程,以及打印静态库中的成员文件信息。

4. 查看库中符号信息

nm libhello.a

运行结果:

hello.o:
0000000000000000 T hello
                 U puts

关于符号信息:
当运行nm xxx.a命令时,将显示类似以下的输出:

0000000000000010 T function1
0000000000000040 T function2
0000000000000090 T function3
00000000000000d0 t static_function
0000000000000100 A variable1
0000000000000104 B variable2

在这个例子中,xxx.a文件中包含了一些函数和变量的定义。

  • T表示函数,t表示静态函数,A表示绝对地址可寻址的全局变量,B表示非绝对地址可寻址的全局变量。
  • 函数和静态函数的名称分别是function1function2function3
  • static_function是一个静态函数,只在当前文件中可见。
  • variable1是一个全局变量,可以通过绝对地址进行访问。
  • variable2是一个全局变量,需要通过非绝对地址进行访问。

5. 链接静态库

编写 test.c 文件:

 #include 

void hello();

int main(int argc, char *argv[])
{
	hello();
	return 0;
}

编译并链接库文件:

gcc test.c -o test -L. lhello

注意:上面的 -L后面的 . 表示在当前目录中寻找链接文件,并且后面的 lhello 是 libhello 的库文件写法,什么时候写 libhello.a 什么时候写 lhello 要分清楚

6. 运行可执行文件

./test

运行结果:

hello world!

动态库的特点

  • 编译(链接)时仅记录用到哪个动态库中的哪个符号,不复制动态库中相关代码
  • 程序不包含库中代码,尺寸小
  • 多个程序可共享同一个库
  • 程序运行时需要加载库
  • 库升级方便,无需重新编译程序
  • 使用更加广泛

创建动态库

1. 编写 .c 文件(动态库文件的前身)

#include 

void bye()
{
	printf("bye!\n");
	return;
}

2. 编译生成目标文件

gcc -c -fPIC bey.c

关于 -fPIC:
gcc -fPIC 是 gcc 编译器的一个选项,用于生成位置独立代码(Position Independent Code)。位置独立代码是一种可以在内存中的任何位置加载和执行的机器代码,这对于动态链接库(Dynamic Linking)和共享库(Shared Libraries)等场景非常重要。使用 -fPIC 选项编译代码时,会生成与位置无关的目标文件,从而可以在不同的内存地址空间加载执行。这在某些情况下更加灵活和通用。

3. 创建共享(动态)库

gcc -shared -o libbey.so bey.o

4. 链接动态库

gcc test1.c -o test1 -L. -lbey

然后执行:

./test1

出现错误:

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

发生这个错误是因为

libbey.so 这个库是动态库,系统默认不会在当前目录找它,而是在 /usr/lib/lib 这两个目录下找,所以就有了直接的解决办法:将这个动态库拷贝到 /usr/lib/ 目录里,也就是
cp libbey.so /usr/lib/ ,但是这个办法不好,因为它搞得这个目录下会有各种垃圾,各种文件,所以又有了另一个办法:在 LD_LIBRARY_PATH 环境变量中添加库所在路径: export LD_LIBRARY_PATH=./

但是这样做又出现了一个问题:如果把可执行文件拷贝到另外一个地方然后执行就又会报原来的那个错误,也就是说这个方法只有在原来的那个目录里有用。

所以还得是通过 sudo vi ~/.bashrc 这个命令在 .bashrc 文件里添加上 export LD_LIBRARY_PATH=(.so库文件所在目录的完整路径) ,然后保存关闭文件后进行 source ~/.bashrc ,然后发现只要在某个目录下有这个要执行的可执行文件,那么就可以完美运行,不会再报错了
静态库和动态库_第1张图片

同时还有一个办法:就是向 /etc/ld.so.conf.d/*.conf 文件中添加动态库文件的路径,然后执行 ldconfig 刷新也可以。

source ~/.bashrc 的作用:运行 “source ~/.bashrc” 的命令可以重新加载当前用户的 Bash 配置文件 ~/.bashrc。当你修改了 ~/.bashrc 文件,希望立即应用这些更改而不需要重新启动 Bash 终端时,可以运行这个命令。它会读取 ~/.bashrc 文件中的配置,并使其立即生效。

5. 查看可执行文件使用了什么库

ldd 可执行文件

静态库和动态库_第2张图片

你可能感兴趣的:(c语言,linux)