Linux下靜態庫和動態庫的建立與使用

2021-10-07 21:03:06 字數 3897 閱讀 9240

靜態庫:

假設當前有乙個 c 語言專案,其目錄結構如下所示:

demo專案

├─ headers

│ └─ test.h

└─ sources

├─ add.c

├─ sub.c

├─ div.c

└─ main.c

可以看到,該專案中包含 1 個頭檔案( .h ),4 個原始檔( .c ),它們各自包含的**如下所示:

整個專案的邏輯很簡單,其中 add.c、sub.c 和 div.c 這 3 個檔案中各包含乙個函式,分別實現將兩個整數做相加、相減和除法操作,而 test.h 僅包含這 3 個函式的宣告部分,main.c 是主程式檔案,其通過引入 test.h 標頭檔案呼叫了 3 個函式,從而分別完成了對使用者輸入的 2 個整數做相加、相減以及除法操作。

對於編譯、執行 demo 專案,我們可以直接使用 gcc 命令完成:

注意,由於在程式預處理階段,gcc 編譯器會自行處理各個 .c 檔案內部引入的 .h 標頭檔案(將 .h 檔案中的**直接拷貝到當前 .c 原始檔中),因此編譯執行 demo 專案時,我們只需要提供所有的原始檔即可,不需要處理標頭檔案。

注意,add.c、sub.c 和 div.c 這 3 個檔案,其包含的都是一些功能模組(實現具體功能的函式),對於這樣的原始檔,只要我們願意共享,每個人都可以直接用到自己的專案中。這就產生乙個問題,如果僅希望別人使用我們實現的功能,但又不想它看到具體實現的原始碼,該怎麼辦呢?很簡單,就是將它們加工成乙個靜態鏈結庫。

顯然對於 demo 專案中的 add.c、sub.c 以及 div.c 這 3 個原始檔來說,以上 2 個條件都符合,因此都可以被加工成靜態鏈結庫。並且根據實際需要,我們可以將它們集體壓縮到乙個靜態鏈結庫中,也可以各自壓縮成乙個靜態鏈結庫。

將原始檔打包為靜態鏈結庫的過程很簡單,只需經歷以下 2 個步驟:

1) 將所有指定的原始檔,都編譯成相應的目標檔案:

ar rcs 靜態鏈結庫名稱 目標檔案1 目標檔案2 ...

lib***.a

linux 系統下,靜態鏈結庫的字尾名為 .a;windows 系統下,靜態鏈結庫的字尾名為 .lib。

其中,*** 代指我們為該庫起的名字,比如 linux 系統自帶的一些靜態鏈結庫名稱為 libc.a、libgcc.a、libm.a,它們的名稱分別為 c、gcc 和 m。

下面,我們嘗試將 add.o、sub.o 和 div.o 打包到乙個靜態鏈結庫中:

其中,libmymath.a 就是 add.o、sub.o 和 div.o 一起打包生成的靜態鏈結庫,mymath 是我們自定義的庫名。

通過以上 2 步操作,我們就成功建立出了 libmymath.a 靜態鏈結庫。那麼,該如何使用它呢?

靜態鏈結庫的使用很簡單,就是在程式的鏈結階段,將靜態鏈結庫和其他目標檔案一起執行鏈結操作,從而生成可執行檔案。

以 demo 專案為例,首先我們將 main.c 檔案編譯為目標檔案:

其中,-l(大寫的 l)選項用於向 gcc 編譯器指明靜態鏈結庫的儲存位置(可以借助 pwd 指令檢視具體的儲存位置); -l(小寫的 l)選項用於指明所需靜態鏈結庫的名稱,注意這裡的名稱指的是 *** 部分,且建議將 -l 和 *** 直接連用(即 -l***),中間不需有空格。

注意 需要提前安裝靜態庫(若是centos系統 命令:yum install glibc-static)

由此,就生成了 a.out 可執行檔案:

