日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

c语言插件实现原理,C语言实现插件机制

發(fā)布時(shí)間:2023/12/10 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c语言插件实现原理,C语言实现插件机制 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

現(xiàn)在越來越多的軟件項(xiàng)目都提供插件機(jī)制,這樣使得軟件的擴(kuò)展性大大增強(qiáng),那么到底插件機(jī)制的實(shí)現(xiàn)是怎么樣的呢?在這里只談?wù)揅語言的實(shí)現(xiàn),其實(shí)C語言實(shí)現(xiàn)插件的例子也很多,像mjpg-streamer就是將輸入輸出做成插件,dm500機(jī)頂盒的主程序enigma也使用了插件機(jī)制,我就是從enigma當(dāng)中學(xué)習(xí)的。好了,這里給一個(gè)簡單的例子來看看如何實(shí)現(xiàn)。

我的設(shè)想是這樣的:有一個(gè)主程序,有一個(gè)插件(.so文件),主程序里面提供一些最基本的功能模塊,而在插件中使用這些功能模塊實(shí)現(xiàn)某些功能。簡單點(diǎn)就是主程序要調(diào)用.so文件中的函數(shù),而.so要調(diào)用主程序中的某些基礎(chǔ)函數(shù)。

為了既能使用插件a.so, 又能使用插件b.so, 還能使用插件c.so,這里要顯式調(diào)用動(dòng)態(tài)鏈接庫,即通過dlopen, dlsym, dlclose來使用.so文件,還是直接來看代碼。

#mkdir soplugin

#cd soplugin

#vim main.h

//main.h

#ifndef MAIN_H

#define MAIN_H

class A {

public:

A(){};

~A(){};

void p(const char *s);

};

#endif

#vim main.cpp

#include

#include?? // dlopen/dlsym/dlclose頭文件

#include "main.h"

void A::p(const char *s)

{

printf("A::p()\n");

}

void plugin_show(const char *s)? // 這個(gè)函數(shù)會(huì)被.so文件調(diào)用

{

printf("%s\n", s);

}

int main(int argc, char *argv[])

{

int (*PluginExec)(int argc, char *argv);

void *plugin;

printf("loading...\n");

plugin = dlopen("./tplugin.so", RTLD_GLOBAL|RTLD_NOW); // 顯式打開.so文件

if (plugin == NULL) {

printf("ptr: %p\n", plugin);

perror("Can not load tplugin.so");

return -1;

}

PluginExec = (int (*)(int, char*))dlsym(plugin, "plugin_exec"); // 得到入口函數(shù)指針

if (PluginExec) {

PluginExec(0, NULL);? // 調(diào)用入口函數(shù)

}

dlclose(plugin);

return 0;

}

#vim plugin.cpp

#include "main.h"

extern void plugin_show(const char *s);

extern "C"

int plugin_exec(int argc, char *argv[])? // 這里要用extern "C"聲明,否則C++編譯器會(huì)給函數(shù)名加上一些亂七八糟的東西,不信你可以試試,然后用objdump去查查看

{

A a;

a.p("in plugin_exec"); // 這個(gè)在主程序中實(shí)現(xiàn)

plugin_show("in plugin.");? // 這個(gè)也在主程序中實(shí)現(xiàn)

return 0;

}

好了,代碼就這些,很簡單,但能說明問題就行了,再寫個(gè)Makefile。

# vim Makefile

all:

g++ -shared -fPIC -DPIC -c plugin.cpp -I.

ld -shared -o tplugin.so plugin.o

g++ -Wl,-E -o mm main.cpp -ldl

前面兩行是將plugin.cpp做成一個(gè).so文件,后面一行是編繹main.cpp,這里要特別注意參數(shù)-Wl,-E,這個(gè)參數(shù)意思是將-E參數(shù)傳遞給鏈接器ld,最終的目的是將main.cpp中的函數(shù)輸出成全局符號(hào),以方便.so文件調(diào)用,如果沒有此參數(shù),那么編繹也不會(huì)有問題,但在運(yùn)行時(shí)dlopen總是會(huì)失敗,原因是無法解決符號(hào)依賴問題。關(guān)于這個(gè)參數(shù)你可以用objdump對(duì)比一下加與不加的結(jié)果差別。

好了,接下來編譯然后運(yùn)行。

#make

g++ -shared -fPIC -DPIC -c plugin.cpp -I.

ld -shared -o tplugin.so plugin.o

g++ -Wl,-E -o mm main.cpp -ldl

#./mm

loading...

A::p()

in plugin.

這個(gè)例子只是簡單的實(shí)現(xiàn)打印,但至少已經(jīng)可以看到主程序和.so文件之間可以調(diào)用了,那我再實(shí)現(xiàn)a.so, b.so當(dāng)然也不成問題了。可能有人會(huì)產(chǎn)生疑問,為什么不隱式調(diào)用呢?原因是:如果隱式調(diào)用就必須在編譯階段確定好.so文件,這樣就談不上可擴(kuò)展插件了,它們之間就存在了編譯上的依賴關(guān)系。而顯式調(diào)用是在運(yùn)行期間確定他們的依賴關(guān)系的。

如果有興趣可以參數(shù)mjpg-streamer去學(xué)習(xí),但是mjpg-streamer中的插件沒有調(diào)用主程序的函數(shù),最好的學(xué)習(xí)例子還是enigma,他里面實(shí)現(xiàn)了大量的插件。以后嵌入式軟件項(xiàng)目的擴(kuò)展性要求會(huì)越來越高,插件擴(kuò)展也大受歡迎,插件擴(kuò)展的機(jī)制很多,需要我們?nèi)ナ占瘜W(xué)習(xí),這里講的是最簡單的一種。我為什么要學(xué)習(xí),原因是我目前參與的一個(gè)項(xiàng)目主程序盡然大到30多MB,編譯鏈接時(shí)間太長,要擴(kuò)展功能就更痛苦了,一次一次的編譯/鏈接,一次一次的等待,真是折磨。

附:

enigma是dm500機(jī)頂盒的主程序,enigma本身通過c++實(shí)現(xiàn)gui, gdi, dvb等一堆基礎(chǔ)庫,并實(shí)現(xiàn)了插件管理器,外圍的功能基本全是c/c++插件實(shí)現(xiàn)。

enigma2是dm800的機(jī)頂盒主程序,enigma2就比enigma更高級(jí)了,他通過c++實(shí)現(xiàn)gui, gdi, dvb等一些基礎(chǔ)庫,其余的界面功能,機(jī)頂盒功能全部是用動(dòng)態(tài)語言python實(shí)現(xiàn),中間使用swig膠合在一起。也是不錯(cuò)的學(xué)習(xí)例子,但項(xiàng)目太大,學(xué)習(xí)不太容易。

總結(jié)

以上是生活随笔為你收集整理的c语言插件实现原理,C语言实现插件机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。