2.4. 使用 GCC 创建库
了解创建库以及 Linux 操作系统用于库的必要概念的步骤。另外,您必须了解用于库的特殊文件名约定。请参阅 第 2.3.1 节 “库命名惯例”。
2.4.1. soname 机制 复制链接链接已复制到粘贴板!
动态加载的库(共享对象)使用一个名为 soname 的机制来管理库的多个兼容版本。了解这个概念:
- 您必须了解动态链接和库。
- 您必须了解 ABI 兼容性的概念。
- 您必须了解库命名约定。
您必须了解符号链接。
- 问题简介
- 动态加载的库(共享目标)作为一个独立的可执行文件存在。这使得可以在不更新依赖于它的应用程序的情况下更新库。但是,这个概念会出现以下问题:
- 库的实际版本的标识
- 需要存在同一库的多个版本
表示多个版本中每个版本的 ABI 兼容性
- soname 机制
- 为了解决这个问题,Linux 使用一种称为 soname 的机制。
foo
库版本 X.Y 与版本号为 X 的其他版本 ABI 兼容。保持兼容性的次更改会增加数字 Y。破坏兼容性的主更改会增加数字 X。
实际的 foo
库版本 X.Y 作为文件 libfoo.so.x.y
存在。在库文件中,soname 是使用值 libfoo.so.x
记录的,以表示兼容性。
在构建期间,链接器搜索名为 libfoo.so
的符号链接,指向库文件。具有此名称的符号链接必须存在,指向实际的库文件。然后,链接器从库文件中读取 soname,并将其记录到应用程序可执行文件中。最后,链接器创建创建应用程序,该应用程序使用 soname 而不是名称或文件名来声明对库的依赖关系。
当运行时动态链接器在运行前链接应用程序时,它会从应用的可执行文件中读取 soname。该 soname 是 libfoo.so.x
。具有此名称的符号链接必须存在,指向实际的库文件。这允许加载库,而不考虑版本的 Y 组件,因为 soname 不会改变。
版本号 Y 组件号不仅限于一个数字。此外,一些库将其版本编码到其名称中。
- 从文件中读取 soname
要显示库文件
somelibrary
的 soname:objdump -p somelibrary | grep SONAME
$ objdump -p somelibrary | grep SONAME
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
使用您要检查的库的实际文件名替换 somelibrary。
- 在文件名中查找库名称和版本
例如,假设库作为文件
libevent-2.0.so.5.1.9
存在。查找实际组件:-
首先忽略标准库文件名前缀
lib
。 -
将其余部分分成以上两个部分,并遵循字符串
.so.
。 -
第一部分是
event-2.0
,即库的名称。 -
第二部分是
5.1.9
。要查找 X 版本组件,请在第一个点前做所有内容:5
。 -
其余是 Y 版本组件:
1.9
。
-
首先忽略标准库文件名前缀
因此,库的名称是 event-2.0
,X 版本组件为 5,Y 为 1.9。
此库文件的 soname 直到 Y 组件: libevent-2.0.so.5
。
当发布一个更新的但仍然兼容的库版本时,它会使用相同的 soname,并且 Y 版本组件会增加。新文件名是 libevent-2.0.so.5.1.10
。
2.4.2. 使用 GCC 创建动态库 复制链接链接已复制到粘贴板!
动态链接的库(共享目标)允许:
- 通过代码重用来节约资源
- 通过更轻松地更新库代码来提高安全性
按照以下步骤从源构建和安装动态库。
先决条件
- 您必须了解 soname 机制。
- GCC 必须安装在系统上。
- 您必须具有库的源代码。
流程
- 进到有库源文件的目录。
使用位置独立代码选项
-fPIC
将每个源文件编译成目标文件:gcc ... -c -fPIC some_file.c ...
$ gcc ... -c -fPIC some_file.c ...
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 目标文件具有与原始源代码文件相同的文件名,但它们的扩展名是
.o
。链接目标文件的共享库:
gcc -shared -o libfoo.so.x.y -Wl,-soname,libfoo.so.x some_file.o ...
$ gcc -shared -o libfoo.so.x.y -Wl,-soname,libfoo.so.x some_file.o ...
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 使用的主版本号是 X ,次版本号是 Y。
将
libfoo.so.x.y
文件复制到合适的位置,其中系统的动态链接器可以找到它。在 Red Hat Enterprise Linux 中,库的目录是/usr/lib64
:cp libfoo.so.x.y /usr/lib64
# cp libfoo.so.x.y /usr/lib64
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 请注意,您需要 root 权限才能操作此目录中的文件。
为 soname 机制创建符号链接结构:
ln -s libfoo.so.x.y libfoo.so.x ln -s libfoo.so.x libfoo.so
# ln -s libfoo.so.x.y libfoo.so.x # ln -s libfoo.so.x libfoo.so
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
其他资源
2.4.3. 使用 GCC 和 ar 创建静态库 复制链接链接已复制到粘贴板!
通过将目标文件转换为特殊类型的存档文件,可以创建用于静态链接的库。
出于安全原因,红帽不建议使用静态链接。只在需要时才使用静态链接,特别是红帽提供的库。如需了解更多详细信息,请参阅静态和动态链接。
先决条件
- 系统上必须安装了 GCC 和 binutils 。
- 您必须了解静态和动态链接。
- 提供了作为库共享的功能的源文件。
流程
使用 GCC 创建中间目标文件。
gcc -c source_file.c ...
$ gcc -c source_file.c ...
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 如果需要,可附加更多源文件。生成的目标文件共享文件名,但使用
.o
文件扩展名。使用
binutils
软件包中的ar
工具将目标文件转换为静态库(存档)。ar rcs libfoo.a source_file.o ...
$ ar rcs libfoo.a source_file.o ...
Copy to Clipboard Copied! Toggle word wrap Toggle overflow 文件
libfoo.a
已创建。使用
nm
命令检查生成的归档:nm libfoo.a
$ nm libfoo.a
Copy to Clipboard Copied! Toggle word wrap Toggle overflow - 将静态库文件复制到合适的目录。
与库链接时,GCC 将自动从
.a
文件扩展名中识别出库是一个用于静态链接的存档。gcc ... -lfoo ...
$ gcc ... -lfoo ...
Copy to Clipboard Copied! Toggle word wrap Toggle overflow