動態庫:

demo1 專案(乙個 c 語言多檔案專案)與上述demo原始碼相同

gcc -fpic -shared 源檔名... -o 動態鏈結庫名

其中,-shared 選項用於生成動態鏈結庫;-fpic(還可寫成 -fpic)選項的功能是,令 gcc 編譯器生成動態鏈結庫(多個目標檔案的壓縮包)時,表示各目標檔案中函式、類等功能模組的位址使用相對位址,而非絕對位址。這樣,無論將來鏈結庫被載入到記憶體的什麼位置,都可以正常使用。

例如,由 demo 專案中的 add.c、sub.c 和 div.c 這 3 個原始檔生成乙個動態鏈結庫,執行命令為:

注意,動態鏈結庫的命令規則和靜態鏈結庫完全相同,只不過在 linux 發行版系統中,其字尾名用 .so 表示;windows 系統中,字尾名為 .dll。

2) 先使用 gcc -c 指令將指定原始檔編譯為目標檔案。仍以 demo 專案中的 add.c、sub.c 和 div.c 為例,先執行如下命令:

以上 2 種操作,生成的動態鏈結庫是完全一樣的,任選一種即可。

通過前面章節的學習我們知道,動態鏈結庫的使用場景就是和專案中其它原始檔或目標檔案一起參與鏈結。以 demo 專案為例,前面我們將 add.c、sub.c 和 div.c 打包到了 libmymath.so 動態鏈結庫中,此時該專案中僅剩 main.c 源程式檔案,因此執行 demo 專案也就演變成了將 main.c 和 libmymath.so 進行鏈結,進而生成可執行檔案。

注意,test.h 標頭檔案並不直接參與編譯,因為在程式的預處理階段,已經對專案中需要用到的標頭檔案做了處理。

注意,生成的 main 通常無法直接執行,例如:

可以看到,執行過程中無法找到 libmymath.so 動態鏈結庫。通過執行ldd main指令,可以檢視當前檔案在執行時需要用到的所有動態鏈結庫,以及各個庫檔案的儲存位置:

可以看到,main檔案的執行需要 4 個動態鏈結庫的支援,其中就包括 libmymath.so,但該檔案無法找到,因此 main執行會失敗。

執行由動態鏈結庫生成的可執行檔案時,必須確保程式在執行時可以找到這個動態鏈結庫。常用的解決方案有如下幾種:

本作業系統(centos 6.5 64 位)中,只需要將 libmymath.so 庫檔案移動 /usr/lib64 或者 /lib64 目錄下,即可使 main.exe 成功執行:

main即可執行 

linux 下靜態庫和動態庫

我們通常把一些公用函式製作成函式庫,供其它程式使用。函式庫分為靜態庫和動態庫兩種。靜態庫在程式編譯時會被連線到目標 中,程式執行時將不再需要該 靜態庫。動態庫在程式編譯時並不會被連線到目標 中,而是在程式執行是才被載入,因此在程式執行時還需要動態庫存在。本文主要通過舉例來說明在 linux中如何建立...

linux下的靜態庫和動態庫

庫是什麼?在我們實際程式設計中,經常會引入各種庫函式,那麼庫是什麼?從本質上來說是一種可執行 的二進位制格式,可以被載入記憶體中執行。庫分靜態庫和動態庫兩種。靜態庫 linux下靜態庫的名字一般是lib a,為庫的名字。利用靜態函式庫編譯成的檔案比較大,因為整個函式庫的所有資料都會被整合進目標 中,...

linux下的靜態庫和動態庫

意義 為了避免 的重寫率,我們可以將已經寫好的 形成乙個庫,當我們再次用到的時候可以直接呼叫,而不是重新去寫,即 站在巨人的肩膀上 linux下有兩種庫 一 靜態庫 準備工作 int swap int x,int y include int main 1 將我們需要的函式生成乙個.o 檔案 root...