2.3. 将库与 GCC 一起使用


了解在代码中使用库。

2.3.1. 库命名惯例

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

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

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

其他资源

2.3.2. 静态和动态链接

开发人员在使用完全编译的语言构建应用程序时可以选择使用静态或动态链接。了解静态和动态链接之间的区别很重要,特别是在 Red Hat Enterprise Linux 上使用 C 和 C++ 语言的上下文中。总之,红帽不建议对 Red Hat Enterprise Linux 的应用程序使用静态链接。

静态和动态链接的比较
静态链接使库成为生成的可执行文件的一部分。动态链接将这些库保留为单独的文件。

静态链接存在许多缺点,应该避免,特别是对于整个应用程序和 glibclibstdc++ 库:

资源使用 :静态链接会导致更大的可执行文件,其中包含更多代码。这些额外的代码来自不能在系统上的多个程序之间共享的库,这会增加运行时文件系统的使用率和内存的使用率。运行同一静态链接的程序的多个进程仍将共享代码。

另一方面,静态应用需要较少的运行时重定位,从而减少启动时间,并且需要较少的专用常驻集大小(RSS)内存。由于位置无关代码(PIC)引入的开销,为静态链接生成的代码比动态链接更高效。

安全 :可以更新提供 ABI 兼容性的动态链接库,而无需根据这些库更改可执行文件。这对于由红帽提供的、作为 Red Hat Enterprise Linux 的一部分的库来说尤为重要,红帽提供安全更新。强烈反对对任何此类库的静态链接。

兼容性 :静态链接似乎提供独立于操作系统提供的库版本的可执行文件。但是,大多数库依赖于其他库。有了静态链接,此依赖变得不灵活,因此会丢失向前和向后兼容性。静态链接可保证仅在构建可执行文件的系统上工作。

警告

静态链接 GNU C 库的应用程序(glibc)仍然需要 glibc 作为动态库存在于系统中。此外,在应用程序的运行时可用的 glibc 的动态库变体在连接应用程序时必须与当前版本按位相同。因此,静态链接保证仅在构建可执行文件的系统上工作。

支持覆盖率 :红帽提供的大多数静态库都位于 CodeReady Linux Builder 频道中,不受红帽支持。

功能 :一些库,特别是 GNU C 库(glibc),在静态链接时提供减少的功能。

例如,当静态链接时,glibc 不支持线程和在同一程序中对 dlopen() 函数的任何形式的调用。

静态链接的情况

在某些情况下静态链接可能是一种合理的选择,例如:

  • 当使用未为动态链接启用的库时。
  • 当在空的 chroot 环境或容器中运行代码所需的完全静态链接时。但是,红帽不支持使用 glibc-static 软件包的静态链接。

2.3.4. 将一个库与 GCC 一起使用

库是可在您的程序中重复使用的代码软件包。C 或 C++ 库由两个部分组成:

  • 库代码
  • 头文件

    使用库编译代码
    头文件描述库的接口:库中的函数和变量。编译代码需要头文件中的信息。

通常,库的头文件将被放置在与您的应用代码不同的目录中。要告诉 GCC 头文件的位置,请使用 -I 选项:

$ gcc ... -Iinclude_path ...
Copy to Clipboard Toggle word wrap

使用头文件目录的实际路径替换 include_path

例如,要指定相对路径 some/interesting/directory

$ gcc ... -Isome/interesting/directory ...
Copy to Clipboard Toggle word wrap

-I 选项可多次使用,以添加包含头文件的多个目录。查找头文件时,会按照它们在 -I 选项中出现的顺序搜索这些目录。

链接使用库的代码

链接可执行文件时,应用程序的目标代码和库的二进制代码都必须提供。静态和动态库的代码以不同的格式存在:

  • 静态库作为存档文件提供。它们包含一组目标文件。存档文件具有文件扩展名 .a
  • 动态库作为共享目标提供。它们是一种可执行文件的形式。共享目标具有文件扩展名 .so

要告诉 GCC 库的存档或共享目标文件的位置,请使用 -L 选项:

