1. 程式人生 > >Linux中的原始檔、目標檔案、庫檔案

Linux中的原始檔、目標檔案、庫檔案

在說明Linux的.a、.so和.o檔案關係之前,先來看看windows下obj,lib,dll,exe的關係

 

windows下obj,lib,dll,exe的關係

    lib是和dll對應的。lib是靜態連結庫的庫檔案,dll是動態連結庫的庫檔案。 
    所謂靜態就是link的時候把裡面需要的東西抽取出來安排到你的exe檔案中,以後執行你的exe的時候不再需要lib。
    所謂動態就是exe執行的時候依賴於dll裡面提供的功能,沒有這個dll,你的exe無法執行。 
    
    lib,dll,exe都算是最終的目標檔案,是最終產物。而c/c++屬於原始碼。原始碼和最終目標檔案中過渡的就是中間程式碼obj,實際上之所以需要中間程式碼,是你不可能一次得到目標檔案。比如說一個exe需要很多的cpp檔案生成。而編譯器一次只能編譯一個cpp檔案。這樣編譯器編譯好一個cpp以後會將其編譯成obj,當所有必須要的cpp都編譯成obj以後,再統一link成所需要的exe,應該說缺少任意一個obj都會導致exe的連結失敗。
    
    1.obj裡存的是編譯後的程式碼跟資料,並且有名稱,所以在連線時有時會出現未解決的外部符號的問題。當連成exe後便不存在名稱的概念了,只有地址。lib就是一堆obj的組合。
    2.理論上可以連線obj檔案來引用其他工程(可以認為一個obj檔案等價於編譯生成它的cpp檔案,可以引用obj來替換cpp,也可以新增cpp來替換obj ),但實際中通常用lib來實現工程間相互引用。
    3.編譯器會預設連結一些常用的庫,其它的需要你自己指定。
    
lib和DLL的區別

    (1)lib是編譯時需要的,dll是執行時需要的。如果要完成原始碼的編譯,有lib就夠了。如果也使動態連線的程式執行起來,有dll就夠了。在開發和除錯階段,當然最好都有。
    (2) 一般的動態庫程式有lib檔案和dll檔案。lib檔案是必須在編譯期就連線到應用程式中的,而dll檔案是執行期才會被呼叫的。如果有dll檔案,那麼對應的lib檔案一般是一些索引資訊,具體的實現在dll檔案中。如果只有lib檔案,那麼這個lib檔案是靜態編譯出來的,索引和實現都在其中。 靜態編譯的lib檔案有好處:給使用者安裝時就不需要再掛動態庫了。但也有缺點,就是導致應用程式比較大,而且失去了動態庫的靈活性,在版本升級時,同時要釋出新的應用程式才行。
    (3)在動態庫的情況下,有兩個檔案,一個是引入庫(.LIB)檔案(實際上也算是一個靜態庫,只是在連結時只能把函式在DLL的入口連結到exe中,而不像真正靜態連結庫那樣將函式體真正連結到exe中 ,通過lib進行的動態連結實際上也使用了靜態連結來實現 ),一個是DLL檔案,引入庫檔案包含被DLL匯出的函式的名稱和位置,DLL包含實際的函式和資料,應用程式使用LIB檔案連結到所需要使用的DLL檔案,庫中的函式和資料並不複製到可執行檔案中,因此在應用程式的可執行檔案中,存放的不是被呼叫的函式程式碼,而是DLL中所要呼叫的函式的記憶體地址,這樣當一個或多個應用程式執行是再把程式程式碼和被呼叫的函式程式碼連結起來,從而節省了記憶體資源。從上面的說明可以看出,DLL和.LIB檔案必須隨應用程式一起發行,否則應用程式將會產生錯誤。

DLL內的函式分為兩種: 
    (1)DLL匯出函式,可供應用程式呼叫;
    (2)DLL內部函式,只能在DLL程式使用,應用程式無法呼叫它們

建立靜態連結庫和建立動態連結庫

    VC6中建立[Win32 Dynamic-Link Library]工程便可以創建出一個空的DLL工程.

    VC6中建立[Win32 Static Library]工程便可以創建出一個空的LIB工程(靜態連結庫工程,僅生成一個lib檔案).

新增lib檔案的常用辦法有二個: 
    1、把*.lib放在VC的Lib目錄中 
    2、修改project setting的Link->Input中的Addtional library path,加入你的目錄dll:是可實際執行的二進位制程式碼,有定位程式碼的!

    3、也可以在object/library中直接寫上lib檔案路徑.(這裡實際上是可以寫上任意obj檔案或者lib檔案的).

 

 

 

linux .o,.a,.so

        .o,是目標檔案,相當於windows中的.obj檔案 

  .so 為共享庫,是shared object,用於動態連線的,相當於windows下的dll 

  .a為靜態庫,是好多個.o合在一起,用於靜態連線 

 

靜態函式庫
特點:實際上是簡單的普通目標檔案的集合,在程式執行前就加入到目標程式中。
優點:可以用以前某些程式相容;描述簡單;允許程式設計師把程式link起來而不用重新編譯程式碼,節省了重新編譯程式碼的時間(該優勢目前已不明顯);開發者可以對原始碼保密;理論上使用ELF格式的靜態庫函式生成的程式碼可以比使用共享或動態函式庫的程式執行速度快(大概1%-5%)
生成:使用ar程式(archiver的縮寫)。ar rcs my_lib.a f1.o f2.o是把目的碼f1.o和f2.o加入到my_lib.a這個函式庫檔案中(如果my_lib.a不存在則建立)
使用:用gcc生成可執行程式碼時,使用-l引數指定要加入的庫函式。也可以用ld命令的-l和-L引數。
 
共享函式庫
    共享函式庫在可執行程式啟動的時候載入,所有程式重新執行時都可自動載入共享函式庫中的函式。.so檔案感覺很複雜,光是命名規則就已經看得我很暈了~整理一下,共享庫需要:soname、real name,另外編譯的時候名字也有說法。依次解釋下:
soname:必須的格式:lib+函式庫名+.so+版本號資訊(但是記住,非常底層的C庫函式都不是以lib開頭命名的)。例子:/usr/lib/libreadline.so.3
real name:顧名思義是真正的名字啦,有主版本號和發行版本號。但是沒找到例項……
編譯器編譯的時候需要的函式庫的名字就是不包含版本號資訊的soname,例如上面的例子把最後的.3去掉就可以了。
位置:共享函式庫檔案必須放在特定目錄,對於開放原始碼來說,GNU標準建議所有的函式庫檔案都放在/usr/local/lib目錄下,而且建議命令、可執行程式都放在/usr/local/bin目錄下。不過這個只是習慣啦,可以改變,具體的位置資訊可以看/etc/ld.so.conf裡面的配置資訊。當然,也可以修改這個檔案,加入自己的一些特殊的路徑要求。