support dynamic libs compiling and loading

This commit is contained in:
an-tao 2018-06-14 18:51:26 +08:00
parent 95b83206fb
commit cc35b08580
8 changed files with 133 additions and 44 deletions

View File

@ -103,9 +103,20 @@ static void parseLine(std::ofstream &oSrcFile,std::string& line,const std::strin
void create_view::handleCommand(std::vector<std::string> &parameters) void create_view::handleCommand(std::vector<std::string> &parameters)
{ {
for(auto file:parameters) for(auto iter=parameters.begin();iter!=parameters.end();iter++)
{ {
if(file[0]=='-') auto file=*iter;
if(file=="-o"||file=="--output")
{
iter=parameters.erase(iter);
if(iter!=parameters.end())
{
_outputPath=*iter;
iter=parameters.erase(iter);
}
break;
}
else if(file[0]=='-')
{ {
std::cout<<ARGS_ERROR_STR<<std::endl; std::cout<<ARGS_ERROR_STR<<std::endl;
return; return;
@ -137,8 +148,8 @@ int create_view::createViewFile(const std::string &script_filename)
className=className.substr(pos+1); className=className.substr(pos+1);
} }
std::cout<<"className="<<className<<std::endl; std::cout<<"className="<<className<<std::endl;
std::string headFileName=className+".h"; std::string headFileName=_outputPath+"/"+className+".h";
std::string sourceFilename=className+".cc"; std::string sourceFilename=_outputPath+"/"+className+".cc";
std::ofstream oHeadFile(headFileName.c_str(),std::ofstream::out); std::ofstream oHeadFile(headFileName.c_str(),std::ofstream::out);
std::ofstream oSourceFile(sourceFilename.c_str(),std::ofstream::out); std::ofstream oSourceFile(sourceFilename.c_str(),std::ofstream::out);
if(!oHeadFile||!oSourceFile) if(!oHeadFile||!oSourceFile)
@ -176,7 +187,12 @@ void create_view::newViewSourceFile(std::ofstream &file,const std::string &class
file <<"#include <map>\n"; file <<"#include <map>\n";
file <<"#include <vector>\n"; file <<"#include <vector>\n";
file <<"#include <set>\n"; file <<"#include <set>\n";
file <<"#include <iostream>\n";
file <<"using namespace std;\n"; file <<"using namespace std;\n";
// file <<"void __attribute__((constructor)) startup()\n";
// file <<"{std::cout<<\"dynamic lib start to load!\"<<std::endl;}\n";
// file <<"void __attribute__((destructor)) shutdown()\n";
// file <<"{std::cout<<\"dynamic lib start to unload!\"<<std::endl;}\n";
std::string buffer; std::string buffer;
char line[8192]; char line[8192];
int import_flag=0; int import_flag=0;

View File

@ -26,7 +26,7 @@ namespace drogon_ctl
virtual std::string script() override {return "create view class files";} virtual std::string script() override {return "create view class files";}
protected: protected:
std::string _outputPath=".";
void createViewFiles(std::vector<std::string> &cspFileNames); void createViewFiles(std::vector<std::string> &cspFileNames);
int createViewFile(const std::string &script_filename); int createViewFile(const std::string &script_filename);
void newViewHeaderFile(std::ofstream &file,const std::string &className); void newViewHeaderFile(std::ofstream &file,const std::string &className);

View File

@ -9,7 +9,7 @@ void ApiTest::get(const HttpRequest& req,const std::function<void (HttpResponse
para["p1"]=std::to_string(p1); para["p1"]=std::to_string(p1);
para["p2"]=p2; para["p2"]=p2;
data.insert("parameters",para); data.insert("parameters",para);
auto res=HttpResponse::newHttpViewResponse("ListParaView",data); auto res=HttpResponse::newHttpViewResponse("DynamicListParaView.csp",data);
callback(*res); callback(*res);
} }
void ApiTest::your_method_name(const HttpRequest& req,const std::function<void (HttpResponse &)>&callback,double p1,int p2) const void ApiTest::your_method_name(const HttpRequest& req,const std::function<void (HttpResponse &)>&callback,double p1,int p2) const

View File

@ -113,7 +113,7 @@ int main()
drogon::HttpAppFramework::registerHttpApiMethod("/api/v1/handle4/{4}/{3}/{1}",func); drogon::HttpAppFramework::registerHttpApiMethod("/api/v1/handle4/{4}/{3}/{1}",func);
//start app framework //start app framework
//drogon::HttpAppFramework::instance().enableDynamicSharedLibLoading(); drogon::HttpAppFramework::instance().enableDynamicSharedLibLoading({"/tmp/views"});
drogon::HttpAppFramework::instance().run(); drogon::HttpAppFramework::instance().run();
} }

View File

@ -79,6 +79,6 @@ namespace drogon
virtual const std::string & getDocumentRoot() const =0; virtual const std::string & getDocumentRoot() const =0;
virtual void setDocumentRoot(const std::string &rootPath)=0; virtual void setDocumentRoot(const std::string &rootPath)=0;
virtual void setFileTypes(const std::vector<std::string> &types)=0; virtual void setFileTypes(const std::vector<std::string> &types)=0;
virtual void enableDynamicSharedLibLoading(const std::string &viewPth="views")=0; virtual void enableDynamicSharedLibLoading(const std::vector<std::string> &libPaths)=0;
}; };
} }

