support dynamic libs compiling and loading
This commit is contained in:
parent
95b83206fb
commit
cc35b08580
|
@ -103,9 +103,20 @@ static void parseLine(std::ofstream &oSrcFile,std::string& line,const std::strin
|
||||||
|
|
||||||
void create_view::handleCommand(std::vector<std::string> ¶meters)
|
void create_view::handleCommand(std::vector<std::string> ¶meters)
|
||||||
{
|
{
|
||||||
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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
|
@ -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);
|
||||||
};
|
};
|
||||||
}
|
}
|
Loading…
Reference in New Issue