1. 程式人生 > >Linux中,.a和.so,其實就是靜態連結庫與動態連結庫

Linux中,.a和.so,其實就是靜態連結庫與動態連結庫

詳細查了一下,.a與.so的區別,其實就是靜態連結庫與動態連結庫。有一篇博文,很詳細,附上鍊接:http://blog.csdn.net/nieyinyin/article/details/6890557

  Linux下的.so是基於Linux下的動態連結,其功能和作用類似與windows下.dll檔案。

  下面是關於.so的介紹:

一、引言

  通常情況下,對函式庫的連結是放在編譯時期(compile time)完成的。所有相關的物件檔案(object file)與牽涉到的函式庫(library)被連結合成一個可執行檔案(executable file)。程式在執行時,與函式庫再無瓜葛,因為所有需要的函式已拷貝到自己門下。所以這些函式庫被成為靜態庫(static libaray),通常檔名為“libxxx.a”的形式。

  其實,我們也可以把對一些庫函式的連結載入推遲到程式執行的時期(runtime)。這就是如雷貫耳的動態連結庫(dynamic link library)技術。

二、動態連結庫的特點與優勢

  首先讓我們來看一下,把庫函式推遲到程式執行時期載入的好處:

  1. 可以實現程序之間的資源共享。

  什麼概念呢?就是說,某個程式的在執行中要呼叫某個動態連結庫函式的時候,作業系統首先會檢視所有正在執行的程式,看在記憶體裡是否已有此庫函式的拷 貝了。如果有,則讓其共享那一個拷貝;只有沒有才連結載入。這樣的模式雖然會帶來一些“動態連結”額外的開銷,卻大大的節省了系統的記憶體資源。C的標準庫 就是動態連結庫,也就是說系統中所有執行的程式共享著同一個C標準庫的程式碼段。

  2. 將一些程序升級變得簡單。使用者只需要升級動態連結庫,而無需重新編譯連結其他原有的程式碼就可以完成整個程式的升級。Windows 就是一個很好的例子。

  3. 甚至可以真正坐到連結載入完全由程式設計師在程式程式碼中控制。

  程式設計師在編寫程式的時候,可以明確的指明什麼時候或者什麼情況下,連結載入哪個動態連結庫函式。你可以有一個相當大的軟體,但每次執行的時候,由於 不同的操作需求,只有一小部分程式被載入記憶體。所有的函式本著“有需求才調入”的原則,於是大大節省了系統資源。比如現在的軟體通常都能開啟若干種不同類 型的檔案,這些讀寫操作通常都用動態連結庫來實現。在一次運行當中,一般只有一種型別的檔案將會被開啟。所以直到程式知道檔案的型別以後再載入相應的讀寫 函式,而不是一開始就將所有的讀寫函式都載入,然後才發覺在整個程式中根本沒有用到它們。

三、動態連結庫的建立

  由於動態連結庫函式的共享特性,它們不會被拷貝到可執行檔案中。在編譯的時候,編譯器只會做一些函式名之類的檢查。在程式執行的時候,被呼叫的動態 連結庫函式被安置在記憶體的某個地方,所有呼叫它的程式將指向這個程式碼段。因此,這些程式碼必須實用相對地址,而不是絕對地址。在編譯的時候,我們需要告訴編 譯器,這些物件檔案是用來做動態連結庫的,所以要用地址不無關程式碼(Position Independent Code (PIC))。

  對gcc編譯器,只需新增上 -fPIC 標籤,如:

  gcc -fPIC -c file1.c   gcc -fPIC -c file2.c   gcc -shared libxxx.so file1.o file2.o

  注意到最後一行,-shared 標籤告訴編譯器這是要建立動態連結庫。這與靜態連結庫的建立很不一樣,後者用的是 ar 命令。也注意到,動態連結庫的名字形式為 “libxxx.so” 字尾名為 “.so”

四、動態連結庫的使用

a.隱式呼叫 (靜態庫與此相同的方式)

  使用動態連結庫,首先需要在編譯期間讓編譯器檢查一些語法與定義。

  這與靜態庫的實用基本一樣,用的是 -Lpath 和 -lxxx 標籤。如:

  gcc file1.o file2.o -Lpath -lxxx -o program.exe

  編譯器會先在path資料夾下搜尋libxxx.so檔案,如果沒有找到,繼續搜尋libxxx.a(靜態庫)。

  在程式執行期間,也需要告訴系統去哪裡找你的動態連結庫檔案。在UNIX下是通過定義名為 LD_LIBRARY_PATH 的環境變數來實現的。只需將path賦值給此變數即可。csh 命令為:

  setenv LD_LIBRARY_PATH   your/full/path/to/dll

  一切安排妥當後,你可以用 ldd 命令檢查是否連線正常。

  ldd program.exe

動態連結庫*.so的編譯與使用

b.顯示呼叫:

  這種方式更加靈活。在程式碼中需要呼叫的地方使用 #include <dlfcn.h>這個標頭檔案中的以下函式來呼叫:

void  *dlopen(const char *, int);
void  *dlsym(void *, const char *);
int    dlclose(void *);
char  *dlerror(void);