.a 和 .so 文件的区别
概述
程序员可能想编写三个不同的程序。但是,他意识到每个程序所需的一些功能可以在它们之间共享。因此,他决定创建一个包含这些共享功能的库。
库基本上是其他人员可以使用的代码和数据的集合。在 Linux 上,档案(位于 .a 文件扩展名)包含已编译的代码,而共享对象(.so 文件)包含解释型代码。
在这里,我们将研究软件如何在 Linux 下运行以及库和档案文件的作用。我们还将看到一些有关如何为我们自己的应用程序创建这些文件的示例。我们将使用 GCC 编译器和 GNU ar 实用程序来完成此任务。
程序如何在 Linux 下运行
大多数 Linux 系统可能都遇到过 /lib 和 /user/lib 目录。这些目录包含计算机上安装的程序所需的所有常用函数。约定规定库名称以“lib”开头,扩展名指示文件的类型 -
.a — stands for “archive” .so — stands for “shared object”
一个程序可能依赖于多个共享对象。手动下载和解压缩共享对象文件可能很麻烦。我们需要一个包管理器,以便在安装软件本身之前计算并确定依赖关系。
当我们运行应用程序时,它将在 /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 文件。
创建档案后,我们现在就可以将对象代码提取到库中了。我们将使用 ar 实用程序,它随 GNU Binutils 提供。
$ ar -cvq libfile.a *.o
要创建档案,请使用 -t (tar) 命令,后跟要归档的文件名。您可以使用逗号指定多个文件名。使用 -z (zip) 命令压缩档案。例如,如果您想压缩名为 dir1、dir2 和 如果档案不存在,则会创建一个档案。如果 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 为我们自己的程序创建静态和动态库文件的示例。
数据结构
网络
关系型数据库管理系统
操作系统
Java
iOS
HTML
CSS
Android
Python
C 编程
C++
C#
MongoDB
MySQL
Javascript
PHP