在Linux下如何使用自己的庫函式

2021-06-29 02:30:16 字數 4173 閱讀 5479

一使用庫必要性

提高**重用性。

二庫的種類:

1 靜態庫

一般以*.a命名。

程式編譯時被載入,此後,只要程式不被重新編譯,靜態庫就沒有作用了(可以刪掉)。

由於靜態庫的**在編譯過程中已經被載入可執行程式,因此體積較大,如果有多個應用程式都用了同乙個靜態庫,在存放可執行程式的硬碟中就會有這個靜態庫的多份拷貝。如果他們同時在執行,那麼在記憶體中也會有這個靜態庫的多份拷貝。但是如下面提到的動態庫相比較,程式執行時間比較短,因為沒有執行時庫函式的載入。所謂「以空間換時間」。

下面我們用乙個例項說明靜態庫的程式設計和使用。

//庫函式:hellowlib.c

#include

void printhellow()    

首先生成目標檔案:gcc -c  printhellow.c  –o printhellow.o

然後使用ar(archive)命令把目標檔案製作庫檔案:ar cqs libhello.a printhellow.o

注意庫檔名一定是lib***.a格式,不要忘了加lib作為字首。

下面我們寫乙個程式呼叫靜態庫libhello.a中的printhellow函式。

int main(int arc, char **argv)

下面編譯:gcc -o testlib testlib.c -l ./  -lhello

即可生成可執行檔案testlib。

注意上面的-l(大寫)指示庫的路徑在當前目錄下。如果沒有這個選項,就需要把庫libhello.a加入到標準路徑中。如/usr/lib中。-l(小寫)只需要跟hello,其他字元全部不要,否則出錯。

2 動態庫(共享庫)

一般以.so命名(share object)

與靜態庫不同,共享庫的**是在可執行程式執行時才載入記憶體的,在編譯過程中僅簡單的引用,因此**體積較小。與上面提到的靜態庫相比,很是節約空間。但執行時需要載入,因此執行時間相對靜態庫而言比較長。所謂「以時間換空間」。

動態鏈結的意思就是在程式裝載記憶體的時候才真正的把庫函式**鏈結進行確定它們的位址,並且就算有幾個程式同時執行,記憶體也只存在乙份函式**。

動態庫的**要實現這樣的功能,必須滿足這樣一種條件:能夠被載入到不同程序的不同位址,所以**要經過特別的編譯處理,我們把這種經過特別處理的**叫做「位置無關**(position independed code .pic)」。

位置無關**可以這樣看,記憶體中的動態**只有乙份副本,但動態庫的資料卻可能有多份。由於每乙個鏈結到動態的程序都可能會修改庫的資料,所以每當有這種情況,作業系統就複製出乙份資料副本,然後修改程序的位址空間對映,使它指向新的資料副本,這樣,程序最後修改的只是屬於自己的那份資料。

更詳細來說,某個程式的在執行中要呼叫某個動態鏈結庫函式的時候,作業系統首先會檢視所有正在執行的程式,看在記憶體裡是否已有此庫函式的拷貝了。如果有,則讓其共享那乙個拷貝;只有沒有才鏈結載入。這樣的模式雖然會帶來一些「動態鏈結」額外的開銷,卻大大的節省了系統的記憶體資源。我們所知c的標準庫就是動態鏈結庫,即系統中所有執行的程式共享著同乙個c標準庫的**段。

正如剛才所說,由於動態鏈結庫函式不會被拷貝到可執行檔案中。編譯的時編譯器只會做一些函式名之類的檢查。程式執行時,被呼叫的動態鏈結庫函式被安置在記憶體的某個地方,所有呼叫它的程式將指向這個**段。因此,這些**必須是相對位址,而不是絕對位址。在編譯的時候,我們需要告訴編譯器,這些物件檔案是用來做動態鏈結庫的,所以要用位址無關**(position independent code (pic))。

共享庫又可分為動態鏈結(dynamic linking)和動態載入(dynamic loading)兩種。

2.1  動態鏈結(dynamic linking)

在編譯程式時指定要連線的庫,然後再程式執行時一開始就將庫載入。這也稱為隱式呼叫庫函式。

示例仍然使用鋼材程式,編譯庫:

gcc -fpic -shared -o libhello.so printhellow.c

-fpic便指示了這是位址無關**,-shared指示是乙個共享庫

編譯程式,和靜態庫使用方法一樣:gcc -o testlib testlib.c -l ./ -lhello

這時候編譯成功,但我們執行testlib卻發生以下錯誤:

./testlib: error while loading shared libraries: libhello.so: cannot load shared object file: no such file or directory

顯然,程式載入時到標準路徑中找不到庫檔案。

解決辦法 1)把我們生成的庫放到標準路徑中去即可。

mv libhello.so  /usr/lib

2)建立符號連線 ln -s `pwd`/libhello.so /usr/lib/libhello.so

3)將動態鏈結庫所在目錄名追加到動態鏈結庫配置檔案/etc/ld.so.conf中

pwd >> /etc/ld.so.conf

ldconfig

4)利用動態鏈結庫管理命令ldconfig,強制其搜尋指定目錄,並更新快取檔案,# ldconfig `pwd`

但是這種方法只是暫時的,如果再次執行ldconfig, 快取檔案內容可能改變,所需的動態鏈結庫可能不被系統共享了。

5)編譯時指定庫的載入路徑: gcc -o testlib testlib.c -l ./ -lhello -wl, -rpath ./

這裡, -rpath 說明了程式執行時庫的載入路徑,因為-rpath是ld命令的選項,所以gcc呼叫它時需要使用gcc的

-wl選項。

2.2  動態載入(dynamic loading)

程式不會自動載入庫,需要在程式中由程式設計師指定何時載入。系統提供了一套動態載入api以方便我們使用。

先看一下這些api: 1)

#include

void *dlopen( const char *file, int mode );

dlopen第乙個引數是共享庫的名稱,會在以下路徑中查詢指定的共享庫:

①環境變數ld_library_path中指定的

②檔案/etc/ld.so.cache中找到的庫的列表,由ldconfig命令重新整理。

③目錄usr/lib。

④目錄/lib。

⑤當前目錄。

第二個引數為開啟共享庫的方式。有兩個值

①rtld_now:將共享庫中的所有函式載入到記憶體

②rtld_lazy:稍後進行共享庫中的函式的載入,呼叫dlsym()時載入某函式 2)

char *dlerror();

用dlerror()函式測試是否開啟成功,並進行錯誤處理; 3)

void *dlsym( void *restrict handle, const char *restrict name );

用dlsym獲得函式位址,存放在乙個函式指標中,用獲得的函式指標進行函式呼叫。

4) char *dlclose( void *handle );

程式結束時用dlclose關閉開啟的動態庫,防止資源洩露。

下面是testdyn.c程式例項:

#include

#include

#include

int main(int arc, char **argv)

perr = dlerror();

if(null != perr)

/* get the address of printhellow function */

pfunc = dlsym(handle, "printhellow");

perr = dlerror();

if(null != perr)

/* call the function */

(*pfunc)();

dlclose(handle);

printf("load share library success!\n") ;  

return -1; }

編譯:gcc -o testdyn testdyn.c–ldl

注意加上–ldl引數。

程式執行:

[root@vmwarelin7 fengxz]# ./testdyn

hellow,now in lib routine

load share library success!

Linux下如何讓自己的程式在開機時自動啟動

系統的服務在開機時一般都可以自動啟動,那我們程式自己寫的程式呢?windows 系統在 開始 所有程式 啟動 裡面放個快捷方式就行,那 linux 下呢?這也是乙個比較簡單的問題,有不少的方法可以解決,這裡介紹三種方法。因為是簡單介紹,所以具體細節不是很詳細,可以通過man看看相關手冊。一 etc ...

Linux下如何讓自己的程式在開機時自動啟動

系統的服務在開機時一般都可以自動啟動,那我們程式自己寫的程式呢?windows系統在 開始 所有程式 啟動 裡面放個快捷方式就行,那linux下呢?這也是乙個比較簡單的問題,有不少的方法可以解決,這裡介紹三種方法。因為是簡單介紹,所以具體細節不是很詳細,可以通過man看看相關手冊。一 etc rc....

在Linux下如何安裝mysql資料庫

rpm qa grep mysql檢查完畢發現有則需要解除安裝,執行以下命令 rpm e nodeps mysql包yum install mysql community 有提示資訊輸入y即可,安裝完畢之後啟動mysql資料庫,注意這裡的是6的啟動方式,跟7的不一樣 service mysqld s...