.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 為我們自己的程式建立靜態和動態庫檔案的示例。

更新於:2022 年 12 月 23 日

3K+ 次瀏覽

開啟你的 職業生涯

透過完成課程獲得認證

開始
廣告