$ gcc ... -Llibrary_path -lfoo ...
Copy to Clipboard Toggle word wrap

使用库目录的实际路径替换 library_path

-L 选项可多次使用,以添加多个目录。查找库时,系统将按照其 -L 选项的顺序搜索这些目录。

选项的顺序很重要:GCC 无法链接库 foo,除非它知道这个库的目录。因此,在使用 -l 选项链接库之前,请使用 -L 选项来指定库目录。

在一个步骤中编译和链接使用库的代码
当您在一个 gcc 命令中编译和链接时,请组合编译时间和链接选项。

2.3.5. 将一个静态库与 GCC 一起使用

静态库作为包含目标文件的存档提供。链接后,它们成为生成的可执行文件的一部分。

注意

出于安全原因,红帽不建议使用静态链接。请参阅 静态和动态链接。仅在需要时才使用静态链接,特别是对红帽提供的库。

先决条件

  • GCC 必须安装在您的系统上。
  • 您必须了解静态和动态链接。
  • 您有一组组成有效程序的源或目标文件,需要一些静态库 foo ,但没有其他库。
  • foo 库作为 libfoo.a 文件提供,对于动态链接,不提供文件 libfoo.so

    注意

    作为 Red Hat Enterprise Linux 一部分的大多数库都只支持动态链接。以下步骤仅适用于 没有 为动态链接启用的库。

请参阅 静态和动态链接

流程

  • 要从源和目标文件链接程序,请添加静态链接库 foo,该库可作为 libfoo.a 文件找到。

    1. 进到包含您代码的目录。
    2. 编译带有 foo 库的头的程序源文件:

      $ gcc ... -Iheader_path -c ...
      Copy to Clipboard Toggle word wrap

      使用包含 foo 库的头文件的目录的路径替换 header_path

    3. 将程序与 foo 库链接:

      $ gcc ... -Llibrary_path -lfoo ...
      Copy to Clipboard Toggle word wrap

      使用包含文件 libfoo.a 的目录的路径替换 library_path

    4. 要稍后运行该程序,只需:

      $ ./program
      Copy to Clipboard Toggle word wrap
      警告

      与静态链接有关的 -static GCC 选项禁止所有动态链接。相反,请使用 -Wl、-Bstatic-Wl,-Bdynamic 选项更精确地控制链接器行为。请参阅 使用 GCC 的静态库和动态库

2.3.6. 将一个动态库与 GCC 一起使用

动态库作为独立的可执行文件提供,在链接时和运行时需要。它们独立于您应用程序的可执行文件。

先决条件

  • GCC 必须安装在系统上。
  • 组成有效程序的一组源或目标文件需要一些动态库 foo ,但不需要其他库。
  • foo 库必须作为文件 libfoo.so 提供。

    将程序与动态库链接
    要将程序与动态库 foo 链接:
$ *gcc ... -L__library_path__ -l__foo__ ...*
Copy to Clipboard Toggle word wrap

当程序链接了动态库时,生成的程序必须总是在运行时加载库。定位库有两个选项:

  • 使用存储在可执行文件本身中的 run path
  • 在运行时使用 LD_LIBRARY_PATH 变量

    使用存储在可执行文件中的 run path
    run path 是一个特殊值,在被链接时作为可执行文件的一部分被保存。之后,当从可执行文件加载程序时,运行时链接器使用 run 路径 值来定位库文件。

在与 GCC 链接时,将路径 library_path 存储为 run path

$ gcc ... -Llibrary_path -lfoo -Wl,-run path=library_path ...
Copy to Clipboard Toggle word wrap

路径 library_path 必须指向包含文件 libfoo.so 的目录。

重要

不要在 -Wl,-run path= 选项中的逗号后添加空格。

要稍后运行程序:

$ ./program
Copy to Clipboard Toggle word wrap
使用 LD_LIBRARY_PATH 环境变量
设置搜索路径来定位库的另一种方法是使用 LD_LIBRARY_PATH 环境变量。必须为每个程序更改此变量的值。这个值应该代表共享库对象所在的路径,且必须为每个程序调用设置。

