Contents

什么是.a和.so文件?

1.概述

想象一个程序员想要设计和编写三个不同的程序。他认为这三个程序共享几个可以被程序重用的通用功能。为了让他的生活更轻松,他需要将这些功能收集到一个名为library的实体中。

通常,库是为其他程序员或程序重用而编写的数据和函数的集合。在 Linux 上,存档库以.a扩展名结尾,共享对象库以.so 扩展名**结尾。

在本文中,我们将了解程序如何在 Linux 下运行以及归档和共享对象库的用途。除此之外,我们还将看到一些关于如何为程序构建库的示例。我们将使用GNU C 编译器  和GNU ar 实用程序。

2. Linux下程序如何运行

大多数 Linux 用户可能都遇到过*/lib/usr/lib*目录。这些是我们存储 安装在我们的 Linux 机器上**的程序使用的所有常用功能的目录。**作为约定,库名称以“lib”开头,扩展名决定了库的类型:

  • .a — 代表“存档”
  • *.so——*代表“共享对象”

一个程序可能依赖于多个共享对象。因此,手动安装共享对象可能很麻烦。为了解决这个问题,我们需要一个包管理器——一个在安装实际程序之前计算和确定依赖关系的工具。

当我们运行程序时,它会在*/usr/lib* 和*/share*目录中查找所需的依赖项。但是,如果缺少所需的依赖项,程序将无法启动

3. 程序库

程序库由执行常见任务所需的相关数据和子程序组成。例如,多个程序可能需要使用复数来计算结果。提供此功能的库的一个很好的例子是GNU C 库 ,它在链接阶段由gcc 编译器链接到我们的程序中。

3.1. 静态库

传统的静态库是一种在编译时与程序链接的库。因此,库的目标代码包含在可执行程序的目标代码中。最终,如果我们有多个程序链接到一个静态库,那么每个生成的程序二进制文件都将包含引用库的目标代码。因此,这将导致更大的可执行文件。

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

3.2. 共享库

为了解决较大的可执行二进制文件的问题,程序员改用共享库。共享库也称为动态库。这些共享库在运行时由操作系统上可用的动态链接器链接。

共享库通常以*.so扩展名结尾——例如libboost.5.6.so*。与静态库不同,引用共享库的程序不会在其生成的可执行文件中包含共享库对象代码。因此,我们得到更小的可执行文件。

同样,当我们有多个程序引用同一个共享库时,该库将有一个可供程序同时重用的单一副本。这是由操作系统安全管理的,它是现代计算的基础。我们看一下*/usr/lib/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 等其他程序使用。

4. 构建*.a*或静态库

为了使这个说明起作用,我们需要gcc 来编译我们的源代码。假设我们有一堆C编程源文件——我们需要将源文件编译成目标代码。我们可以通过发出带有*-Wall选项的gcc*命令来实现:

$ gcc -Wall -c *.c

我们需要确保我们位于源目录的根目录。-Wall选项告诉编译器打印它遇到的所有警告。*.c参数中的星号告诉编译器编译所有**.c源文件。发出上述命令后,编译器会将*.c文件编译为相应的目标文件。因此,我们获得了 构建库所需的所有必需的*.o*文件。

接下来,我们将使用GNU Binutils 中包含的ar实用程序从目标代码创建一个库文件:

$ ar -cvq libfile.a *.o

-c选项抑制错误,  -v 选项用于详细输出,  -q选项用于快速将指定文件附加到存档。如果存档不存在,则会创建一个新存档。当ar命令执行成功时,我们应该得到一个静态库文件libfile.a。让我们看看libfile.a文件中包含的内容:

$ ar -t libfile.a

这将列出归档到libfile.a中的所有目标文件。稍后,当我们想在我们的程序中包含该库时,我们可以简单地在编译命令中引用该库:

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

-L选项用于指定库目录。 注意命令中的库文件名。我们 用*-l替换了**lib*前缀。MyProgram可执行文件将包含 libfile.a库的目标代码。

5. 构建*.so*或共享库

使用gcc可以轻松构建共享库。和之前一样,我们首先需要将源文件编译成对应的目标文件:

$ gcc -Wall -c *.c

编译代码后,我们需要将目标代码文件提供给我们的下一个命令以创建共享库:

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

-shared选项向编译器指定我们正在构建一个共享库。 成功编译后,我们将构建一个共享库,我们可以将其安装在我们的系统上,以便所有程序在运行时都可以使用它。