一、基本概念
1.1什麼是庫 在windows平台和linux平台下都大量存在着庫。 本質上來說庫是一種可執行代碼的二進制形式,可以被作業系統載入記憶體執行。由于windows和linux的平台不同(主要是編譯器、彙編器和連接配接器的不同),是以二者庫的二進制是不相容的。本文僅限于介紹linux下的庫。
1.2庫的種類 linux下的庫有兩種:靜态庫和共享庫(動态庫)。二者的不同點在于代碼被載入的時刻不同。 靜态庫的代碼在編譯過程中已經被載入可執行程式,是以體積較大。共享庫的代碼是在可執行程式運作時才載入記憶體的,在編譯過程中僅簡單的引用,是以代碼體積較小。
1.3庫存在的意義庫是别人寫好的現有的,成熟的,可以複用的代碼,你可以使用但要記得遵守許可協定。現實中每個程式都要依賴很多基礎的底層庫,不可能每個人的代碼都從零開始,是以庫的存在意義非同尋常。共享庫的好處是,不同的應用程式如果調用相同的庫,那麼在記憶體裡隻需要有一份該共享庫的執行個體.
1.4庫檔案是如何産生的在linux下靜态庫的字尾是.a,它的産生分兩步 Step1.由源檔案編譯生成一堆.o,每個.o裡都包含這個編譯單元的符号表;Step2.ar指令将很多.o轉換成.a,成為靜态庫動态庫的字尾是.so,它由gcc加特定參數編譯産生。具體方法參見後文執行個體。
1.5庫檔案是如何命名的,有沒有什麼規範在linux下,庫檔案一般放在/usr/lib和/lib下,靜态庫的名字一般為libxxxx.a,其中xxxx是該lib的名稱 動态庫的名字一般為libxxxx.so.major.minor,xxxx是該lib的名稱,major是主版本号,minor是副版本号.
1.6如何知道一個可執行程式依賴哪些庫 ldd指令可以檢視一個可執行程式依賴的共享庫,例如#ldd/bin/lnlibc.so.6=>/lib/libc.so.6(0×40021000)/lib/ld-linux.so.2=>/lib/ld-linux.so.2(0×40000000)可以看到ln指令依賴于libc庫和ld-linux庫
1.7可執行程式在執行的時候如何定位共享庫檔案
當系統加載可執行代碼時候,能夠知道其所依賴的庫的名字,但是還需要知道絕對路徑。此時就需要系統動态載入器(dynamiclinker/loader) 對于elf格式的可執行程式,是由ld-linux.so*來完成的,它先後搜尋elf檔案的DT_RPATH段—環境變量LD_LIBRARY_PATH—/etc/ld.so.cache檔案清單—/lib/,/usr/lib目錄找到庫檔案後将其載入記憶體 如:exportLD_LIBRARY_PATH=’pwd’将目前檔案目錄添加為共享目錄
1.8在新安裝一個庫之後如何讓系統能夠找到他如果安裝在/lib或者/usr/lib下,那麼ld預設能夠找到,無需其他操作。如果安裝在其他目錄,需要将其添加到/etc/ld.so.cache檔案中,步驟如下1.編輯/etc/ld.so.conf檔案,加入庫檔案所在目錄的路徑2.運作ldconfig,該指令會重建/etc/ld.so.cache檔案
二代碼示例:
2.1準備好測試代碼hello.h、hello.c和main.c;
hello.h(見程式1)為該函數庫的頭檔案。
hello.c(見程式2)是函數庫的源程式,其中包含公用函數hello,該函數将在螢幕上輸出"Hello XXX!"。
main.c(見程式3)為測試庫檔案的主程式,在主程式中調用了公用函數hello。
程式1: hello.h
#ifndef HELLO_H #define HELLO_H void hello(const char *name); #endif |
程式2:hello.c
#include <stdio.h> void hello(const char *name) { printf("Hello %s!\n", name); } |
程式3:main.c
#include "hello.h" int main() { hello("everyone"); return 0; } |
代碼很簡單,然後就開始編譯了。
2.2編譯和使用Linux靜态庫檔案
2.1.1編譯靜态庫
首先将.c檔案編譯成二進制檔案:
# gcc -c hello.c
現在目錄下應該有如下檔案:
将.o檔案轉化為靜态連結庫的的.a檔案:
#ar rcs libmyhello.a hello.o
2.1.2使用靜态連結庫:
将hello.h,main.c,libmyhello.a三個問價,拷貝到一個新的目錄下,這裡我們可以看到hello.c檔案已經被棄用了,然後使用如下指令編譯可執行檔案main.c并執行以下如下:
# gcc-o hello main.c -static -L. -lmyhello
#./hello
Helloeveryon
說明:gcc會在靜态庫名前加上字首lib,然後追加擴充名.a得到的靜态庫檔案名來查找靜态庫檔案,是以,我們在寫需要連接配接的庫時,隻寫名字就可以,如libmyhello.a的庫,隻寫:-lmyhello
2.1.1編譯東态庫
首先将.c檔案編譯成二進制檔案:
gcc -c -fPIC hello.c
現在目錄下應該有如下檔案:
将.o檔案轉化為動态連結庫的的.so檔案:
gcc -shared -fPIC -o libmyhello.so hello.o
2.1.2使用靜态連結庫:
将hello.h,main.c,libmyhello.a三個問價,拷貝到一個新的目錄下,這裡我們可以看到hello.c檔案已經被棄用了,然後使用如下指令編譯可執行檔案main.c并執行以下如下:
# gcc-o hello main.c -static -L. -lmyhello
#./hello
但是出現如下報錯:
./hello: error while loading shared libraries: libmyhello.so: cannot open shared object file: No such file or directory
錯誤提示,找不到動态庫檔案libmyhello.so。程式在運作時,會在/usr/lib和/lib等目錄中查找需要的動态庫檔案。若找到,則載入動态庫,否則将提示類似上述錯誤而終止程式運作。有多種方法可以解決,
(1)我們将檔案 libmyhello.so複制到目錄/usr/lib中,再試試。
# mv libmyhello.so /usr/lib
# ./hello
成功!
(2)既然連接配接器會搜尋LD_LIBRARY_PATH所指定的目錄,那麼我們可以将這個環境變量設定成目前目錄:
先執行:
export LD_LIBRARY_PATH=$(pwd)
再執行:
./hello
成功!
(3)執行:
ldconfig /usr/zhsoft/lib
注: 當使用者在某個目錄下面建立或拷貝了一個動态連結庫,若想使其被系統共享,可以執行一下"ldconfig 目錄名"這個指令.此指令的功能在于讓ldconfig将指定目錄下的動态連結庫被系統共享起來,意即:在緩存檔案/etc/ld.so.cache中追加進指定目錄下的共享庫.本例讓系統共享了/usr/zhsoft/lib目錄下的動态連結庫.該指令會重建/etc/ld.so.cache檔案。
參考:
http://blog.csdn.net/jiayouxjh/article/details/7602729
http://wenku.baidu.com/view/7d8602b265ce050877321301.html