Linux中國

如何在 Linux 上動態鏈接模塊庫

當使用 C 編程語言編寫一個應用程序時,你的代碼通常有多個源文件代碼。

最終,這些文件必須被編譯到一個單個的可執行文件之中。你可以通過創建靜態或動態庫(後者也被稱為 共享 shared 庫)來實現這一點。這兩種類型的庫在創建和鏈接的方式上有所不同。兩者都有缺點和優點,這取決於你的使用情況。

動態鏈接是最常見的方法,尤其是在 Linux 系統上。動態鏈接會保持庫模塊化,因此,很多應用程序可以共享一個庫。應用程序的模塊化也允許單獨更新其依賴的共享庫。

在這篇文章中,我將演示動態鏈接是如何工作的。在後期的文章中,我將演示靜態鏈接。

鏈接器

鏈接器 linker 是一個命令,它將一個程序的數個部分結合在一起,並為它們重新組織內存分配。

鏈接器的功能包括:

  • 整合一個程序的所有的部分
  • 計算出一個新的內存組織結構,以便所有的部分組合在一起
  • 恢復內存地址,以便程序可以在新的內存組織結構下運行
  • 解析符號引用

鏈接器通過這些功能,創建了一個名為 可執行文件 executable 的可以運行的程序。在你創建一個動態鏈接的可執行文件前,你需要一些用來鏈接的庫,和一個用來編譯的應用程序。準備好你 最喜歡的文本編輯器 並繼續。

創建目標文件

首先,創建帶有這些函數簽名的頭文件 mymath.h

int add(int a, int b);
int sub(int a, int b);
int mult(int a, int b);
int divi(int a, int b);

使用這些函數定義來創建 add.csub.cmult.cdivi.c 文件。我將把所有的代碼都放置到一個代碼塊中,請將其分為四個文件,如注釋所示:

// add.c
int add(int a, int b){
return (a+b);
}

//sub.c
int sub(int a, int b){
return (a-b);
}

//mult.c
int mult(int a, int b){
return (a*b);
}

//divi.c
int divi(int a, int b){
return (a/b);
}

現在,使用 GCC 來創建目標文件 add.osub.omult.odivi.o

(LCTT 校註:關於「 目標文件 object file 」,有時候也被稱作「對象文件」,對此,存在一些譯法混亂情形,稱之為「目標文件」的譯法比較流行,本文採用此譯法。)

$ gcc -c add.c sub.c mult.c divi.c

-c 選項跳過鏈接步驟,並且只創建目標文件。

創建一個共享的目標文件

在最終的可執行文件的執行過程中將鏈接動態庫。在最終的可執行文件中僅放置動態庫的名稱。實際上的鏈接過程發生在運行時,在此期間,可執行文件和庫都被放置到了主內存中。

除了可共享外,動態庫的另外一個優點是它減少了最終的可執行文件的大小。在一個應用程序最終的可執行文件生成時,其使用的庫只包括該庫的名稱,而不是該庫的一個多餘的副本。

你可以從你現有的示例代碼中創建動態庫:

$ gcc -Wall -fPIC -c add.c sub.c mult.c divi.c

選項 -fPIC 告訴 GCC 來生成 位置無關的代碼 position-independent code (PIC)。-Wall 選項不是必需的,並且與代碼的編譯方式是無關的。不過,它卻是一個有價值的選項,因為它會啟用編譯器警告,這在排除故障時是很有幫助的。

使用 GCC ,創建共享庫 libmymath.so

$ gcc -shared -o libmymath.so add.o sub.o mult.o divi.o

現在,你已經創建了一個簡單的示例數學庫 libmymath.so ,你可以在 C 代碼中使用它。當然,也有非常複雜的 C 庫,這就是他們這些開發者來生成最終產品的工藝流程,你和我可以安裝這些庫並在 C 代碼中使用。

接下來,你可以在一些自定義代碼中使用你的新數學庫,然後鏈接它。

創建一個動態鏈接的可執行文件

假設你已經為數學運算編寫了一個命令。創建一個名稱為 mathDemo.c 的文件,並將這些代碼複製粘貼至其中:

