关于两个图书馆的故事

不是关于您的典型库的故事,而是关于编程中的库的故事。 在这种情况下,库是程序可以使用的预编译模块的集合-无论是函数,变量,类还是数据结构。 通常,库对于存储经常使用的模块很有用,因此当程序运行所述模块时,并非每个程序都必须显式链接某个模块。

有两种类型的库,静态库和动态库。 在深入探讨关键区别之前,对您来说,重要的是要了解程序(在这种情况下为C程序)的编译方式。 编译分为四个步骤,其中最后一个阶段是链接器。 链接器采用在上一步中创建的程序的目标代码以及该函数使用的函数的所有其他目标文件,并创建一个可执行文件。 让我们看一下包含静态库的程序和包含动态库的程序的链接阶段的两个示例。

示例—静态库

您创建了一个程序calculation_static.c ,该程序运行函数get_product(int a, int b) 。 编译后的汇编程序短语之后,您的函数现在将转换为目标代码。 作为链接阶段的第一步,链接器将使用calculation_static.c的目标代码,并使用该目标代码生成可执行文件。 但是等等,链接器将在所有库中搜索get_product(int a, int b)函数。 链接器找到它后,它将复制get_product(int a, int b)的目标代码,并将其粘贴到get_product(int a, int b)get_product(int a, int b)创建的可执行文件中。

优点:静态链接的最大特点是可执行程序,如果它是第一次运行,它将始终运行。 该代码不会被破坏。

缺点—例如,如果有多个函数,假设我们的calculation_static.c包含100个函数,而我们包含另一个C程序calculation2_static.c ,其中包含200个函数,那么您需要在其中包含所有300个函数的目标代码。您的可执行文件。

假设您是通过静态链接生成可执行文件的,而用户则将这个可执行文件用于其程序。 几个月过去了,包含get_product(int a, int b)函数的库的创建者完全更改了该函数。 这就是问题所在,用户几个月前使用的可执行文件具有旧的get_product(int a, int b)函数,而不是新版本。 用户将不得不使用该库再次编译原始C程序,并获取该可执行文件以更新其版本。 本质上,每次更新库时,您都必须重新编译程序。

如何创建-要创建静态库,最基本的工具是名为“ ar”(档案)的程序。 该程序可以修改静态库中的目标文件,列出目标文件的名称以及其他各种内容。

  ar rc libraryName.a filename.o filename2.o filename3.o 

此命令创建一个名为libraryName的库,并放置file1.o,file2.o和file3.o目标文件的副本。 如果libraryName已经存在,则仅将对象文件添加到其中,如果存在更新版本,则将其替换。 “ r”标志告诉库用较新的对象替换较旧的对象文件,而“ c”标志告诉存档器创建尚不存在的库。

示例—动态库

您创建另一个程序get_mod(int a, int b) ,该程序运行位于动态库中的get_mod(int a, int b)函数。 动态库的不同之处在于它们已经存储在内存中,但是如果在编译过程中未将其存储在内存中,则它们将在存储期间存储。 因此,现在您位于链接短语中,并具有目标代码calculation_dynamic.c 。 链接器将创建一个包含目标代码的可执行文件,然后还将包含get_mode(int a, int b)函数所在位置的地址。

优点-因此,与静态链接不同,没有大小问题。 此外,如果包含get_mode(int a, int b)函数的库的创建者get_mode(int a, int b)函数进行了更新,则无需重新编译您的get_mode(int a, int b) ,则只需下载这些库并将其存储在内存中(地址保持不变)。

缺点—因为动态库是通过库链接的,并且不需要进行持续的重新编译,所以如果更新不兼容,它也可能导致程序停止工作。

如何创建-要创建动态库,请首先为要包含在动态库中的所有文件创建目标代码。

  gcc -fPIC -g -c -Wall your_c_files.c 

-fPIC标志启用“位置无关代码”生成,这是共享库的要求。 给定-c标志,我们首先编译或汇编所有c代码,但不链接它们。

-shared标志使编译器知道我们正在编译共享库,但是-Wl标志对于将-shared标志的选项传递给编译器是必需的。 如您所见,选项用逗号分隔-soname和我们的实际library_name(-shared的两个选项)标志。

然后,您要运行以实际创建动态库。

  gcc -shared -Wl,-soname,library_name.so -o library_name.so you_object_codes.o 

要传递动态库名称,必须使用-Wl标志并包括-soname。

到那为止,那就是对库的简单介绍。