天天看點

linux下lib說明

linux下lib說明

說明:本文是自己對以前學習的一個總結,并提供了例子代碼(包括靜态庫、共享庫、動态加載共享庫)下載下傳,下載下傳位址:

  http://pickup.mofile.com/0760747733420493

一、lib類型:

  與windows下靜态庫(.lib)和動态庫(.dll)一樣,linux同樣存在靜态庫(static library 檔案字尾為.a)和共享庫(shared library 檔案字尾為.so),在/usr/lib目錄下同時存在一個庫的靜态版本和動态版本。

  "An archive (or static library) is simply a collection of object files stored as a single file.

When you provide an archive to the linker, the linker searches the archive for the object files

it needs, extracts them, and links them into your program much as if you had provided those

object files directly."

  "A shared library is similar to a archive in that it is a grouping of object files. However,

there are many important differences.The most fundamental difference is that when a shared library is

linked into a program, the final executable does not actually contain the code that is

present in the shared library. Instead, the executable merely contains a reference to the

shared library."

  "the object files that compose the shared library are combined into a

single object file so that a program that links against a shared library always includes all

of the code in the library, rather than just those portions that are needed."

  以上引自《Advanced Linux Programming》

  由此可知,靜态庫和共享庫都是一個obj檔案的集合,但靜态連結後,執行程式中存在自己所需obj的一份拷貝,而動态連結後,執行程式僅僅是包含對共享庫的一個引用。共享庫相當于一個由多個obj檔案組合而成的obj檔案,在連結後其所有代碼被加載,不管需要的還是不需要的。

似乎可以得出一個結論:

  靜态連結後的程式比動态連結的所用存儲空間大,因為執行程式中包含了庫中代碼拷貝;

  而動态連結的程式比靜态連結的所用的運作空間大,因為它将不需要的代碼也加載到運作空間。

二、lib編譯:

靜态庫的編譯,實際上是一個将.o檔案打包的過程。

  ar -rc libfunc.a func1.o func2.o  # 将f1.o、f2.o編譯成靜态庫libfunc.a

動态庫的編譯,使用gcc -fPIC -shared編譯選項。

  gcc -fPIC -shared -o libfunc.so func1.o func2.o # 将f1.o、f2.o編譯成動态庫libfunc.so

三、lib調用:

靜态庫的調用比較簡單,跟标準庫函數調用一樣

一個例子:main.c調用./lib目錄下libfunc.a庫,該庫頭檔案在./inc目錄下,編譯:

  gcc -o test main.c -I./inc -L./lib -lfunc

共享庫的調用需要注意庫檔案放置位置,如果該庫檔案不在/lib、/usr/lib下,則需要設定LD_LIBRARY_PATH變量。

一個例子:main.c調用./lib目錄下libfunc.so庫,該庫頭檔案在./inc目錄下,如果使用編譯:

  gcc -o test main.c -I./inc -L./lib -lfunc

  ./test # 運作錯誤:error while loading shared libraries: libfunc.so

  這是因為動态連結時程式隻是存放共享庫的名稱而不是絕對路徑,是以運作時我們需要先設定該庫所處位置:

  export LD_LIBRARY_PATH=./lib

  ./test # 運作成功

動态裝載共享庫:在隻有共享庫而沒有庫的頭檔案,或者你想在運作時動态加載、解除安裝庫時,linux的dl庫函數:dlopen、dlclose、dlsym幫你辦到,其相當于windows下LoadLibrary、FreeLibrary、GetProcAddress函數

函數原型:

       void *dlopen(const char *filename, int flag);

       void *dlsym(void *handle, char *symbol);

       int dlclose(void *handle);

一個例子:main.c動态裝載./lib目錄下libfunc.so庫,庫中有一個函數void print_str(const char*);

       void *handle = dlopen("libfunc.so", RTLD_LAZY);

       void (*pt_str)(const char*);

       pt_str = dlsym(handle, "print_str");

       pt_str("hello world.");

       dlclose(handle);

四、相關說明:

1、共享庫特别适合多個程式共享代碼,更新程式部分功能子產品,實作程式“插件”功能的情況;

   而靜态庫是一勞永逸,編譯後不需要帶一堆庫檔案跑,而且不管放置到哪裡都可正常運作。

2、當搜尋的庫檔案目錄下同時存在該庫的靜态版本和共享版本時,連結器優先使用共享版本.so,此時你可以使用-static連結選項指定連結靜态版本.a。

3、動态庫可以導出兩個特殊的函數:_init和_fini,前者在動态庫被加載後調用,後者在動态庫被解除安裝前調用,

我們可以使用這兩個函數做些特别的工作。需要注意的是:在定義這兩個函數後編譯時,需要使用

-nostartfiles選項,否則編譯器報重複定義錯誤。

4、ldd指令用來檢視程式所依賴的共享庫,同時也友善我們判斷共享庫是否被找到;

   nm指令檢視obj檔案(.so也是一個obj)中的辨別(函數、變量)。

繼續閱讀