背景:不同产品组将其功能编译为.so,这些.so 可以加载到统一的基础平台上运行,如果产品组代码有改动,只需要更新对应的.so
问题:如何动态加载.so文件,并使用里边的函数/类 ?
解决方法1: 使用类的多态特性,将各种产品功能抽象为“工作类”,这些“工作类”都继承一个“动态加载基类”,然后定义纯C的类创建和销毁函数,产品功能.so加载进来后,基础平台寻找创建和销毁函数,就可以创建一个“工作类”实例,并通过基类指针使用。下面是示例代码
class worker_base { protected: int wtype; public: worker_base():wtype(0){} virtual ~worker_base(){} void settype(int type) { wtype = type; } virtual int doJob() = 0; }; typedef worker_base * create_t(); typedef void destroy_t(worker_base *);
上图是worker_base.h, 定义了worker_base类,这个类是一个基类,工作函数 doJob 定义为纯虚函数,同时,定义基类的创建和销毁函数指针 create_t 和 destroy_t
#include <string> #include "worker_base.h" namespace worker{ class worker : public worker_base{ public: worker(){} ~worker(){} public : virtual int doJob() { printf("dojob in module X "); return 0; } }__rte_cache_aligned; }
上图是worker.h , 定义class worker 为具体的产品工作类,继承 work_base, 并实现自己的 doJob
#include <stdio.h> #include "worker.h" worker::worker * wk = NULL; extern "C" worker_base* create(){ printf("create report "); wk = new worker::worker(); return wk; } extern "C" void destroy(worker_base* rpt) { printf("delete report "); //delete rpt; }
上图为worker.cpp , 实现了worker 类实例的创建和销毁函数
#include <string> #include <list> #include <dlfcn.h> #include "worker_base.h" #include "DomParser.h" /// worker list typedef std::list<worker_base*>::iterator worker_iter; enum hooktype { WK }; class Register { public: Register(){}; ~Register(){}; public: std::list<worker_base*> worker_list; private: bool parse(); bool hook_register(hooktype ht, void* hk);///<Register one hook function into the list bool invoke_method(const std::string& hooktype, const std::string& libname); bool init(); bool run(); public: inline static Register& instance() { extern Register __g_reg; return __g_reg; } }; static inline Register& GetHook() { return Register::instance(); }
上图是register.h , 定义了一个注册类,该类通过一个链表维护所以工作类实例,parse 函数解析XML文件,将产品.so加载进来,dlsym 寻找create_t和delete_t符号,创建实例然后插入链表。主流程通过调用链表里的实例的run方法完成对.so类的调用,下面是加载一个.so的方法
#include <strsplit.h> #include <iostream> #include "register.h" Register __g_reg; /*将一个worker实例(基类指针)注册到链表*/ bool Register::hook_register(hooktype ht, void* hk) { if(ht == WK){ worker_list.push_back((worker_base*)hk); }else{ printf("hook typedef error "); return false; } return true; } bool Register::parse() { const std::string& fname("./model.xml"); nsfocus::DomParser parser; try{ if(parser.open(fname)){ xercesc::DOMNode* node; xercesc::DOMNode* root = parser.getRootNode(); node = nsfocus::DomUtil::getChildNode(root, "modules/netio", "/"); std::string hooktype; std::string val; nsfocus::DomUtil::getAttribNodeValue<std::string>(node, "hooktype", hooktype); nsfocus::DomUtil::getAttribNodeValue<std::string>(node, "files_list", val); size_t toks = 0; nsfocus::strsplit split(val, " ", true, 3000, toks, '