在 Linux中如何使用動態連結模組庫?
導讀 | 學習如何用動態連結庫將多個 C 目標檔案結合到一個單個的可執行檔案之中。當使用 C 程式語言編寫一個應用程式時,你的程式碼通常有多個原始檔程式碼。 |
最終,這些檔案必須被編譯到一個單個的可執行檔案之中。你可以透過建立靜態或動態庫(後者也被稱為 共享shared 庫)來實現這一點。這兩種型別的庫在建立和連結的方式上有所不同。兩者都有缺點和優點,這取決於你的使用情況。
動態連結是最常見的方法,尤其是在 系統上。動態連結會保持庫模組化,因此,很多應用程式可以共享一個庫。應用程式的模組化也允許單獨更新其依賴的共享庫。
在這篇文章中,我將演示動態連結是如何工作的。在後期的文章中,我將演示靜態連結。
連結器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.c 、sub.c 、mult.c 和 divi.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.o、sub.o、mult.o 和 divi.o :
(LCTT 校注:關於“目標檔案object file”,有時候也被稱作“物件檔案”,對此,存在一些譯法混亂情形,稱之為“目標檔案”的譯法比較流行,本文采用此譯法。)
$ gcc -c add.c sub.c mult.c divi.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 的檔案,並將這些程式碼複製貼上至其中:
nclude <stdlib.h> int main() { int x, y; printf("Enter two numbers\n"); 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't perform division\n"); exit(0); }else{ printf("\n%d / %d = %d\n", x, y, divi(x, y)); return 0; } }
注意:第一行是一個 include 語句,透過名稱來引用你自己的 libmymath 庫。要使用一個共享庫,你必須已經安裝了它,如果你沒有安裝你將要使用的庫,那麼當你的可執行檔案在執行並搜尋其包含的庫時,將找不到該共享庫。如果你需要在不安裝庫到已知目錄的情況下編譯程式碼,這裡有 一些方法可以覆蓋預設設定。不過,對於一般使用來說,我們希望庫存在於已知的位置,因此,這就是我在這裡演示的東西。
複製檔案 libmymath.so 到一個標準的系統目錄,例如:/usr/lib64, 然後執行 ldconfig 。ldconfig 命令建立所需的連結,並快取到標準庫目錄中發現的最新共享庫。
$ 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 系統上絕大多數的命令是動態連結的,並且在現代硬體上,所能節省的時間是可以忽略不計的。對開發者和使用者來說,它的固有模組性是一種強大的功能。
在這篇文章中,我描述瞭如何建立動態庫,並將其連結到一個最終可執行檔案。在我的下一篇文章中,我將使用相同的原始檔程式碼來建立一個靜態連結的可執行檔案。
原文來自:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2907277/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 動態連結庫與靜態連結庫
- linux下靜態連結庫和動態連結庫的區別有哪些Linux
- cmake 連結動態連結庫
- 動態連結庫的生成和使用(二)
- 動態連結庫(DLL)的建立和使用
- 跨模組介面與動態庫
- 如何連結兩個名字一樣動態庫
- 關於顯示載入動態連結庫模組及解除安裝的問題
- 如何動態匯入ECMAScript模組
- OrchardCore 如何動態載入模組?
- 使用js動態新增連結隨機連結JS隨機
- Linux下玩轉nginx系列(八)---如何使用upsync模組實現動態負載均衡LinuxNginx負載
- 【技術向】Linux動態連結庫預載入型後門Linux
- 【連結 1】與靜態連結庫連結
- 在AndroidStudio下使用cmake編譯出靜態連結庫的方法Android編譯
- 在Linux中,什麼是硬連結和軟連結?Linux
- Linux環境下:程式的連結, 裝載和庫[靜態連結]Linux
- 編譯 pyav 成 wheel 並使用 auditwheel 固化動態連結庫編譯
- 載入動態連結庫——dlopen dlsym dlclose
- C#呼叫C++動態連結庫C#C++
- Linux動態庫Linux
- windows和linux gcc生成動態連結庫DLL和SO並用python呼叫WindowsLinuxGCPython
- JS動態引入模組JS
- 如何使用cgdb + qemu除錯linux核心模組除錯Linux
- 如何在 Linux 中配置使用 SSD (固態驅動器)Linux
- Vuex 單狀態庫 與 多模組狀態庫Vue
- 在Linux中,如何新增一個使用者到特定的組?Linux
- 在Linux中, 如何建立一個新使用者和新組?Linux
- [Linux]動靜態庫Linux
- P/Invoke之C#呼叫動態連結庫DLLC#
- Linux共享庫、靜態庫、動態庫詳解Linux
- 在Linux中,如何在Linux中使用Ansible進行自動化部署?Linux
- 靜態連結動態連結的連結順序問題和makefile示例
- linux下的靜態庫與動態庫Linux
- lua——alien庫實現lua呼叫C動態連結庫(dll、so)
- 動態庫使用
- 在 Linux 中如何移動檔案Linux
- Gazebo新增模型並控制模型運動作為動態障礙物(Ubuntu16.04, Gazebo7.16),附錄動態連結庫和靜態連結庫區別模型Ubuntu