1. 背景
庫:就是已經編寫好的,后續可以直接使用的代碼。
c++靜態庫:會合入到最終生成的程序,使得結果文件比較大。優點是不再有任何依賴。
c++動態庫:動態庫,一個文件可以多個代碼同時使用內存中只有一份,節省內存,可以隨主代碼一起編譯。缺點是需要頭文件。
網友說:庫就是除了main函數之外的其他代碼,都可以組成庫。
2. 只介紹動態庫(工作中主要用動態庫)
C++使用動態庫比C語言使用動態庫稍微麻煩點。
因為C++支持函數重載(參數變量個數不同、參數類型不同、類型修飾符不同const/not const等),都會使得C++對函數名進行重寫,不方便根據函數名查找對應函數。
C++中可以使用extern關鍵字修飾對應的函數,表示函數名按照C言語分隔編譯,不進行改寫。(extern關鍵字另一個關鍵字修飾變量,表示變量在其他文件中已經定義。通常見於修飾全局變量)
3. 使用so文件需要的api
頭文件 #include <dlfcn.h>

dlopen以指定的模式打開共享鏈接庫。使用可以參考: http://man7.org/linux/man-pages/man3/dlopen.3.html
4. C++使用動態鏈接庫實例
4.1 test.h
1 class Test{ 2 public: 3 virtual int get(); 4 virtual void set(const int num); 5 };
4.2 test.cpp
1 #include <iostream> 2 #include "test.h" 3 4 int g_num = 0; ///全局變量 5 6 int Test::get() { return g_num; } 7 void Test::set(const int num){ g_num = num; } 8 9 #ifdef __cplusplus 10 extern "C" { 11 #endif 12 13 Test* create(){ return new Test; } 14 15 #ifdef __cplusplus 16 } 17 #endif
4.3 main.cpp
1 #include <iostream> 2 #include <dlfcn.h> 3 #include "test.h" 4 using namespace std; 5 6 //聲明函數指針 7 typedef Test* (*so_init)(); 8 9 //定義插件類來封裝,句柄用完后需要釋放 10 struct Plugin{ 11 void *handle; 12 Test *t; 13 14 Plugin():handle(NULL), t(NULL) { } 15 ~Plugin(){ 16 if(t) { delete t; } 17 if (handle) { dlclose(handle); } 18 } 19 }; 20 21 int create_instance(const char *so_file, Plugin &p){ 22 //根據特定的模式打開so文件, 獲取so文件句柄 23 //RTLD_NOW:需要在dlopen返回前,解析出所有未定義符號 24 //RTLD_DEEPBIND:在搜索全局符號前先搜索庫內的符號,避免同名符號的沖突 25 p.handle = dlopen(so_file, RTLD_NOW | RTLD_DEEPBIND); 26 if (!p.handle) { 27 cout << "Cannot open library: " << dlerror() << endl; 28 return -1; 29 } 30 31 //根據字符串"create"讀取庫中對應到函數, 並返回函數地址,可以理解為一種間接的“反射機制” 32 so_init create_fun = (so_init) dlsym(p.handle, "create"); 33 if (!create_fun) { 34 cout << "Cannot load symbol" << endl; 35 dlclose(p.handle); 36 return -1; 37 } 38 39 //調用方法, 獲取類實例 40 p.t = create_fun(); 41 42 return 0; 43 } 44 45 int main(){ 46 Plugin p1; 47 Plugin p2; 48 49 if (0 != create_instance("./libtest_1.so", p1) 50 || 0 != create_instance("./libtest_2.so", p2)){ 51 cout << "create_instance failed" << endl; 52 return 0; 53 } 54 55 p1.t->set(1); //對庫1中到全局變量進行設置 56 p2.t->set(2); //對庫2中到全局變量進行設置 57 58 //輸出兩個庫中的全局變量 59 cout << "t1 g_num is " << p1.t->get() << endl; 60 cout << "t2 g_num is " << p2.t->get() << endl; 61 return 0; 62 }
執行:
g++ -fPIC -shared test.cpp -o libtest_1.so
g++ -fPIC -shared test.cpp -o libtest_2.so
g++ -g -Wl,--no-as-needed -ldl main.cpp -rdynamic

