C++静态库与动态库

原文链接

1 前言 从源文件到可执行文件

在讨论静态和动态库之前,我们先回顾一下从源文件到生成可执行文件的过程。编译器需要4个步骤(预处理器、编译器、汇编、链接器)将源代码转换为可执行文件:C++静态库与动态库_第1张图片
在gcc中,直接从main.c到main
gcc main.c -o main
处理器: 预处理器步骤删除文件中的所有注释,包括并扩展所有头文件,并用值替换所有宏。编译器: 编译然后获取预处理的代码并将其转换为汇编代码。
汇编代码: 汇编代码是一种人类可读的机器代码表示低级语言。汇编程序将汇编代码翻译成机器代码。
链接器: 链接步骤获取多个文件的所有目标代码或机器代码,并将它们链接到一个可执行文件中。
请注意,上图中的库实际上就是我们今天要讨论的内容。
编译 c 程序时,编译器生成目标代码(目标代码是尚未链接到完整程序的机器代码的一部分)。在生成目标代码之后,编译器还调用链接器。链接器的主要任务之一是编写库函数的代码(如 printf ()、 scanf ()、 sqrt ()…等)可用于您的程序。链接器可以通过两种方式完成这项任务,一种是将库函数的代码复制到目标代码(静态链接) ,另一种是进行一些安排,使库函数的完整代码不被复制,而是在运行时可用(动态链接)。

2 静态库(linux .a,windows .lib)

可以把静态库看作是位于 c 文件中的特定函数的集合,它们被编译成一个大文件,您可以随身携带并与任何文件一起使用,以解决特定的任务。静态库是文件编译成可执行文件时链接在一起的目标文件的集合。
优点:由于库代码是在编译时连接的,因此最终的可执行文件在运行时不依赖库,即不需要额外的运行时加载成本。静态库的一个主要优势是速度,即使现在也是首选。在静态库中不会有动态的符号查询。即使在今天,许多生产线软件仍然使用静态库。
缺点:创建了更大的二进制文件,需要更多的磁盘空间和主存。对于静态库中的任何变化(升级),都要重新编译主程序。

示例

编译库文件
gcc -c libmylib.c -o libmylib.o

创建动态库
ar rcs libmylib.a libmylib.o

编译驱动程序
gcc -c driver.c -o driver.o

将已编译的驱动程序链接到静态库。-L传递了静态库的路径,-l传递了库名(lib* 中的 *)。
gcc -o driver driver.o -L. -lmylib

或者直接从源文件
gcc driver.c -L. -lmylib -o driver

运行驱动程序
./driver

3 动态库(linux .so,windows .dll)

优点:显著减小可执行程序的大小;如果更新之后认为与原始版本二进制兼容,则无需重新编译代码
缺点:与静态库相比,执行时间较慢;入伏哦库更改而未将库重新编译到内存中,则可能存在兼容性问题;当一个库的新版本与旧版本不兼容时,需要进行更改。

示例

编译器选项:

  • -Wall 显示警告
  • -fPIC 用于输出位置无关的代码,这是共享库所需要的特性
  • -shared生成一个共享对象,然后将其与其他对象链接起来,形成一个可执行文件
  • -Wl,options 将选项传递给链接器 本例中传递的是:
    “-soname libctest.so.1”.The name passed with the “-o” option is passed to gcc.

编译库文件,创建目标代码
gcc -Wall -fPIC -c *.c

创建动态库
gcc -shared -Wl,-soname,libctest.so.1 -o libctest.so.1.0 *.o

创建链接默认版本

ln -sf /opt/lib/libctest.so.1.0 /opt/lib/libctest.so.1
ln -sf /opt/lib/libctest.so.1.0 /opt/lib/libctest.so

使用共享对象库编译主程序和链接
gcc -Wall -L/opt/lib prog.c -lctest -o prog

其中库的名称是 libctest.so。(这就是为什么您必须创建符号链接,否则您将得到错误“/usr/bin/ld: can not find-lctest”)
但是,如果然后运行可执行文件,它将无法工作,因为在执行可执行文件之前需要执行一个步骤。你需要设置你的 LD_LIBRARY_PATH 环境变量,这样运行时链接器就可以找到并加载你的 .so 文件。
例如export LD_LIBRARY_PATH=/opt/lib:$LD_LIBRARY_PATH
如果你的 .so 在 /opt/lib

动态库与静态库的区别

静态库在编译时连接,而动态链接在运行时发生。
对于静态库,每个进程都有自己的代码和数据副本。与动态库的情况一样,它只是共享代码,数据是特定于每个进程的。

参考:
https://www.cnblogs.com/skynet/p/3372855.html
https://www.geeksforgeeks.org/static-vs-dynamic-libraries/
https://medium.com/@nickteixeira/how-to-explain-to-my-wife-what-i-do-gcc-main-c-dc5d48a96d24
https://medium.com/@nickteixeira/what-are-static-libraries-in-c-and-why-do-software-engineers-use-them-eb7022d89135
https://medium.com/@nickteixeira/shared-dynamic-libraries-vs-static-libraries-differences-in-performance-2716f5b3c826
http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html
http://www.yolinux.com/TUTORIALS/LibraryArchives-StaticAndDynamic.html

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