通過《gcc使用靜態鏈結庫和動態鏈結庫》一節的學習,讀者已經了解了什麼是庫檔案、什麼是靜態鏈結庫和動態鏈結庫以及它們之間的區別。同時文章中還提到,在 c、c++ 實際開發過程中,除了可以使用系統庫檔案外,我們還可以根據實際需要,手動建立靜態鏈結庫或者動態鏈結庫。
假設當前有乙個 c 語言專案,其目錄結構如下所示:
demo專案
├─ headers
│ └─ test.h
└─ sources
├─ add.c
├─ sub.c
├─ div.c
└─ main.c
其中,headers 用於表示該專案擁有的所有標頭檔案;sources 表示該專案擁有的所用原始檔,讀者可按照此目錄結構構建 demo 專案,也可以將所有檔案統一放置在 demo 專案下,本節選擇的是後者,即將所有檔案統一放置在 demo 目錄下。
可以看到,該專案中包含 1 個頭檔案( .h ),4 個原始檔( .c ),它們各自包含的**如下所示:
[root@bogon demo]# ls
add.c div.c main.c sub.c test.h
[root@bogon demo]# cat test.h
#ifndef __test_h_
#define __test_h_
int add(int a,int b);
int sub(int a,int b);
int div(int a,int b);
#endif
[root@bogon demo]# cat add.c
#include 「test.h」
int add(int a,int b)
return a + b;
[root@bogon demo]# cat sub.c
#include 「test.h」
int sub(int a,int b)
return a - b;
[root@bogon demo]# cat div.c
#include 「test.h」
int div(int a,int b)
return a / b;
[root@bogon demo]# cat main.c
#include
#include "test.h" //必須引入標頭檔案
int main(void)
int m, n;
printf("input two numbers: ");
scanf("%d %d", &m, &n);
printf("%d+%d=%d\n", m, n, add(m, n));
printf("%d-%d=%d\n", m, n, sub(m, n));
printf("%d÷%d=%d\n", m, n, div(m, n));
return 0;
[root@bogon demo]#
整個專案的邏輯很簡單,其中 add.c、sub.c 和 div.c 這 3 個檔案中各包含乙個函式,分別實現將兩個整數做相加、相減和除法操作,而 test.h 僅包含這 3 個函式的宣告部分,main.c 是主程式檔案,其通過引入 test.h 標頭檔案呼叫了 3 個函式,從而分別完成了對使用者輸入的 2 個整數做相加、相減以及除法操作。
對於編譯、執行 demo 專案,我們可以直接使用 gcc 命令完成:
[root@bogon demo]# gcc main.c add.c sub.c div.c -o main.exe
[root@bogon demo]# ls
add.c div.c main.c main.exe sub.c test.h
[root@bogon demo]# ./main.exe
input two numbers: 10 2
10+2=12
10-2=8
10÷2=5
[root@bogon demo]#
注意,由於在程式預處理階段,gcc 編譯器會自行處理各個 .c 檔案內部引入的 .h 標頭檔案(將 .h 檔案中的**直接拷貝到當前 .c 原始檔中),因此編譯執行 demo 專案時,我們只需要提供所有的原始檔即可,不需要處理標頭檔案。
注意,add.c、sub.c 和 div.c 這 3 個檔案,其包含的都是一些功能模組(實現具體功能的函式),對於這樣的原始檔,只要我們願意共享,每個人都可以直接用到自己的專案中。這就產生乙個問題,如果僅希望別人使用我們實現的功能,但又不想它看到具體實現的原始碼,該怎麼辦呢?很簡單,就是將它們加工成乙個靜態鏈結庫。
靜態鏈結庫的建立
原始檔中只提供可以重複使用的**,例如函式、設計好的類等,不能包含 main 主函式;
原始檔在實現具備模組功能的同時,還要提供訪問它的介面,也就是包含各個功能模組宣告部分的標頭檔案。
顯然對於 demo 專案中的 add.c、sub.c 以及 div.c 這 3 個原始檔來說,以上 2 個條件都符合,因此都可以被加工成靜態鏈結庫。並且根據實際需要,我們可以將它們集體壓縮到乙個靜態鏈結庫中,也可以各自壓縮成乙個靜態鏈結庫。
1) 將所有指定的原始檔,都編譯成相應的目標檔案:
[root@bogon demo]# gcc -c sub.c add.c div.c
[root@bogon demo]# ls
add.c add.o div.c div.o main.c sub.c sub.o test.h
ar rcs 靜態鏈結庫名稱 目標檔案1 目標檔案2 ...
lib***.a
linux 系統下,靜態鏈結庫的字尾名為 .a;windows 系統下,靜態鏈結庫的字尾名為 .lib。
其中,*** 代指我們為該庫起的名字,比如 linux 系統自帶的一些靜態鏈結庫名稱為 libc.a、libgcc.a、libm.a,它們的名稱分別為 c、gcc 和 m。
[root@bogon demo]# ar rcs libmymath.a add.o sub.o div.o
[root@bogon demo]# ls
add.c add.o div.c div.o libmymath.a main.c sub.c sub.o test.h
其中,libmymath.a 就是 add.o、sub.o 和 div.o 一起打包生成的靜態鏈結庫,mymath 是我們自定義的庫名。
通過以上 2 步操作,我們就成功建立出了 libmymath.a 靜態鏈結庫。那麼,該如何使用它呢?
靜態鏈結庫的使用
靜態鏈結庫的使用很簡單,就是在程式的鏈結階段,將靜態鏈結庫和其他目標檔案一起執行鏈結操作,從而生成可執行檔案。
以 demo 專案為例,首先我們將 main.c 檔案編譯為目標檔案:
[root@bogon demo]# gcc -c main.c
[root@bogon demo]# ls
add.c div.c libmymath.a main.osub.c
test.h add.o div.o main.c sub.o
[root@bogon demo]# gcc -static main.o libmymath.a
[root@bogon demo]# ls
add.c a.out div.o main.c sub.c test.h
add.o div.c libmymath.a main.o sub.o
其中,-static 選項強制 gcc 編譯器使用靜態鏈結庫。
[root@bogon demo]# gcc main.o -static -l /root/demo/ -lmymath
[root@bogon demo]# ls
add.c a.out div.o main.c sub.c test.h
add.o div.c libmymath.a main.o sub.o
其中,-l(大寫的 l)選項用於向 gcc 編譯器指明靜態鏈結庫的儲存位置(可以借助 pwd 指令檢視具體的儲存位置); -l(小寫的 l)選項用於指明所需靜態鏈結庫的名稱,注意這裡的名稱指的是 *** 部分,且建議將 -l 和 *** 直接連用(即 -l***),中間不需有空格。
由此,就生成了 a.out 可執行檔案:
[root@bogon demo]# ./a.out
input two numbers: 10 2
10+2=12
10-2=8
10÷2=5
動態鏈結庫 靜態鏈結庫
包含標頭檔案和庫 idir 指定編譯查詢標頭檔案的目錄,常用於查詢第三方的庫的標頭檔案,例 gcc test.c i.inc o test。ldir 指定鏈結時查詢lib的目錄,常用於查詢第三方庫。llibrary 指定額外鏈結的lib庫 巨集定義 dmacro 以字串 1 預設值 定義 macro...
靜態鏈結庫 動態鏈結庫
庫是寫好的現有的,成熟的,可以復用的 現實中每個程式都要依賴很多基礎的底層庫,不可能每個人的 都從零開始,因此庫的存在意義非同尋常。本質上來說庫是一種可執行 的二進位制形式,可以被作業系統載入記憶體執行。庫有兩種 靜態庫 a lib 和動態庫 so dll windows上對應的是.lib dll ...
靜態鏈結庫,動態鏈結庫
關於靜態鏈結庫,參考如下博文 當你完成了 開發,想把這個 給別人用,但是又不希望別人看到原始碼,就要給別人乙個庫和標頭檔案,庫和標頭檔案是配合的,缺一不可。或者過程相反,你從別人那裡拿到乙個庫和標頭檔案來使用。那麼如何編譯生成乙個庫給他人,如何使用從他人那裡拿到的庫呢?範例1 我們想把linuxfr...