2.4. 使用 GCC 创建库

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

2.4.1. 库命名规则

用于库的一个特殊文件名称规则:例如称为 foo 的库一般会有文件 libfoo.solibfoo.a。通过 GCC 的链接输入选项(而非输出选项)自动理解此约定:

  • 当对库进行链接时,库可以通过它的名称 foo 以及参数 -l 指定(-lfoo):

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

2.4.2. soname 机制

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

先决条件

  • 您必须了解动态链接和库。
  • 您必须了解 ABI 兼容性的概念。
  • 您必须了解库命名约定。
  • 您必须了解符号链接。

问题介绍

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

  • 识别库的实际版本
  • 需要同一库的多个版本
  • 代表每个版本的 ABI 兼容性

soname 机制

为了解决这个问题,Linux 使用名为 soname 的机制。

foo 库版本 X.Y 与在版本号中的 X 值相同的其它版本是 ABI 兼容。不会影响兼容性的次要更改会增加数字 Y。会影响兼容性的主要变化会增加数字 X

实际的 foo 库版本 X.Y 作为文件 libfoo.so.x.y 存在。在库文件中,使用值 libfoo.so.x 记录 soname 来指示兼容性。

构建应用程序时,链接程序通过搜索文件 libfoo.so 来查找库。必须存在带有此名称的符号链接,指向实际库文件。然后,链接器会从库文件读取 soname,并将其记录到应用程序可执行文件。最后,链路器创建使用 soname(而不是文件名)声明对库的依赖项的应用。

运行时动态链路器会在运行之前链接应用程序时,它会从应用程序的可执行文件读取 soname。这个 soname 是 libfoo.so.x。必须存在带有此名称的符号链接,指向实际库文件。无论某个版本的 Y 是什么,都允许载入库,因为 soname 不会改变。

注意

版本号的 Y 组件不仅限于一个数字。另外,一些库会使用其名称对它们的版本进行编码。

从文件中读取 soname

显示库文件 somelibrary 的 soname :

$ objdump -p somelibrary | grep SONAME

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

2.4.3. 使用 GCC 创建动态库

动态链接的库(共享对象)允许:

  • 通过代码重复利用的资源保留
  • 通过更新库代码来提高安全性

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

先决条件

  • 您必须了解 soname 机制。
  • 必须在系统中安装 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.4.4. 使用 GCC 和 ar 创建静态库

通过将对象文件转换为特殊归档文件,可以为静态链接创建库。

注意

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

先决条件

  • 在系统中必须安装 GCC 和 binutils。
  • 您必须了解静态和动态链接。
  • 提供了作为库共享的功能的源文件。

步骤

  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 page:

    $ man ar