要使用路径 library_path 中存在的库运行程序:

$ export LD_LIBRARY_PATH=library_path:$LD_LIBRARY_PATH
$ ./program
Copy to Clipboard Toggle word wrap
run path 和 LD_LIBRARY_PATH 的交互
在 Red Hat Enterprise Linux 10 上,只有在没有在 LD_LIBRARY_PATH 中找到链接库时,才会在链接过程中使用程序中编码的 run path。可以使用 -Wl,--disable-new-dtags 选项恢复 Red Hat Enterprise Linux 10 中的旧行为,其中 run path 在 LD_LIBRARY_PATH 之前搜索。
将库放在默认目录中
运行时链接器配置指定多个目录来作为动态库文件的默认位置。要使用此默认行为,请将库复制到合适的目录中。

本文档没有详细地涵盖动态链接器行为。如需更多信息,请参阅以下资源:

  • 动态链接器的 Linux 手册页:
$ man ld.so
Copy to Clipboard Toggle word wrap
  • /etc/ld.so.conf 配置文件的内容:
$ cat /etc/ld.so.conf
Copy to Clipboard Toggle word wrap
  • 动态链接器识别的库的报告,无需额外配置,其包括目录:
$ ldconfig -v
Copy to Clipboard Toggle word wrap

2.3.7. 将静态库和动态库与 GCC 一起使用

有时您需要动态链接一些库。这种混合链接方法需要了解 GCC 如何处理不同的库类型。

gcc 识别动态和静态库。遇到 -lfoo 选项时,gcc 将首先尝试查找包含 foo 库的动态链接版本的共享目标(一个 .so 文件),然后查找包含库的静态版本的存档文件(.a)。因此,这个搜索可能会导致以下情况:

  • 只找到了共享目标,gcc 会动态链接它。
  • 只找到了归档,gcc 会静态链接它。
  • 共享目标和存档都都找到了,默认情况下,gcc 会选择对共享目标的动态链接。
  • 共享目标和存档都未找到,链接失败。

由于这些规则,选择用于链接的库的静态或动态版本的最佳方法是让 gcc 只找到该版本。在指定 -Lpath 选项时,可以使用或省略包含库版本的目录,来在某种程度上控制它。

此外,由于动态链接是默认的,因此链接被明确指定的唯一情形是存在两个版本的库都应被静态链接时。有两种可能的解决方案:

  • 通过文件路径而不是 -l 选项指定静态库
  • 使用 -Wl 选项将选项传给链接器

    通过文件指定静态库
    通常,使用 -lfoo 选项指示 gcc 链接到 foo 库。但是,可以指定包含库的 libfoo.a 文件的全路径:
$ *gcc ... path/to/libfoo.a ...*
Copy to Clipboard Toggle word wrap

从文件扩展名 .agcc 将理解为这是一个与程序链接的库。但是,指定库文件的全整路径是一个不太灵活的方法。

使用 -Wl 选项
gcc 选项 -Wl 是一个将选项传给底层链接器的特殊选项。此选项的语法与其他 gcc 选项不同。Wl 选项后跟一个以逗号分隔的链接选项列表,而其他 gcc 选项则需要以空格分隔的选项列表。

gcc 使用的 ld 链接器提供选项 -Bstatic-Bdynamic,来指定此选项后面的库是否应分别被静态链接或动态链接。在将 -Bstatic 和库传给链路器后,必须为以下使用 -Bdynamic 选项动态链接的库手动恢复默认的动态链接行为:

要链接程序,请静态链接库first (libfirst.a),动态链接库second (libsecond.so):

$ gcc ... -Wl,-Bstatic -lfirst -Wl,-Bdynamic -lsecond ...
Copy to Clipboard Toggle word wrap
注意

GCC 可以配置为使用默认 ld 以外的链接器。

返回顶部
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。 了解我们当前的更新.

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

Theme

© 2025 Red Hat