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

    5 Comments

    1. 350fairfax nordvpn coupons
      It’s amazing to go to see this website and reading the views of all friends concerning this paragraph,
      while I am also eager of getting know-how.

    2. It’s really very complicated in this active life to listen news on TV,
      so I only use internet for that purpose, and get the newest news.

      my website nordvpn coupons inspiresensation (T.co)

    3. What’s up colleagues, its enormous piece of writing about tutoringand entirely explained,
      keep it up all the time.

      My web site nordvpn coupons inspiresensation

    4. Simply wish to say your article is as astounding. The clarity
      in your post is simply excellent and i could assume you’re
      an expert on this subject. Well with your permission let me to grab your feed to keep updated with forthcoming post.
      Thanks a million and please keep up the gratifying work.

      Review my web blog – nordvpn coupons inspiresensation

    5. Wonderful blog! Do you have any hints for aspiring writers?
      I’m planning to start my own website soon but I’m
      a little lost on everything. Would you recommend starting with
      a free platform like WordPress or go for a paid option? There are so many options out there that I’m totally confused ..
      Any recommendations? Kudos!

      my blog nordvpn coupons inspiresensation (t.co)

    Leave a reply

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

    這個站點使用 Akismet 來減少垃圾評論。了解你的評論數據如何被處理

    More in:Linux中國