前面一篇文章“VS2010 C++創建、調用DLL圖解”簡單講述了在Windows下創建和調用動態庫(.dll文件)方法,本篇結合項目過程,總結一下Linux下調用動態庫(.so文件)的方法和注意點。
像window調用庫文件一樣,在linux下,也有相應的API因為加載庫文件而存在。它們主要是以下幾個函數:
| 函數名 | 功能描述 |
|---|---|
| dlopen | 打開對象文件,使其可被程序訪問 |
| dlsym | 獲取執行了 dlopen 函數的對象文件中的函數的地址 |
| dlerror | 該函數沒有參數,它會在發生前面的錯誤時返回一個字符串,同時將其從內存中清空; 在沒有錯誤發生時返回 NULL, |
| dlclose | 關閉目標文件。如果無需再調用共享對象的話,應用程序可以調用該方法來通知操作系統不再需要句柄和對象引用了。它完全是按引用來計數的,所以同一個共享對象的多個用戶相互間不會發生沖突(只要還有一個用戶在使用它,它就會待在內存中)。任何通過已關閉的對象的 |
實例代碼(soTest.c):
1 #include <stdio.h> 2 #include <dlfcn.h> 3 4 int main(int argc, char *argv[]){ 5 void * libm_handle = NULL; 6 float (*cosf_method)(float); 7 char *errorInfo; 8 float result; 9 10 // dlopen 函數還會自動解析共享庫中的依賴項。這樣,如果您打開了一個依賴於其他共享庫的對象,它就會自動加載它們。 11 // 函數返回一個句柄,該句柄用於后續的 API 調用 12 libm_handle = dlopen("libm.so", RTLD_LAZY ); 13 // 如果返回 NULL 句柄,表示無法找到對象文件,過程結束。否則的話,將會得到對象的一個句柄,可以進一步詢問對象 14 if (!libm_handle){ 15 // 如果返回 NULL 句柄,通過dlerror方法可以取得無法訪問對象的原因 16 printf("Open Error:%s.\n",dlerror()); 17 return 0; 18 } 19 20 // 使用 dlsym 函數,嘗試解析新打開的對象文件中的符號。您將會得到一個有效的指向該符號的指針,或者是得到一個 NULL 並返回一個錯誤 21 cosf_method = dlsym(libm_handle,"cosf"); 22 errorInfo = dlerror();// 調用dlerror方法,返回錯誤信息的同時,內存中的錯誤信息被清空 23 if (errorInfo != NULL){ 24 printf("Dlsym Error:%s.\n",errorInfo); 25 return 0; 26 } 27 28 // 執行“cosf”方法 29 result = (*cosf_method)(0.0); 30 printf("result = %f.\n",result); 31 32 // 調用 ELF 對象中的目標函數后,通過調用 dlclose 來關閉對它的訪問 33 dlclose(libm_handle); 34 35 return 0; 36 }
在這個例子中主要是調用了 math 庫(libm.so)中的“cosf”函數,dlopen函數的第二個參數表示加載庫文件的模式,主要有兩種:RTLD_LAZY 暫緩決定,等有需要時再解出符號;RTLD_NOW 立即決定,返回前解除所有未決定的符號。另外記得引用包含API的頭文件“#include <dlfcn.h>”(^_^)。
編譯執行結果如下:

如果將代碼12行中的庫文件名改為一個不存在的庫文件,運行后錯誤結果如下:

如果將代碼21行中的函數名改為一個不存在的函數名,運行后錯誤結果如下:

本文主要簡單講述在linux下調用SO庫文件的一些基本知識和注意點。
本實例在redhat 5.2的64系統下測試通過。