#include <mymath.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
  int x, y;
  printf("Enter two numbersn");
  scanf("%d%d",&x,&y);

  printf("n%d + %d = %d", x, y, add(x, y));
  printf("n%d - %d = %d", x, y, sub(x, y));
  printf("n%d * %d = %d", x, y, mult(x, y));

  if(y==0){
    printf("nDenominator is zero so can&apos;t perform divisionn");
      exit(0);
  }else{
      printf("n%d / %d = %dn", x, y, divi(x, y));
      return 0;
  }
}

注意:第一行是一個 include 語句,通過名稱來引用你自己的 libmymath 庫。要使用一個共享庫,你必須已經安裝了它,如果你沒有安裝你將要使用的庫,那麼當你的可執行文件在運行並搜索其包含的庫時,將找不到該共享庫。如果你需要在不安裝庫到已知目錄的情況下編譯代碼,這裡有 一些方法可以覆蓋默認設置。不過,對於一般使用來說,我們希望庫存在於已知的位置,因此,這就是我在這裡演示的東西。

複製文件 libmymath.so 到一個標準的系統目錄,例如:/usr/lib64, 然後運行 ldconfigldconfig 命令創建所需的鏈接,並緩存到標準庫目錄中發現的最新共享庫。

$ sudo cp libmymath.so /usr/lib64/
$ sudo ldconfig

編譯應用程序

從你的應用程序源文件代碼(mathDemo.c)中創建一個名稱為 mathDemo.o 的目標文件:

$ gcc -I . -c mathDemo.c

-I 選項告訴 GCC 來在其後所列出的目錄中搜索頭文件(在這個示例中是 mymath.h)。在這個示例中,你指定的是當前目錄,通過一個單點(.)來表示。創建一個可執行文件,使用 -l 選項來通過名稱來引用你的共享數學庫:

$ gcc -o mathDynamic mathDemo.o -lmymath

GCC 會找到 libmymath.so ,因為它存在於一個默認的系統庫目錄中。使用 ldd 來查證所使用的共享庫:

$ ldd mathDemo
    linux-vdso.so.1 (0x00007fffe6a30000)
    libmymath.so => /usr/lib64/libmymath.so (0x00007fe4d4d33000)
    libc.so.6 => /lib64/libc.so.6 (0x00007fe4d4b29000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fe4d4d4e000)

看看 mathDemo 可執行文件的大小:

$ du ./mathDynamic
24   ./mathDynamic

當然,它是一個小的應用程序,它所佔用的磁碟空間量也反映了這一點。相比之下,相同代碼的一個靜態鏈接版本(正如你將在我後期的文章所看到的一樣)是 932K !

$ ./mathDynamic
Enter two numbers
25
5

25 + 5 = 30
25 - 5 = 20
25 * 5 = 125
25 / 5 = 5

你可以使用 file 命令來查證它是動態鏈接的:

$ file ./mathDynamic
./mathDynamic: ELF 64-bit LSB executable, x86-64,
dynamically linked,
interpreter /lib64/ld-linux-x86-64.so.2,
with debug_info, not stripped

成功!

動態鏈接

因為鏈接發生在運行時,所以,使用一個共享庫會產生一個輕量型的可執行文件。因為它在運行時解析引用,所以它會花費更多的執行時間。不過,因為在日常使用的 Linux 系統上絕大多數的命令是動態鏈接的,並且在現代硬體上,所能節省的時間是可以忽略不計的。對開發者和用戶來說,它的固有模塊性是一種強大的功能。

在這篇文章中,我描述了如何創建動態庫,並將其鏈接到一個最終可執行文件。在我的下一篇文章中,我將使用相同的源文件代碼來創建一個靜態鏈接的可執行文件。

via: https://opensource.com/article/22/5/dynamic-linking-modular-libraries-linux

作者:Jayashree Huttanagoudar 選題:lkxed 譯者:robsean 校對:wxy

本文由 LCTT 原創編譯,Linux中國 榮譽推出


本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive

對這篇文章感覺如何?

太棒了
0
不錯
0
愛死了
0
不太好
0
感覺很糟
0
雨落清風。心向陽

    You may also like

    Leave a reply

    您的郵箱地址不會被公開。 必填項已用 * 標註

    此站點使用Akismet來減少垃圾評論。了解我們如何處理您的評論數據

    More in:Linux中國