如果想理解大型程式的構建必須完全理解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檔案,而動態庫中有。動態庫更適合多工...