共享庫
共享庫和動態庫就是同一個東西,在linux上叫共享對象庫,文件後綴爲 .so,windows上叫動態加載函數庫, 文件後綴是 .dll。
共享庫只是在調用模塊中嵌入調用的代碼在庫的相對位置的地址,當程序執行時,共享庫的程序一起加載到內存中,當執行調用共享庫中代碼的指令時,條轉到共享庫中執行,執行完畢後在條轉回來
共享庫的優點
佔用空間小,方便更新(共享庫發生變化是,程序不需要再次編譯)
共享庫的缺點
相對於靜態庫執行效率略低。
打包一個簡單的共享庫:
將我之前寫的那個文件打包爲共享庫
’1. 編譯.c文件生成.o文件,這裏的-fpic參數的作用爲生成共享庫時生成與位置無關的代碼:
gcc -c -fpic func_add.c func_mul.c func_sub.c
2.鏈接生成共享庫文件
gcc -shared *.o -o libmymath.so
調用共享庫
1.直接調用共享庫
gcc test.c libmymath.so
2.修改環境變量來調用共享庫
打開~/.bashrc
vi ~/.basrhc
在末尾添加代碼:
export LIBRARY_PATH = $LIBRARY_PATH:/home/zhizhen/my_math/
重新加載配置文件
source ~/.bashrc
編譯時要指定庫名(省略前綴lib和後綴 .so)
gcc test.c -lmymath
3.添加編譯參數來調用共享庫
gcc test.c -L./ -lmymath
使用共享庫
在使用共享庫時,調用者這是記錄了被調代碼在庫的位置,因此在執行時需要共享庫同時被加載,操作系統會根據LD_LIBRARY_PATH路徑來加載共享庫。我們之前的操作雖然編譯成功了但是由於沒有配置LD_LIBRARY_PATH環境變量,操作系統會找不到我們的共享庫。
添加LD_LIBRARY_PATH
1.打開~/.bashrc
vi ~/.bashrc
2.添加LD_LIBRARY_PATH
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/zhizhen/my_math/
3.重新加載配置文件
source ~/.bashrc
4.運行可執行文件
./a.out
動態加載共享庫
需要調用頭文件
#include<dlfcn.h>
可以進行的操作
1.打開共享庫
void* dlopen(const char* filename,int flag);
參數1:filename:共享庫名或者庫的路徑(如果爲庫名,則會自動從LIBRARY_PATH中尋找相同的庫名)。
參數2:flag加載方式
- RTLD_LAZY:懶加載,即當被使用時才加載
- RTLD_NOW:立即加載
返回值:共享庫的句柄,類似於文件指針。用來打開我們想要的共享庫
2.獲取標識符地址並使用
void* dlsym(void* handle,const char* symbol);
參數1:handle:共享庫的句柄
參數2:symbol:標識符的名字
返回值:標識符在共享庫中的位置(地址、可以解應用、或跳轉過去),比如如果標識符在共享庫裏是個變量就進行解引用操作,如果是函數就跳轉過去執行。
3.卸載共享庫
int dclose(void* handle)
參數1:handle:共享庫的句柄
返回值:關閉成功返回0,關閉失敗返回-1
4.獲取錯誤信息
char* dlerror(void)
返回值:錯誤信息
例子
#include<stdio.h>
#include<dlfcn.h>
int main()
{
void* handle = dlopen("libmymath.so",RTLD_NOW);
if(NULL == handle)
{
puts(dlerror());
return -1;
}
//定義函數指針
//由於該標示符在共享庫裏表式的是函數,所以會調用該方法
//該函數執行的是共享庫裏的相加的方法
int (*add)(int num1,int num2) = dlsym(handle,"func_add");
if(add == NULL)
{
puts(dlerror());
return -1;
}
printf("%d\n",add(12,10));
return 0;
}