加入收藏 | 设为首页 | 会员中心 | 我要投稿 成都站长网 (https://www.028zz.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 服务器 > 搭建环境 > Linux > 正文

Linux C++ 编写插件系统

发布时间:2022-10-14 14:31:02 所属栏目:Linux 来源:互联网
导读: 在项目中,如果你想方便的扩展现有的应用程序的功能linux编码,你会如何实现呢?想到的思路就是使用插件系统,插件系统只是在指定文件夹中搜索 .so,如果找到,则将内容添加到程序中。当然

在项目中,如果你想方便的扩展现有的应用程序的功能linux编码,你会如何实现呢?想到的思路就是使用插件系统,插件系统只是在指定文件夹中搜索 .so,如果找到,则将内容添加到程序中。当然,因为程序实际上并不知道 .so动态库中的内容,所以通常的方法是让 .so 定义一个集合入口点并调用程序本身定义的函数,然后程序可以使用这些动态库提供的接口功能。

什么是插件?

插件是共享库(dll 或 so,取决于您的平台)内的组件。这些组件在运行时按需动态加载。插件系统注册表存储有关可以加载的不同组件的信息。应用程序可以查询插件注册表,找到它需要加载的组件,然后在运行时动态加载它。

加载库

程序运行时会自动搜索该目录,并动态加载目录中的插件。只需调用 file.find(".so")

void?findAllPlugins(const?std::string&?path,?std::list<std::string>&?pluginNames)?{
?DIR?*pDIR;
?struct?dirent?*entry;
?if(?pDIR=opendir(path.c_str())?){
??while(entry?=?readdir(pDIR)){
???std::string?file(entry->d_name);
???if(?file.compare(".")?>?0?&&?file.compare("..")?>?0)?{
????std::cout?<<?file?<<?std::endl;
????if(file.find(".so")?!=?std::string::npos?)?{
?????pluginNames.push_back(std::move(file));
????}
???}
??}
??closedir(pDIR);
?}?else?{
??std::cout<<?"Can?not?open?dir:?"<std::endl;
?}
}

功能是加载plugins目录中的所有so插件,打印出so相关信息

应用程序向插件提供接口

为了实现功能扩展,应用程序必须向插件提供接口。在baseClass.hpp中定义一个抽象类baseTest作为接口:

#ifndef?BASECLASS_HPP_
#define?BASECLASS_HPP_

#include?


class?baseTest?{
public:
?virtual?int?PrintThis(const?std::string&?message)=0;
?virtual?int?sum(int?a,?int?b)=0;
?virtual?~baseTest(){}
};


typedef?baseTest*?createTest_t();
typedef?void?deleteTest_T(baseTest?*ptr);

#endif?/*?BASECLASS_HPP_?*/

插件实现

在test.h中定义Test ,让Test 继承并实现baseTest中提供的所有接口:

#ifndef?TEST_H
#define?TEST_H

#include?"../project/baseClass.hpp"

class?Test?:?public?baseTest?{
public:
????Test();
????virtual?~Test();
????virtual?int?PrintThis(const?std::string&?message);
????virtual?int?sum(int?a,?int?b);
};

#endif?//?TEST_H

test.cpp

#include?"test.h"
#include?

Test::Test()?{
????std::cout<<"Create?new?object?from?library?success\n";
}

Test::~Test()?{
?std::cout<<"Destroy?object?from?library?success\n";
}

int?Test::PrintThis(const?std::string?&message)?{
????std::cout<<"Write?new?message?"?<<?message<<std::endl;
????return?static_cast<int>(message.size());
}


int?Test::sum(int?a,?int?b)?{
?return?a+b;
}

extern?"C"?baseTest*?createTest()?{
????return?new?Test();
}

extern?"C"?void?deleteTest(baseTest*?ptr)?{
????return?delete?ptr;
}

在linux系统下面,动态链接库的生成比较简单,如果使用g++进行编译的话,只需要加上 -fPIC 和 -shared 两个选项即可。为了让应用程序动态加载插件,需要将插件编译为so文件。

g++?-shared?-o?"libplugin.so"??./test.o

至此,一个libplugin.so插件就实现了。

实现应用程序

将所有插件编译为so文件并放入当前工程目录下的plugin/Debug目录中,启动应用程序,插件自动被加载到程序中.

应用程序编写自己的插件子系统的 C++ 简单示例如下:

int?main(int?argc,?char?*argv[])?{
?const?std::string?pluginsPath("/plugin/Debug");
?std::list<std::string>?pluginNames;
?std::list?handlers;
?findAllPlugins(pluginsPath,pluginNames);

?for(auto?name?:?pluginNames)?{
??std::cout<<"Find?plugin?"<std::endl;
??void*?plugin?=?dlopen((pluginsPath?+?"/"?+??name).c_str(),?RTLD_NOW);
?????if(!plugin)?{
?????????std::cout<<"Can?not?load?library"<std::endl;
?????????continue;
?????}
?????dlerror();
?????createTest_t*?creator?=?reinterpret_cast(dlsym(plugin,"createTest"));
?????if(!creator)?{
?????????std::cout<<"Could?not?create?Test?"<std::endl;
?????????dlclose(plugin);
?????????continue;
?????}
?????dlerror();
?????deleteTest_T*?del?=?reinterpret_cast(dlsym(plugin,"deleteTest"));
?????if(!del)?{
?????????std::cout<<"Could?not?delete?Test?"<std::endl;
?????????dlclose(plugin);
?????????continue;
?????}
?????task?t;
?????t.plugin?=?plugin;
?????t.del?=?del;
?????t.test?=?creator();
?????handlers.push_back(std::move(t));
?}
?int?i?=?0;
?for(auto?h?:?handlers)?{
??h.test->PrintThis("Hello?");
??++i;
??std::cout<sum(i,i+1)<<std::endl;
??h.del(h.test);
??dlclose(h.plugin);
?}
????return?0;
}

编译运行:

linux查看字符集编码_linux编码_linux 默认编码

总结

插件是共享库内的组件,这些组件在运行时按需动态加载。程序主要实现步骤为应用程序提供接口,由用户或第三方实现接口,在编译出相应的动态链接库so(即插件)。我们在放把插件放在指定目录下(plugin),然后应用程序启动时候遍历目录找到插件,实现动态加载插件。

(编辑:成都站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!