View File

@ -52,7 +52,7 @@ namespace drogon
virtual const std::string & getDocumentRoot() const override {return _rootPath;} virtual const std::string & getDocumentRoot() const override {return _rootPath;}
virtual void setDocumentRoot(const std::string &rootPath) override {_rootPath=rootPath;} virtual void setDocumentRoot(const std::string &rootPath) override {_rootPath=rootPath;}
virtual void setFileTypes(const std::vector<std::string> &types) override; virtual void setFileTypes(const std::vector<std::string> &types) override;
virtual void enableDynamicSharedLibLoading(const std::string &viewPth="views") override; virtual void enableDynamicSharedLibLoading(const std::vector<std::string> &libPaths) override;
~HttpAppFrameworkImpl(){} ~HttpAppFrameworkImpl(){}
private: private:
std::vector<std::pair<std::string,uint16_t>> _listeners; std::vector<std::pair<std::string,uint16_t>> _listeners;
@ -111,7 +111,7 @@ namespace drogon
size_t _threadNum=1; size_t _threadNum=1;
std::string _viewFilePath; std::vector<std::string> _libFilePaths;
std::unique_ptr<SharedLibManager>_sharedLibManagerPtr; std::unique_ptr<SharedLibManager>_sharedLibManagerPtr;
@ -121,13 +121,21 @@ namespace drogon
using namespace drogon; using namespace drogon;
using namespace std::placeholders; using namespace std::placeholders;
void HttpAppFrameworkImpl::enableDynamicSharedLibLoading(const std::string &viewPath) void HttpAppFrameworkImpl::enableDynamicSharedLibLoading(const std::vector<std::string> &libPaths)
{ {
assert(!_running); assert(!_running);
if(_viewFilePath.empty()) if(_libFilePaths.empty())
{ {
_viewFilePath=_rootPath+"/"+viewPath; for(auto libpath:libPaths)
_sharedLibManagerPtr=std::unique_ptr<SharedLibManager>(new SharedLibManager(&_loop,_viewFilePath)); {
if(libpath[0]!='/')
{
_libFilePaths.push_back(_rootPath+"/"+libpath);
} else
_libFilePaths.push_back(libpath);
}
_sharedLibManagerPtr=std::unique_ptr<SharedLibManager>(new SharedLibManager(&_loop,_libFilePaths));
} }
} }
void HttpAppFrameworkImpl::setFileTypes(const std::vector<std::string> &types) void HttpAppFrameworkImpl::setFileTypes(const std::vector<std::string> &types)

View File

