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)
{
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;
return;
@ -137,8 +148,8 @@ int create_view::createViewFile(const std::string &script_filename)
className=className.substr(pos+1);
}
std::cout<<"className="<<className<<std::endl;
std::string headFileName=className+".h";
std::string sourceFilename=className+".cc";
std::string headFileName=_outputPath+"/"+className+".h";
std::string sourceFilename=_outputPath+"/"+className+".cc";
std::ofstream oHeadFile(headFileName.c_str(),std::ofstream::out);
std::ofstream oSourceFile(sourceFilename.c_str(),std::ofstream::out);
if(!oHeadFile||!oSourceFile)
@ -176,7 +187,12 @@ void create_view::newViewSourceFile(std::ofstream &file,const std::string &class
file <<"#include <map>\n";
file <<"#include <vector>\n";
file <<"#include <set>\n";
file <<"#include <iostream>\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;
char line[8192];
int import_flag=0;

View File

@ -26,7 +26,7 @@ namespace drogon_ctl
virtual std::string script() override {return "create view class files";}
protected:
std::string _outputPath=".";
void createViewFiles(std::vector<std::string> &cspFileNames);
int createViewFile(const std::string &script_filename);
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["p2"]=p2;
data.insert("parameters",para);
auto res=HttpResponse::newHttpViewResponse("ListParaView",data);
auto res=HttpResponse::newHttpViewResponse("DynamicListParaView.csp",data);
callback(*res);
}
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);
//start app framework
//drogon::HttpAppFramework::instance().enableDynamicSharedLibLoading();
drogon::HttpAppFramework::instance().enableDynamicSharedLibLoading({"/tmp/views"});
drogon::HttpAppFramework::instance().run();
}

View File

@ -79,6 +79,6 @@ namespace drogon
virtual const std::string & getDocumentRoot() const =0;
virtual void setDocumentRoot(const std::string &rootPath)=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 void setDocumentRoot(const std::string &rootPath) override {_rootPath=rootPath;}
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(){}
private:
std::vector<std::pair<std::string,uint16_t>> _listeners;
@ -111,7 +111,7 @@ namespace drogon
size_t _threadNum=1;
std::string _viewFilePath;
std::vector<std::string> _libFilePaths;
std::unique_ptr<SharedLibManager>_sharedLibManagerPtr;
@ -121,13 +121,21 @@ namespace drogon
using namespace drogon;
using namespace std::placeholders;
void HttpAppFrameworkImpl::enableDynamicSharedLibLoading(const std::string &viewPath)
void HttpAppFrameworkImpl::enableDynamicSharedLibLoading(const std::vector<std::string> &libPaths)
{
assert(!_running);
if(_viewFilePath.empty())
if(_libFilePaths.empty())
{
_viewFilePath=_rootPath+"/"+viewPath;
_sharedLibManagerPtr=std::unique_ptr<SharedLibManager>(new SharedLibManager(&_loop,_viewFilePath));
for(auto libpath:libPaths)
{
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)

View File

@ -14,14 +14,14 @@
#include "SharedLibManager.h"
#include <trantor/utils/Logger.h>
#include <drogon/config.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <dlfcn.h>
void *dlopen(const char *filename, int flag);
static void forEachFileIn(const std::string &path,const std::function<void (const std::string &filename)> &cb)
#include <fstream>
static void forEachFileIn(const std::string &path,const std::function<void (const std::string &,const struct stat &)> &cb)
{
DIR* dp;
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(S_ISDIR(st.st_mode))
continue;
cb(fullname);
cb(fullname,st);
}
return;
}
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),
_viewPath(viewPath)
_libPaths(libPaths)
{
_loop->runEvery(5.0,[=](){
managerLibs();
@ -72,30 +72,89 @@ _viewPath(viewPath)
}
void SharedLibManager::managerLibs()
{
LOG_DEBUG<<"manager .so libs in path "<<_viewPath;
forEachFileIn(_viewPath,[=](const std::string &filename){
LOG_DEBUG<<filename;
auto pos=filename.rfind(".");
if(pos!=std::string::npos)
{
auto exName=filename.substr(pos+1);
if(exName=="so")
for(auto libPath:_libPaths)
{
forEachFileIn(libPath,[=](const std::string &filename,const struct stat &st){
//LOG_DEBUG<<filename;
auto pos=filename.rfind(".");
if(pos!=std::string::npos)
{
//loading so file;
if(_dlMap.find(filename)!=_dlMap.end())
return;
auto Handle=dlopen(filename.c_str(),RTLD_NOW);
if(!Handle)
auto exName=filename.substr(pos+1);
if(exName=="csp")
{
LOG_ERROR<<"load "<<filename<<" error!";
LOG_ERROR<<dlerror();
}
else
{
LOG_DEBUG<<"Successfully loaded library file "<<filename;
_dlMap[filename]=Handle;
//compile
auto lockFile=filename+".lock";
std::ifstream fin(lockFile);
if (fin) {
return;
}
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/net/EventLoop.h>
#include <unordered_map>
#include <vector>
namespace drogon{
class SharedLibManager:public trantor::NonCopyable
{
public:
SharedLibManager(trantor::EventLoop *loop,const std::string viewPath);
SharedLibManager(trantor::EventLoop *loop,const std::vector<std::string> & libPaths);
~SharedLibManager(){}
private:
void managerLibs();
trantor::EventLoop *_loop;
std::string _viewPath;
std::unordered_map<std::string,void *> _dlMap;
std::vector<std::string> _libPaths;
struct DLStat{
void * handle;
struct timespec mTime;
};
std::unordered_map<std::string,DLStat> _dlMap;
void* loadLibs(const std::string &sourceFile);
};
}