Linux 動態鏈接庫(.so)的使用


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM