1、靜態庫和共享庫?
靜態庫和共享庫(動態庫),二者的不同點在于代碼被載入的時刻不同。?
靜態庫的代碼在編譯過程中已經被載入可執行程序,因此體積較大。?
共享庫的代碼是在可執行程序運行時才載入內存的,在編譯過程中僅簡單的引用,因此代碼體積較小。
靜態鏈接庫和動態鏈接庫的區別在于,主程序在運行前,靜態鏈接庫的鏈接固定寫入在程序中,而動態鏈接庫則是在每次程序運行再加載鏈接。
2、庫存在的意義?
庫是別人寫好的現有的,成熟的,可以復用的代碼,你可以使用但要記得遵守許可協議。?
現實中每個程序都要依賴很多基礎的底層庫,不可能每個人的代碼都從零開始,因此庫的存在意義非同尋常。?
共享庫的好處是,不同的應用程序如果調用相同的庫,那么在內存里只需要有一份該共享庫的實例。
3.靜態庫?
Step 1.由源文件編譯生成一堆.o,每個.o里都包含這個編譯單元的符號表?
Step 2.ar命令將很多.o轉換成.a,成為靜態庫
靜態鏈接庫 libcool.a 遵從 GNU/Linux 規定的靜態鏈接庫命名規范,必須是”libyour_library_name.a”
動態庫的后綴是.so,它由gcc加特定參數編譯產生。?
4、動態庫
在 GNU/Linux 中動態鏈接文件,必需通過鏈接器 ld 生成。假設我們有 hot.c other.c 等文件要生成動態鏈接庫 libhot.so 。首先使用如下指令得到相應的 object 文件 hot.o 和 other.o?
gcc -fPIC -c hot.c?
gcc -fPIC -c other.c?
參數 -fPIC 指定生成的 object 文件為位置無關代碼(position-independence code),只有 PIC 可以被用作生成動態鏈接庫。然后使用如下指令得到動態庫:
ld -Bshared -o libhot.so hot.o other.o?
或者可以使用編譯器的ld wrapper:?
gcc -shared -o libhot.so hot.o other.o?
也可以使用編譯器直接生成動態庫:?
gcc -fPIC -shared -o libhot.so hot.c other.c?
這里選項 -shared 指示目標文件的類型是動態鏈接庫,動態庫的命名規范是”libyour_library_name.so”
linux操作系統中,?
1.和靜態庫類似,動態庫文件也是一些目標文件(后綴名為.o)的集合體而已。?
2.動態庫的后綴名是.so,對應于windows操作系統的后綴名為.dll的動態庫。?
3.可以使用gcc命令來創建一個動態庫文件。?
來看一個實例,和靜態庫的代碼實際是一樣的。先看看可以編譯成庫文件的源文件中的代碼:
/* test.c */ int f() { return 3; }
1
2
3
4
5
代碼非常簡單。我們敲入下列命令:
gcc -c -fPIC test.cgcc -shared -fPIC -o libtest.so test.o
1
2
會在當前目錄下生成一個libtest.so動態庫文件。再看如何使用這個庫??慈缦麓a:
/* app.c */ #include extern int f(); int main() { printf(“return value is %d ”,f()); return 0; }
1
2
3
4
5
6
7
8
敲入如下命令:
gcc –c app.cgcc -o app app.o -L. –ltest
1
2
敲命令的時候要記得將libtest.a文件和生成的app.o文件放在同一個目錄(即當前目錄)下。這樣,敲入命令后,會在當前目錄下生成一個名為app的可執行文件。但是當我們執行./app命令,來執行這個可執行文件時,卻提示如下錯誤:
這就奇怪了,libtest.so文件明明就在當前目錄下,為什么會提示找不到呢?? 原來linux和windows的機制是不同的,它不會在當前目錄下尋找動態連接庫文件,它只會在標準路徑下尋找。(The system searches only /lib and /usr/lib, by default.)。我們可以使用一個命令,使得操作系統去我們指定的路徑下面去尋找。假設libtest.so文件所在的目錄是/root/Desktop/aabb,那么執行命令
export LD_LIBRARY_PATH=/root/Desktop/aabb
1
后,再執行./app,我們發現,程序就正常運行了。
在加載動態鏈接庫的時候,有可能會遇到加載不到的錯誤,原因在于系統默認加載的動態鏈接庫路徑里沒有找到你的動態庫,有三種解決方法:
1.在執行gcc main.c -L. -ltest -o main 前,執行 export LD_LIBRARY_PATH=$(pwd)
2.將其添加到/etc/ld.so.cache文件中。將你so所在的目錄寫到/etc/ld.so.conf文件里,然后執行ldconfig該命令會重建/etc/ld.so.cache文件。
3.將你的so放在/etc/ld.so.conf里的路徑位置里。
Linux下的dlopen、dlsym、dlclose 相當于windows平臺的LoadLibrary、GetProcAddress 、FreeLibrary,可以在運行時動態加載動態庫,使用其中的導出函數。但是局限在于,這樣僅僅能夠導出全局函數,而不能導出類的方法。所以一般動態庫導出C++類實現的功能時都會設計一大堆的全局函數來包裝一下。? 包含頭文件:
#include dlfcn.h : Linux動態庫的顯式調用
1
函數
void * dlopen( const char * pathname, int mode );
1
函數描述:? 在dlopen的()函數以指定模式打開指定的動態連接庫文件,并返回一個句柄給調用進程。使用dlclose()來卸載打開的庫。? mode:分為這兩種? RTLD_LAZY 暫緩決定,等有需要時再解出符號? RTLD_NOW 立即決定,返回前解除所有未決定的符號。
dlerror? 函數定義:
void*dlsym(void* handle,const char* symbol)
1
函數描述:? dlsym根據動態鏈接庫操作句柄(handle)與符號(symbol),返回符號對應的地址。使用這個函數不但可以獲取函數地址,也可以獲取變量地址。? dlclose
dlopen以指定模式打開指定的動態連接庫文件,并返回一個句柄給調用進程,dlerror返回出現的錯誤,dlsym通過句柄和連接符名稱獲取函數名或者變量名,dlclose來卸載打開的庫。 dlopen打開模式如下:
RTLD_LAZY 暫緩決定,等有需要時再解出符號? RTLD_NOW 立即決定,返回前解除所有未決定的符號。? 生產動態鏈接庫
編譯參數 gcc -fPIC -shared
使用so文件的編譯參數? 編譯選項如下:
gcc -rdynamic -o main main.c -ldl
1
選項 -rdynamic 用來通知鏈接器將所有符號添加到動態符號表中? (目的是能夠通過使用 dlopen 來實現向后跟蹤)比如日志系統,主程序里使用一套日志系統,dlopen方式打開的libso里無法使用。編譯時加上這個參數,不需要增加任何代碼就可以使代碼通用。? 使用-ldl選項指明生成的對象模塊需要使用共享庫
?
評論
查看更多