.a 文件和 .so 文件的区别

linuxopen sourceoperating system更新于 2026/1/27 19:07:17

概述

一位程序员可能想要编写三个不同的程序。然而,他意识到每个程序所需的某些功能可以在它们之间共享。因此,他决定创建一个包含这些共享功能的库。

库本质上是其他人可以使用的代码和数据的集合。在 Linux 上,归档文件(文件扩展名为 .a)包含编译后的代码,而共享对象(.so 文件)包含解释后的代码。

本文将探讨软件在 Linux 下的运行方式以及库和归档文件的用途。我们还将通过一些示例来了解如何为我们自己的应用程序创建这些文件。我们将使用 GCC 编译器和 GNU ar 实用程序来完成此任务。

程序如何在 Linux 下运行

大多数 Linux 系统可能都遇到过 /lib 和 /user/lib 目录。这些目录包含计算机上安装的程序所需的所有常用函数。库名称通常以"lib"开头,扩展名表示文件的类型 -

.a — 代表"存档"
.so — 代表"共享对象"

一个程序可能依赖于多个共享对象。手动下载并解压共享对象文件可能非常麻烦。我们需要一个包管理器,以便在安装软件之前计算并确定依赖关系。

运行应用程序时,它会在 /lib 和 /share 文件夹中查找所有必需的依赖项。如果未安装所需的依赖项,程序将无法运行。

程序库

库提供用于执行特定任务的函数。例如,多个应用程序可能需要使用复数计算。库提供的函数的一个很好的例子是 GNU C 标准库 (libc),当我们使用 gcc 编译器编译应用程序时,它会链接到我们的应用程序中。

静态库

传统的静态库是编译成存档文件(例如 .a)的源文件集合,编译器可以在编译期间使用它们。在链接此类库时,链接器不需要任何有关库内容的额外信息;相反,它只需获取存档文件并将其放置在最终应用程序二进制文件中的某个位置即可。相比之下,动态库在运行时动态加载。它们通常是共享对象 (.so),但也可能是存档文件 (.a)。动态库允许应用程序共享数据,而无需在每个版本中重新编译它们。

静态库通常以 .a 扩展名结尾,例如 glibc.a。

共享库

为了解决可执行文件过大的问题,程序员经常使用共享库。动态库文件也称为共享库文件。这些静态链接文件在应用程序首次运行时链接到应用程序中。

共享库通常以 .so(代表共享对象)结尾,例如 libboost_filesystem.so。与静态库不同,引用动态库的程序在构建到可执行文件中时不会包含其对应的对象。因此,我们得到的可执行文件更小。

当多个应用程序引用同一个共享库时,该库只有一个副本,可供所有应用程序同时使用。可以说,Linux 是现代计算最重要的基础之一。让我们看一下 xorg 文件夹 -

$ ls -halF /usr/bin/xorg
-rwxr-xr-x 1 root root 95K Apr 13 20:12 libexa.so*
-rwxr-xr-x 1 root root 23K Apr 13 20:12 libfbdevhw.so*
-rwxr-xr-x 1 root root 111K Apr 13 20:12 libfb.so*
-rwxr-xr-x 1 root root 213K Apr 13 20:12 libglamoregl.so*
-rwxr-xr-x 1 root root 143K Apr 13 20:12 libint10.so*
-rwxr-xr-x 1 root root 15K Apr 13 20:12 libshadowfb.so*
-rwxr-xr-x 1 root root 39K Apr 13 20:12 libshadow.so*

我们可以看到 xorg 使用了列出的共享库文件。这些文件反过来也可以被其他程序(例如 dwm)使用。

构建 .a 文件或静态库

为了说明此示例,我们需要 GCC 来运行该程序。如果我们想使用 GCC 将 C 程序创建为可执行文件,我们可以执行以下命令 -

$ gcc -Wall -c *.c

我们需要确保当前目录位于文件夹结构的底部。-W 标志会使编译器打印出它找到的所有警告。*.c 参数中的 * 字符指示编译器编译所有 .c 文件。当您执行以下命令时,编译器会将每个 .cpp 文件编译为目标文件。然后,我们得到了所有需要的 .o 文件,我们将用它们来创建我们自己的库。

创建归档文件后,我们现在可以将目标代码提取到库中。我们将使用 GNU Binutils 自带的 ar 实用程序。

$ ar -cvq libfile.a *.o

要创建归档文件,请使用 -t (tar) 命令,后跟要归档的文件的名称。您可以使用逗号指定多个文件名。使用 -z (zip) 命令压缩归档文件。例如,如果您要压缩三个名为 dir1、dir2 和 dir3 的目录,如果归档文件尚不存在,则会创建一个。如果 ar 命令执行成功,我们将得到一个名为 libfile.a 的静态归档文件。让我们看看 libfile.a 库文件包含的内容 -

$ ar -t libfile.a

此命令列出了已归档到 libfile.a 中的所有目标文件。以后需要使用该库时,只需将其添加到编译命令中即可。

$ gcc -o MyProgram *.o -L path/to/libdir -lfile.a

指定 -L 选项会告诉编译器在哪里查找库。请确保在命令中使用正确的文件名。我们将库前缀替换为 -l。MyProgram 可执行文件包含 libfile.a 共享库的目标代码。

构建 .so 或共享库

您可以使用 GCC 轻松构建共享库。我们首先必须将源代码编译成相应的目标代码 -

$ gcc -Wall -c *.c

将源文件编译成可执行文件后,我们需要运行另一个程序来从该可执行文件生成共享库。

$ gcc -shared -o libfile.so *.o

使用 -shared 标志时,指定我们正在构建共享目标文件。成功编译后,我们将创建一个共享目标文件,可用于从任何程序进行链接。

结论

我们了解了大多数程序如何在 Linux 系统上运行,以及它们如何依赖于各种类型的库文件。然后,我们研究了静态库文件和动态库文件及其用途。最后,我们看了一个示例,展示了如何使用 gcc 及其辅助工具 ar 为我们自己的程序创建静态库文件和动态库文件。


相关文章


有用资源