Red Hat Training

A Red Hat training course is available for RHEL 8

2.3. 使用 GCC 创建库

了解创建库以及 Linux 操作系统用于库的必要概念的步骤。

2.3.1. 库命名惯例

对库使用特殊文件名惯例:名为 foo 的库应该以文件 libfoo.solibfoo.a 的形式存在。通过链接 GCC 的输入选项(而非输出选项)可自动理解这一惯例:

  • 当链接到库时,只能将其名称 foo-l 作为 -lfoo 来指定库:

    $ gcc ... -lfoo ...
  • 在创建库时,必须指定完整文件名 libfoo.solibfoo.a

2.3.2. soname 机制

动态加载的库(共享对象)使用一个名为 soname 的机制来管理库的多个兼容版本。

先决条件

问题简介

动态加载的库(共享目标)作为一个独立的可执行文件存在。这使得可以在不更新依赖于它的应用程序的情况下更新库。但是,这个概念会出现以下问题:

  • 库的实际版本的标识
  • 需要存在同一库的多个版本
  • 表示多个版本中每个版本的 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

使用您要检查的库的实际文件名替换 somelibrary

2.3.3. 使用 GCC 创建动态库

动态链接的库(共享目标)允许:

  • 通过代码重用来节约资源
  • 通过更轻松地更新库代码来提高安全性

按照以下步骤从源构建和安装动态库。

先决条件

流程

  1. 进到有库源文件的目录。
  2. 使用位置独立代码选项 -fPIC 将每个源文件编译成目标文件:

    $ gcc ... -c -fPIC some_file.c ...

    目标文件具有与原始源代码文件相同的文件名,但它们的扩展名是 .o

  3. 链接目标文件的共享库:

    $ gcc -shared -o libfoo.so.x.y -Wl,-soname,libfoo.so.x some_file.o ...

    使用的主版本号是 X ,次版本号是 Y。

  4. libfoo.so.x.y 文件复制到合适的位置,其中系统的动态链接器可以找到它。在 Red Hat Enterprise Linux 中,库的目录是 /usr/lib64

    # cp libfoo.so.x.y /usr/lib64

    请注意,您需要 root 权限才能操作此目录中的文件。

  5. 为 soname 机制创建符号链接结构:

    # ln -s libfoo.so.x.y libfoo.so.x
    # ln -s libfoo.so.x libfoo.so

其他资源

2.3.4. 使用 GCC 和 ar 创建静态库

通过将目标文件转换为特殊类型的存档文件,可以创建用于静态链接的库。

注意

出于安全原因,红帽不建议使用静态链接。只在需要时才使用静态链接,特别是红帽提供的库。详情请查看 第 2.2.2 节 “静态和动态链接”

先决条件

流程

  1. 使用 GCC 创建中间目标文件。

    $ gcc -c source_file.c ...

    如果需要,可附加更多源文件。生成的目标文件共享文件名,但使用 .o 文件扩展名。

  2. 使用 binutils 软件包中的 ar 工具将目标文件转换为静态库(存档)。

    $ ar rcs libfoo.a source_file.o ...

    文件 libfoo.a 已创建。

  3. 使用 nm 命令检查生成的归档:

    $ nm libfoo.a
  4. 将静态库文件复制到合适的目录。
  5. 与库链接时,GCC 将自动从 .a 文件扩展名中识别出库是一个用于静态链接的存档。

    $ gcc ... -lfoo ...

其他资源

  • ar(1) 的 Linux 手册页:

    $ man ar