天天看點

動态庫,靜态庫,LD_LIBRARY_PATH,LIBRARY_PATH,-L,-l

我們通常把一些公用函數制作成函數庫,供其它程式使用。函數庫分為靜态庫和動态庫兩種。

兩者對比:

動态庫 靜态庫
編譯時 不連接配接到目标代碼 連接配接到目标代碼
運作時 動态加載 不再需要(已經在目标代碼内)

動态庫的生成和使用,靜态庫的生成和使用

假如編寫一個數組相關的應用,大概代碼架構如下:

/home/xiantao/binarysearchtree/

▾arrdata/一個關于建立數組的函數包括建立數組和列印數組,被test.c使用

arr.c

arr.h

test.c

▾ taolib/自己的一個調試宏的實作,arr.h中會使用這個

maclib.h

這次就把arr.c中的函數當成我們要用的到庫,分别生成動态庫和靜态庫來使用。

靜态庫的生成和使用:

1.編寫源程式,上邊已經有了,包括arr.c,arr.h和test.c這三個檔案

下面是arr.h的内容

1 #ifndef_ARR_H_

2 #define_ARR_H_

3 #include"../taolib/maclib.h"

4 voidswap(DataType *a,DataType *b);

5 voidprintarr(DataType arr[],int len);

6 voidcreatearr(DataType arr[],int len);

7 #endif

2.編譯,将arr.c編譯成arr.o

[email protected]:~/binarysearchtree/arrdata$gcc -c arr.c此時生成arr.o

無論靜态庫,還是動态庫,都是由.o檔案建立的。是以,我們必須将源程式arr.c通過gcc先編譯成.o檔案。

3.由.o檔案建立靜态庫(.a)

[email protected]:~/binarysearchtree/arrdata$ar cr libarr.a arr.o此時生成libarr.a

靜态庫檔案名的命名規範是以lib為字首,緊接着跟靜态庫名,擴充名為.a。例如:我們将建立的靜态庫名為arr,則靜态庫檔案名就是libarr.a。在建立和使用靜态庫時,需要注意這點。建立靜态庫用ar指令。

第4步:在test.c中使用靜态庫

靜态庫制作完了,如何使用它内部的函數呢?隻需要在使用到這些公用函數的源程式中包含這些公用函數的原型聲明,然後在用gcc指令生成目标檔案時指明靜态庫名,gcc将會從靜态庫中将公用函數連接配接到目标檔案中。

[email protected]:~/binarysearchtree/arrdata$ls注意此時有libarr.a這個靜态庫,可以沒有arr.o

arr.c arr.h libarr.a test.c

編譯test.c檔案并測試

xiant[email protected]:~/binarysearchtree/arrdata$gcc -o test test.c -L. -larr (注意此時時arr,而不是libarr)

以下三種方式都行

[email protected]:~/binarysearchtree/arrdata$gcc -o test test.c./libarr.a

[email protected]:~/binarysearchtree/arrdata$gcc -o test test.c libarr.a

[email protected]:~/binarysearchtree/arrdata$gcc -o test test.c arr.a

[email protected]:~/binarysearchtree/arrdata$./test

9 4 0 1 8 19 19 10

-L訓示靜态庫的目錄,-l訓示靜态庫的名稱,如果把libarr.a移動到/usr/lib/下,就不用加-L選項了,編譯器會自動到那個目錄下找到。

回頭看以下,其實如果檔案夾下隻有三個檔案arr.c,arr.h和test.c,然後編譯:

[email protected]:~/binarysearchtree/arrdata$gcc arr.c test.c

測試也能成功。是以如果使用了靜态庫,我們隻需要一個test.c源檔案,在編譯階段加上靜态庫目錄和名稱就行;此時是在進行編譯的時候,并沒有編譯arr.c這個檔案,而隻是在連結階段使用到了libarr.a這個靜态庫。(不同于動态庫的使用,它是在運作時和arr.so進行綁定的)。假如在運作./test之前删除這個靜态庫也是能成功運作的。

動态庫到生成和使用:

1.源檔案準備,與上邊一樣

2.編譯生成arr.o

[email protected]:~/binarysearchtree/arrdata$ gcc-fPIC-c arr.c

如果在編譯arr.c成arr.o的時候沒有加上-fPIC這個選項,後面編譯生成動态庫時會出現以下這個錯誤:

/usr/bin/ld:arr.o: relocation R_X86_64_32 against `.rodata' can not be used whenmaking a shared object; recompile with -fPIC

arr.o: erroradding symbols: Bad value

collect2: error:ld returned 1 exit status

3.由.o檔案建立動态庫(.so)

[email protected]:~/binarysearchtree/arrdata$gcc -shared arr.o -o libarr.so

[email protected]:~/binarysearchtree/arrdata$ls

arr.c arr.h arr.o libarr.so test.c

  動态庫檔案名命名規範和靜态庫檔案名命名規範類似,也是在動态庫名增加字首lib,但其檔案擴充名為.so。例如:我們将建立的動态庫名為arr,則動态庫檔案名就是libarr.so。用gcc來建立動态庫。

也可以第二步第三步合起來編譯:

[email protected]:~/binarysearchtree/arrdata[master]$ gcc -shared -o libarr.so arr.c    (如果不加-fPIC選項會錯現下列錯誤)

/usr/bin/ld: /tmp/cce8PdBO.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC

/tmp/cce8PdBO.o: error adding symbols: Bad value

collect2: error: ld returned 1 exit status

正确編譯方式:

[email protected]:~/binarysearchtree/arrdata[master]$ gcc -shared -fPIC -o libarr.so arr.c

4編譯test.c,使用動态庫

xian[email protected]:~/binarysearchtree/arrdata$ gcc -o test test.c -L.-larr (和靜态庫使用一樣)

[email protected]:~/binarysearchtree/arrdata[master]$ gcc  test.c libarr.so -o test(也行)

測試運作:

[email protected]:~/binarysearchtree/arrdata$./test

./test: error whileloading shared libraries: libarr.so: cannot open shared object file:No such file or directory

發現提示找不到這個動态庫。其實linux上是有個預設到動态庫的/usr/lib和/lib。如果把剛剛生成到liarr.so移動到/usr/lib/或者/lib/在運作./test,成功.

方法二,就是可以設定環境變量的:LD_LIBRARY_PATH。隻要在這個變量中包含想要使用到動态庫的目錄就行。

方法三,修改/etc/ld.so.conf檔案,把該庫所在絕對路徑添加到檔案末尾,并執行ldconfig重新整理

方法四,在第四步編譯的時候,使用參數-Wl,-rpath參數告訴編譯器,在編譯生成test 可執行檔案的時候,記住這個庫的位置,以緻于在運作的時候不需要在設定這個動态庫的位置。當然,如果該動态庫的位置最後改變的話彙報錯,找不到相應的動态庫(共享庫):

./test: error while loading shared libraries: libarr.so: cannot open shared object file: No such file or directory

           方法四擴充:可以使用ldd指令檢視可執行程式(test)所依賴的動态庫:

                         [email protected]:~/binarysearchtree/arrdata[master]$ ldd test

                         linux-vdso.so.1 =>  (0x00007fff463fc000)

                         libarr.so => /home/xiantao/binarysearchtree/arrdata/libarr.so (0x00007f60e9860000)

                         libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f60e9485000)

                         /lib64/ld-linux-x86-64.so.2 (0x00007f60e9a64000)

假如把在編譯生成test可執行檔案後,删除libarr.so這個檔案,再運作時,會出現什麼結果,猜測會提示找不到共享庫。試驗以下,果然提示如下錯誤:

./test: error whileloading shared libraries: libarr.so: cannot open shared object file:No such file ordirectory。有點眼熟,其實就是沒有設定好動态運作庫到路徑的提示錯誤一樣,對于程式來說,也就是它找不到動态庫到路徑。

總結:

使用靜态庫編譯生成的可執行檔案大小要大于動态庫的(必需的啊,畢竟動态庫人家是在運作時動态加載使用的)。靜态庫使用時,隻需要在編譯階段(test)使用,動态庫需要再編譯階段(test)和運作(test)階段都要有相應的設定,而且都要有相應的.so檔案。

上邊提到過一次:在編譯test.c檔案時,編譯指令在兩種情況下式樣的,那假如目錄下同時有動态庫(libarr.so)和靜态庫(libarr.a)時,到底使用的時誰呢?測試一下:

同時編譯兩種庫,然後運作test

[email protected]:~/binarysearchtree/arrdata$gcc -c arr.c

[email protected]:~/binarysearchtree/arrdata$ar -cr libarr.a arr.o

[email protected]:~/binarysearchtree/arrdata$gcc -fPIC -c arr.c

xia[email protected]:~/binarysearchtree/arrdata$gcc -o test test.c -L. -larr

[email protected]:~/binarysearchtree/arrdata$./test

./test: error whileloading shared libraries: libarr.so: cannot open shared object file:No such file or directory

然後再添加LD_LIBRARY_PATH

[email protected]:~/binarysearchtree/arrdata$LD_LIBRARY_PATH=./

[email protected]:~/binarysearchtree/arrdata$./test成功

說明如果同時有靜态庫和動态庫,編譯器是會預設使用動态庫的。

同時,還需要注意以下更多的編譯選項,-W -D,-rdynamic -Wl,-rpath

以下時引用别人部落格

LIBRARY_PATH和LD_LIBRARY_PATH是Linux下的兩個環境變量,二者的含義和作用分别如下:

LIBRARY_PATH環境變量用于在程式編譯期間查找動态連結庫時指定查找共享庫的路徑,例如,指定gcc編譯需要用到的動态連結庫的目錄。

LD_LIBRARY_PATH環境變量用于在程式加載運作期間查找動态連結庫時指定除了系統預設路徑之外的其他路徑,注意,LD_LIBRARY_PATH中指定的路徑會在系統預設路徑之前進行查找。

差別與使用:

開發時,設定LIBRARY_PATH,以便gcc能夠找到編譯時需要的動态連結庫。

釋出時,設定LD_LIBRARY_PATH,以便程式加載運作時能夠自動找到需要的動态連結庫。

GCC裡的連結器的選項是-rpath和-rpath-link,看了下man ld,大緻是這個意思:

GCC連結選項-L,-rpath-link和-rpath

-L: “連結”的時候,去找的目錄,也就是所有的-lFOO選項裡的庫,都會先從-L指定的目錄去找,然後是預設的地方。

-rpath_link (或者-rpath-link):這個也是用于“連結”的時候的,例如你顯示指定的需要FOO.so,但是FOO.so本身是需要BAR.so的,後者你并沒有指定,而是FOO.so引用到它,這個時候,會先從-rpath-link給的路徑裡找。

-rpath:“運作”的時候,去找的目錄。運作的時候,要找.so檔案,會從這個選項裡指定的地方去找。對于交叉編譯,隻有配合--sysroot選項才能起作用。

也就是說,-rpath指定的路徑會被記錄在生成的可執行程式中,用于運作時。

-rpath-link則隻用于連結時。

繼續閱讀