@ -14,14 +14,14 @@
#include "SharedLibManager.h" #include "SharedLibManager.h"
#include <trantor/utils/Logger.h> #include <trantor/utils/Logger.h>
#include <drogon/config.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <dirent.h> #include <dirent.h>
#include <dlfcn.h> #include <dlfcn.h>
#include <fstream>
void *dlopen(const char *filename, int flag); static void forEachFileIn(const std::string &path,const std::function<void (const std::string &,const struct stat &)> &cb)
static void forEachFileIn(const std::string &path,const std::function<void (const std::string &filename)> &cb)
{ {
DIR* dp; DIR* dp;
struct dirent* dirp; struct dirent* dirp;
@ -55,16 +55,16 @@ static void forEachFileIn(const std::string &path,const std::function<void (cons
/* if dirent is a directory, continue */ /* if dirent is a directory, continue */
if(S_ISDIR(st.st_mode)) if(S_ISDIR(st.st_mode))
continue; continue;
cb(fullname); cb(fullname,st);
} }
return; return;
} }
using namespace drogon; using namespace drogon;
SharedLibManager::SharedLibManager(trantor::EventLoop *loop,const std::string viewPath): SharedLibManager::SharedLibManager(trantor::EventLoop *loop,const std::vector<std::string> & libPaths):
_loop(loop), _loop(loop),
_viewPath(viewPath) _libPaths(libPaths)
{ {
_loop->runEvery(5.0,[=](){ _loop->runEvery(5.0,[=](){
managerLibs(); managerLibs();
@ -72,30 +72,89 @@ _viewPath(viewPath)
} }
void SharedLibManager::managerLibs() void SharedLibManager::managerLibs()
{ {
LOG_DEBUG<<"manager .so libs in path "<<_viewPath; for(auto libPath:_libPaths)
forEachFileIn(_viewPath,[=](const std::string &filename){ {
LOG_DEBUG<<filename; forEachFileIn(libPath,[=](const std::string &filename,const struct stat &st){
auto pos=filename.rfind("."); //LOG_DEBUG<<filename;
if(pos!=std::string::npos) auto pos=filename.rfind(".");
{ if(pos!=std::string::npos)
auto exName=filename.substr(pos+1);
if(exName=="so")
{ {
//loading so file; auto exName=filename.substr(pos+1);
if(_dlMap.find(filename)!=_dlMap.end()) if(exName=="csp")
return;
auto Handle=dlopen(filename.c_str(),RTLD_NOW);
if(!Handle)
{ {
LOG_ERROR<<"load "<<filename<<" error!"; //compile
LOG_ERROR<<dlerror(); auto lockFile=filename+".lock";
} std::ifstream fin(lockFile);
else if (fin) {
{ return;
LOG_DEBUG<<"Successfully loaded library file "<<filename; }
_dlMap[filename]=Handle;
if(_dlMap.find(filename)!=_dlMap.end())
{
if(st.st_mtim.tv_sec>_dlMap[filename].mTime.tv_sec)
{
LOG_DEBUG<<"new csp file:"<<filename;
if(dlclose(_dlMap[filename].handle)==0)
{
LOG_DEBUG<<"close dynamic lib successfully:"<<_dlMap[filename].handle;
}
else
LOG_DEBUG<<dlerror();
}
else
return;
}
{
std::ofstream fout(lockFile);
}
std::string cmd="drogon_ctl create view ";
cmd.append(filename).append(" -o ").append(libPath);
LOG_DEBUG<<cmd;
system(cmd.c_str());
auto srcFile=filename.substr(0,pos);
srcFile.append(".cc");
DLStat dlStat;
dlStat.handle=loadLibs(srcFile);
dlStat.mTime=st.st_mtim;
_dlMap[filename]=dlStat;
_loop->runAfter(3.5,[=](){
LOG_DEBUG<<"remove file "<<lockFile;
if(unlink(lockFile.c_str())==-1)
perror("");
});
} }
} }
});
}
}
void* SharedLibManager::loadLibs(const std::string &sourceFile) {
LOG_DEBUG<<"src:"<<sourceFile;
std::string cmd="g++ ";
cmd.append(sourceFile).append(" ").append(definitions)
.append(compileFlags).append(includeDirs).append(" -shared -fPIC --no-gnu-unique -o ");
auto pos=sourceFile.rfind(".");
auto soFile=sourceFile.substr(0,pos);
soFile.append(".so");
cmd.append(soFile);
void *Handle = nullptr;
if(system(cmd.c_str())==0)
{
LOG_DEBUG<<"Compiled successfully";
//loading so file;
Handle=dlopen(soFile.c_str(),RTLD_LAZY);
if(!Handle)
{
LOG_ERROR<<"load "<<soFile<<" error!";
LOG_ERROR<<dlerror();
} }
}); else
{
LOG_DEBUG<<"Successfully loaded library file "<<soFile;
}
}
return Handle;
} }

View File

@ -16,16 +16,22 @@
#include <trantor/utils/NonCopyable.h> #include <trantor/utils/NonCopyable.h>
#include <trantor/net/EventLoop.h> #include <trantor/net/EventLoop.h>
#include <unordered_map> #include <unordered_map>
#include <vector>
namespace drogon{ namespace drogon{
class SharedLibManager:public trantor::NonCopyable class SharedLibManager:public trantor::NonCopyable
{ {
public: public:
SharedLibManager(trantor::EventLoop *loop,const std::string viewPath); SharedLibManager(trantor::EventLoop *loop,const std::vector<std::string> & libPaths);
~SharedLibManager(){} ~SharedLibManager(){}
private: private:
void managerLibs(); void managerLibs();
trantor::EventLoop *_loop; trantor::EventLoop *_loop;
std::string _viewPath; std::vector<std::string> _libPaths;
std::unordered_map<std::string,void *> _dlMap; struct DLStat{
void * handle;
struct timespec mTime;
};
std::unordered_map<std::string,DLStat> _dlMap;
void* loadLibs(const std::string &sourceFile);
}; };
} }