關於靜態庫的連線問題

2021-08-20 11:34:05 字數 2713 閱讀 6862

如果想理解大型程式的構建必須完全理解linker階段到底做了哪些工作;一下拋磚引玉,一些個人的理解。
提前知識:linxu下目標檔案格式(elf):

1.可重定位目標檔案; //你可以暫時理解為通常說的.o

2.可執行目標檔案; //你可以單純的理解為.exe

3.共享庫;

首先對於基本的程式編譯步驟大致可以分為如下:

比如正常編譯乙個a.c檔案:

gcc -c a.c // 產生a.o

gcc -o a a.o // 產生a(elf)

預編譯:

cpp a.c a.i; //簡單的巨集替換;

編譯: //將進行巨集替換之後的檔案轉換成特定的彙編檔案;

cc1 a.i -o a.s

彙編:as -o main.o main.s //將彙編好的檔案轉化成對應的.o格式檔案;//主要是為了連線程式便利。

連線:(簡單的說就是將一堆.o 生成.a .so 或者.out分別對應靜態庫動態庫以及可執行檔案)

假設有如下三個 a.o , b.o, c.o; main.o(使用a.o , b.o, c.o,並且由主入口函式,也就是所謂的main)則對應的編譯

main: gcc -wall -g -o  main  main.o a.o b.o c.o

; //-g指示可調式, -wall指示出錯顯示更多錯誤資訊;

lib.a: ar rcs a.o b.o c.o

; lib.so:

//注意編譯.so的時候一定需要帶的-fpic選項

gcc -g -c -fpic -wall a.c b.c c.c

gcc -g -c -shared -o libfoo.so a.o b.o c.o

注:還需要掌握的是elf檔案格式:

![這裡寫描述](

至於各個節的意義需要自己掌握,對於理解程式的編譯執行包括庫的製作都很重要。

理解elf檔案格式之後:

對應的每一節都是os所說的符號表示,也就是讓os或者在連線時候可以通過制定的符號,找到你想要的資訊:

符號主要分為如下三類:

1. 全域性(全域性函式 以及 變數)

2 . 區域性(static定義的函式以及變數,僅供內部呼叫)

3. 外部 (供外部呼叫的函式)

linux下靜態庫主要的好處就是盡可能的減少了**所佔磁碟 記憶體的空間,最簡單的例子就是比如c語言所定義的一大堆標準庫,你在實際的編譯的時候,你的可執行**都會把你所引用的標準庫中所有函式加進去即使你只用到了乙個,靜態庫由此而生,其實也就是對應符號的外部引用;

比如如下過程:

gcc -c a.c b.c

ar rcs lib.a a.o b.o ; // 生成.a

gcc -o main main.o lib.a // main.c 呼叫lib.a

聯結器主要完成的工作如下:(姑且把main稱作目標檔案, lib.a稱為儲存文件)

link解析時主要有如下三個集合:

e: 存放用於生成最後可執行檔案的 符號集合;

u:(引用但尚未定義的符號集合)

d:(支援外部引用的符號集合)

在執行上述操作的時,主要完成以下,link從左往右讀取main.o發現是目標檔案,則將其存放入e集合中,並且把引用尚未定義的放入結合u中,以及定義的放入d中,接著掃瞄lib.a,把支援外部引用的部分放到d中,並與e中相比較,如果出現引用但尚未定義的,則把lib.a中的相應符號部分放入e中捨去其餘的部分,這樣就起到了只複製呼叫部分。

也正是因為執行流程如下,所以需要特別注意編譯連線時候的檔案的順序,如果把a依賴於b則必須把b放在後面,如果把b放在了前面則會導致u集合為空,而後面再匯入a的時候出現undefined reference的錯誤。

特獻上全部流程:

a.cpp內容如下:

int atime = 0;

int sum(int a,int b)

b.cpp內容:

int btime = 0;

int sum_func(int a,int b)

func.h內容:

extern

int sum(int a,int b);

extern

int sum_func(int a,int b);

main.c內容:

#include

#include"func.h"

using

std::cout;

using

std::endl;

int main()

編譯過程:

g++ -c a.cpp b.cpp

g++ -c main.cpp

ar src libsum.a a.o b.o

g++ -static -o main main.o libsum.a

//g++ -static -o main libsum.a main.o

會出現如下問題:

unrefernced defined function: sum, sum_func;

![這裡寫描述](

生成動態連線庫 靜態連線庫的 makefile

靜態連線庫 擴充套件名為 a 是.o檔案的簡單集合。在 linux unix下,使用 ar 命令生成靜態連線庫。動態連線庫 擴充套件名為.so 是將.o檔案集合,並增加了匯出表。匯出表是乙個函式名 函式索引 函式位址的陣列。因此,應用程式可以裝載 使用 ldopen函式 後,根據函式名,匯出函式的索...

關於java資料庫連線的問題

下面是以後可能用到的資料庫方面的知識,覺得還不錯 1.mysql drivername的值為 com.mysql.jdbc.driver url的值為 jdbc mysql localhost 3306 hibernate其中hibernate是你的資料庫名稱 2.sqlserver drivern...

Windows庫連線之靜態庫

庫連線分為動態庫和靜態庫。靜態庫還是比較容易的。首先定義標頭檔案,標頭檔案中宣告函式,可以用extern c 來標註c風格函式。然後就寫具體的原始檔,寫出具體 最後編譯生成.lib檔案。呼叫靜態庫的時候,將.lib檔案和標頭檔案新增到工程中即可。靜態庫中沒有dll檔案,而動態庫中有。動態庫更適合多工...