1、Linux函數庫介紹
函數庫可以看做是事先編寫的函數集合,它可以與主函數分離,從而增加程序開發的復用性。Linux中函數庫可以有3種使用的形式:靜態、共享和動態。
1) 靜態庫的代碼在編譯時就已連接到開發人員開發的應用程序中;
2) 而共享庫只是在程序開始運行時才載入;
3) 動態庫也是在程序運行時載入,但與共享庫不同的是,動態庫使用的庫函數不是在程序運行使開始載入,而是在程序中的語句需要使用該函數時才載入。動態庫可以在程序運行期間釋放動態庫所占用的內存,騰出空間供其他程序使用。
注:
l 由於共享庫和動態庫並沒有在程序中包括庫函數的內容,只是包含了對庫函數的引用,因此代碼的規模比較小。
l 系統中可用的庫大都存放在/usr/local/lib、/usr/lib、/lib、目錄中。
l 頭文件大都放在/usr/include、/usr/local/include目錄下。
l 共享庫的相關配置文件和管理命令如下:
/etc/ld.so.conf:包含共享庫的搜索位置。
ldconfig:共享庫管理工具,一般在更新了共享庫之後要運行該命令。
ldd:可以查看可執行文件所使用的共享庫。
l 庫文件名由前綴lib和庫名以及後綴組成,根據庫的類型不同,後綴名也不一樣。
2、大量使用庫文件的主要原因
1) 為了便於編程,對於部分經常使用的函數,相應的開發語言都提供了對應的庫文件支持。
2) 隱藏具體的函數實現細節。程序員在使用庫文件時,只需要包含所需要函數所在的頭文件,而不必關心該函數的具體實現。對於商業軟件來說,其知識產權也得到了一定的保護。
3、使用這些庫函數都有什麼途徑
在任何編程環境中,庫文件都是一些預先編譯好的函數集合,這些函數以二進制代碼形式存儲在庫文件中。用戶要使用這些函數,只需要包含這些庫文件即可。一般來說,要從庫文件獲得相應的函數有兩種辦法。
1) 在編譯時將庫中相應函數的二進制映像代碼直接拷貝到當前編譯的程序中,當前程序是獨立運行的。這種庫我們叫做靜態庫,在Linux中,以.a為後綴的為靜態庫。
2) 在編譯時只引用庫中相應函數的二進制映像代碼的入口地址(不直接拷貝),該程序在運行時從共享庫文件中讀出該函數代碼(這需要首先將共享庫加載到內存中),從而間接引用,這種庫我們稱之為共享庫,在Linux中,以libxxx.xo.x.x為格式命名。
4、具體如何使用
使用靜態庫、共享庫和動態庫三種類型的方法很相似,都是使用選項是“-l”(注意這裡是小寫的“L”)。該選項是用於指明具體使用的庫文件。由於在Linux中函數庫的命名規則都是以“lib”開頭的,因此,這裡的庫文件只需填寫lib之後的內容即可。如:有靜態庫文件libm.a,在調用時只需寫作“-lm”;同樣對於動態庫文件libm.so;在調用時也只需寫作“-lm”即可,其整體調用命令類似如下:
[root@localhost gcc]# gcc -o dynamic –L /root/lq/testc/lib/ dynamic.o -lmydynamic
那麼,若系統中同時存在文件名相同的靜態庫文件和動態庫文件時,該鏈接選項究竟會調用靜態庫文件還是動態庫文件呢?經測試後可以發現,系統調用的是動態庫文件,這是由於Linux系統中默認的是采用動態鏈接的方式。這樣,若用戶要調用含有同名動態庫文件的靜態庫文件,則在“-l”後需要顯示地寫出包含後綴名的文件名,如:要調用libm.a庫文件時就需寫作“-llibm.a”。
1) 如果你已經有一個靜態庫文件libhello.a,此庫文件的頭文件為libhello.h,其內容如下:
#ifndef __libhello_H__
#define __libhello_H__
void print_hello(void); //print hello world,this is library to console
#endif /*__libhello_H__*/
我們可以從上面的代碼看出,頭文件知道libhello.a庫文件包含了print_hello()函數,其返回值類型和參數都為空。因此,在編寫程序時,你只需要使用此函數(在包含頭文件的前提下),而不用去管其具體實現細節。
使用libhello.a庫文件的示例程序main.c如下:
#include "libhello.h"
int main(int argc, char** argv)
{
print_hello(); //引用庫函數
return 0;
}
我們現在可以把main.c、libhello.a拷貝到同一目錄下,進行編譯:
# gcc –o usehello_static usehello.c –lhello // 也可以直接用libhello.a,前面不用加橫槓
2) 如果你已經有了一個共享庫文件libhello.so.0.0,我們這裡得做兩個符號鏈接(具體原因本人搞的不是很清楚):
# ln –s libhello.so.0 libhello.so.0.0
# ln –s libhello.so libhello.so.0
我們可以將這三個文件拷貝到當前目錄,此庫文件libhello.so.0.0中定義了print_hello()函數。可以查看其頭文件libhello.h,其中包含如下內容:
#ifndef __libhello_H__
#define __libhello_H__
void print_hello(void); //即對print_hello()函數進行了一次生命
#endif /*__libhello_H__*/
同樣,我們也可以在main.c中引用該共享庫文件中的函數,main.c內容如下:
#include "libhello.h"
int main(int argc, char** argv)
{
print_hello(); //引用庫函數
return 0;
}
然後采用以下命令編譯連接(你可以把庫文件libhello.so.0.0拷貝到當前目錄或者系統/lib目錄下):
# gcc –Wall –g –c usehello.c –o usehello.o //usehello.o為二進制目標文件
# gcc –g –o usehello_dynamic usehello.o –L ./ -lhello //紅色標記的是專門用於引用共享庫的命令”-L dir”
生成可執行文件後,你可以用ldd命令可執行文件所使用的共享庫:
# ldd usehello_dynamic
終端會提示:libhello.so.0 => not found,所以你要想讓這個可執行文件運行時達到你預期的效果,你必須在其運行的同時將共享庫加到庫的搜索路徑中去:
# LD_LIBRARY_PATH = $(pwd) ./usehello_dynamic