天天看點

老生常談--關于Linux下編譯和使用動态連結庫靜态連結庫

一、基本概念

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

繼續閱讀