静态和动态库

图书馆

库是一种可用于程序其他部分的服务集合。 通过使其更加模块化和可重用,而不是将每个组件都放在一个非常大的程序中,这有助于程序设计。 目的是要具有高凝聚力和低耦合度,这意味着要使相关功能朝着一个共同目标努力,并使它们尽可能独立,彼此之间的影响很小。

在C中,库是一个集合,它由可以重新实现的函数和数据类型组成。 我们经常将它们视为标准库,例如#include 的函数。 C程序通常分为几个源文件和头文件,我们需要能够将它们链接到操作系统提供的库中。 这些功能和过程中有很多反复使用,并且共享相似的例程。 因此,该库将它们打包,并允许我们重用这些通用功能和过程的相同版本。 可以通过利用这些库来运行程序。

静态库的工作

在C中,静态库是一组.o目标文件及其功能的容器,并设置为归档.a.lib文件。 尽管它们仍然是库中的不同文件,但是它们是静态链接的。 完成链接后,库中链接在一起的目标文件将无法更改,我们需要再次对其进行归档以更新库。 我们将不得不重建它。 静态库往往对较小的项目更好,因为它们将每个程序的所有通用功能链接在一起。 这有助于模块化和可重用性,因为所有代码都已与应用程序一起编译,而其他人只需要运行它即可。

静态库在编译阶段被利用,应用程序从静态库中获取代码,以供以后链接。 库中的代码将复制到应用中以进行组装和链接。

创建一个静态库

请看一下我以前的文章,关于如何创建静态库:

C静态库
库是一种可用于程序其他部分的服务集合。 这有助于… medium.com

动态库的工作原理

C语言中的另一种选择是使用动态(共享)库,该库通常是.so文件。 但是,根据操作系统的不同,还有许多其他扩展名,例如.dll.dylib 。 动态库的文件已构建,并与分别存储的几个目标文件动态链接在一起。 动态链接的优点是,在进行链接时可以进行更多配置,但要权衡拥有大量单独文件的权衡。 文件将被动态加载并链接到程序,而不是每次都重新构建。 因此,动态库通过让应用程序在运行时准确地引用该库(而不是编译时)来工作。 链接时,您需要同时具有库和应用程序。 对于共享相同功能且需要引用而不是复制库代码的大型项目,动态库通常更好。

创建一个动态库

首先,让我们将函数集中在一个目录中。 这将有助于在下一步中更轻松地对所有命令使用gcc命令。

现在,我们将在其上使用编译器gcc(GNU编译器集合)。

与静态库相似,-c标志编译或汇编源文件,但不链接。

我们还需要使用-fPIC(位置无关代码)标志。 可以在任何内存地址引用动态库,因为它们在进程之间共享,并且在两个进程中的相同地址处加载库可能不起作用。 代码必须与位置无关,否则每个进程仍将需要其自己的副本,类似于静态库。 因此,我们使用-fPIC标志来确保在编译期间,动态库仍可以位于任何地址位置并可以与PIC一起使用。

现在,我们可以使用-shared和-o标志创建动态库。 像静态库一样,我们需要为每个C文件获取.o对象文件,但是这次我们将很快将它们动态链接。 -shared标志将产生一个共享的对象,该对象可以链接到其他对象以形成可执行文件。

我们将使用nm命令仔细检查所有内容。 此命令将允许我们从目标文件中列出符号(类型和值)。 -D标志用于获取动态符号。

我们有目标文件,并且正确列出了符号。 现在,我们可以将我们的库以及gcc包括在内。

-o 将我们的可执行文件重命名为main。 -l-l.so的简化版本,在使用多个库归档文件时非常有用。 -L是返回库的路径; 我们使用 指定当前目录。 我们还可以使用-L和路径名搜索任何其他目录。

我们暂时无法运行此程序。 我们还需要使用ldd命令。

ldd命令显示每个程序或共享库所需的共享库依赖关系。 对于每个依赖项,ldd显示匹配的对象和加载该对象的内存地址。

我们可以为此使用LD_LIBRARY_PATH。 LD_LIBRARY_PATH是用冒号分隔的一组目录,其中在标准目录集之前先搜索库。 我们将将此路径添加到环境变量中。

现在我们已经准备好了,现在我们可以执行我们的程序,例如./len并获取主函数的输出,并调用动态库中的任何函数或进程。