Commit 25528296 authored by Leander Schulten's avatar Leander Schulten
Browse files

Changed the internal module system and how modules gets loaded.

Alle Module(Programme, Filter, Consumer) sind jetzt an eine Lib gebunden, wenn diese ungeladen wird, werden diese alle mitentfernt. Module haben nur einen normalen Pfad(../../Test) und bekommen erst vom ModuleManager einen freien Platz von dem noch keine Lib geladen wurde, da es sonst zu Problemen kommt(z.B. ../../Test____1.so)
parent e432c672
......@@ -814,11 +814,10 @@ void CodeEditorHelper::compile(){
stream << "}" << endl;
stream.flush();
file.close();
#ifdef Q_OS_WIN
auto result = Modules::Compiler::compileToLibrary(file,module->getName()+".dll");
#else
auto result = Modules::Compiler::compileToLibrary(file,module->getName()+".so");
#endif
auto result = Modules::Compiler::compileAndLoadModule(file,module->getName());
if(result.first){
QFileInfo finfo = file;
emit information(result.second.replace(finfo.absoluteFilePath(),""));
......
......@@ -48,6 +48,8 @@ int main(int argc, char *argv[])
/*Test::TestModulSystem testModulSystem;
testModulSystem.runTest();
return 0;*/
// init the rand function for different random numbers each startup
srand(static_cast<unsigned int>(time(nullptr)));
Test::testSampleClass();
......
......@@ -22,24 +22,29 @@ Compiler::Compiler()
}
/**
* @brief Compiler::compileToLibrary compiles the code in the file to a module Library
* @note Unloads the old Library found at newLibraryFile and loads the new Library, replacing all
* old Programs/Filters/Consumers in ProgramBlockManager by new in instances
* @param file a FileInfo Object describing the file where the code is in
* @param newLibraryFile the FilePath of the new Library
* @return return code from the compiler and the output of the compiler
*/
std::pair<int,QString> Compiler::compileToLibrary(const QFileInfo &file,const QString &newLibraryFile){
std::pair<int,QString> Compiler::compileAndLoadModule(const QFileInfo &sourceCode, const QString &moduleName){
auto moduleFilePath = sourceCode.absolutePath() + "/" + moduleName;
auto result = compileToLibrary(sourceCode,moduleFilePath);
if(result.first == 0){
ModuleManager::singletone()->unloadLibrary(moduleFilePath);
ModuleManager::singletone()->loadModule(ModuleManager::singletone()->getFreeAbsoluteFilePathForModule(moduleFilePath));
}
return result;
}
std::pair<int,QString> Compiler::compileToLibrary(const QFileInfo &file,const QString &absoluteNewLibraryFilePath){
QString tempOutputFileName = absoluteNewLibraryFilePath+QString::number(rand());
QProcess p;
#ifdef Q_OS_MAC
p.setEnvironment(QProcess::systemEnvironment()<<"PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/Library/TeX/texbin:/usr/local/MacGPG2/bin:/usr/local/share/dotnet:/opt/X11/bin:/Library/Frameworks/Mono.framework/Versions/Current/Commands");
QString cmd = compilerCmd + " "+ compilerLibraryFlags + " " + compilerFlags + " " + file.absoluteFilePath() + " -o " + file.absolutePath()+"/"+newLibraryFile + ".temp" + " -I\"/"+includePath + "\" ";
//p.setEnvironment(QProcess::systemEnvironment()<<"PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/Library/TeX/texbin:/usr/local/MacGPG2/bin:/usr/local/share/dotnet:/opt/X11/bin:/Library/Frameworks/Mono.framework/Versions/Current/Commands");
QString cmd = compilerCmd + " "+ compilerLibraryFlags + " " + compilerFlags + " " + file.absoluteFilePath() + " -o " + tempOutputFileName + " -I\"/"+includePath + "\" ";
p.start("bash", QStringList() << "-c" << cmd);
#elif defined(Q_OS_WIN)
QString tempName=newLibraryFile + ".o";
QString tempName=tempOutputFileName + ".o";
QString compilerCMD = compilerCmd.right(compilerCmd.length()-compilerCmd.lastIndexOf('/')-1);
QString cmd = /*".\\" + */ compilerCMD + " -c \"" + file.absoluteFilePath() + "\" " + compilerFlags + " -o \"" + file.absolutePath() + "/" + tempName+"\" -I\"" + includePath + "\" ";
QString cmd = /*".\\" + */ compilerCMD + " -c \"" + file.absoluteFilePath() + "\" " + compilerFlags + " -o \"" + tempName+"\" -I\"" + includePath + "\" ";
cmd = "\" " + cmd + " \"";
qDebug().noquote() << cmd;
/*
......@@ -63,29 +68,22 @@ std::pair<int,QString> Compiler::compileToLibrary(const QFileInfo &file,const QS
if(p.exitCode() != 0){
qDebug() << p.errorString();
qDebug() << p.error();
//qDebug().noquote() << cmd;
}else{
#ifdef Q_OS_WIN
// we have to unload the existing lib first
ModuleManager::singletone()->singletone()->unloadLibrary(file.absolutePath() + "/" + newLibraryFile);
// we only have a .o ans need a .dll
// cmd: g++ -shared -o foo.dll foo.dll.o
QProcess oToDll;
oToDll.setEnvironment(QStringList() <<"PATH"<< compilerCmd.left(compilerCmd.lastIndexOf('/')));
oToDll.start("cmd /c \" " + compilerCMD + " " + compilerLibraryFlags + " -o \"" + file.absolutePath() + "/" + newLibraryFile +"\" \""+ file.absolutePath() + "/" + tempName +"\" \"");
oToDll.start("cmd /c \" " + compilerCMD + " " + compilerLibraryFlags + " -o \"" + tempOutputFileName +"\" \""+ tempName +"\" \"");
oToDll.waitForFinished();
if(oToDll.exitCode() == 0){
ModuleManager::singletone()->singletone()->loadModule(file.absolutePath() + "/" + newLibraryFile);
}
QFile::rename(tempOutputFileName,absoluteNewLibraryFilePath);
QFile::remove(tempName);
return{oToDll.exitCode(),oToDll.readAllStandardError()};
#endif
#ifdef Q_OS_MAC
// we have to unload the existing lib first
if(p.exitCode()==0){
ModuleManager::singletone()->unloadLibrary(file.absolutePath() + "/" + newLibraryFile);
QFile(file.absolutePath() + "/" + newLibraryFile + ".temp").rename(file.absolutePath() + "/" + newLibraryFile);
ModuleManager::singletone()->loadModule(file.absolutePath() + "/" + newLibraryFile);
Q_ASSERT(QFile::rename(tempOutputFileName,absoluteNewLibraryFilePath));
}
#endif
}
......
......@@ -15,7 +15,17 @@ public:
public:
Compiler();
static void setCompilerCommand(QString s){compilerCmd = s;}
static std::pair<int,QString> compileToLibrary(const QFileInfo &file,const QString &newLibraryFile);
/**
* @brief Compiler::compileAndLoadModule compiles the code in the file to a module Library and load the module(and unload the old)
* @note Unloads the old Library with the same name and loads the new Library, replacing all
* old Programs/Filters/Consumers in ProgramBlockManager by new in instances
* @param file a FileInfo Object describing the file where the code is in
* @param moduleName the name of the Module
* @return return code from the compiler and the output of the compiler
*/
static std::pair<int,QString> compileAndLoadModule(const QFileInfo &sourceCode, const QString &moduleName);
static std::pair<int,QString> compileToLibrary(const QFileInfo &file, const QString &absoluteNewLibraryFilePath);
static std::pair<int,QString> compileToLibrary(const QString &code,const QString &newLibraryFile);
};
......
......@@ -87,17 +87,31 @@ typedef Modules::Program* (*CreateProgramm)(unsigned int index);
bool ModuleManager::unloadLibrary(QString filePath){
for(auto e = loadedLibraryMap.begin();e!=loadedLibraryMap.end();++e){
qDebug()<<e->first;
if(e->first == filePath){
filter.erase(std::remove_if(filter.begin(),filter.end(),[&](const auto &f){
return f.libraryIdentifier == e->second.libraryIdentifier;
}),filter.cend());
programms.erase(std::remove_if(programms.begin(),programms.end(),[&](const auto &f){
return f.libraryIdentifier == e->second.libraryIdentifier;
}),programms.cend());
consumer.erase(std::remove_if(consumer.begin(),consumer.end(),[&](const auto &f){
return f.libraryIdentifier == e->second.libraryIdentifier;
}),consumer.cend());
QLibrary lib(filePath);
qDebug()<<filePath+"____";
// add "____" to avoid subname conflicts. eg we unload print ans e have name print_super
if(e->first.startsWith(filePath+"____",Qt::CaseInsensitive)){
for(auto it = filter.cbegin();it != filter.cend();){
if(it->libraryIdentifier == e->second.libraryIdentifier){
it = filter.erase(it);
}else{
++it;
}
}
for(auto it = programms.cbegin();it != programms.cend();){
if(it->libraryIdentifier == e->second.libraryIdentifier){
it = programms.erase(it);
}else{
++it;
}
}
for(auto it = consumer.cbegin();it != consumer.cend();){
if(it->libraryIdentifier == e->second.libraryIdentifier){
it = consumer.erase(it);
}else{
++it;
}
}
QLibrary lib(e->first);
bool suc = lib.unload();
if(suc){
loadedLibraryMap.erase(e);
......@@ -107,11 +121,7 @@ typedef Modules::Program* (*CreateProgramm)(unsigned int index);
}
return true;
}
int counter = 0;
while (QFile::exists(filePath+ QString::number(counter)+".old")) {
++counter;
}
suc = QFile(filePath).rename(filePath+ QString::number(counter)+".old");
suc = QFile::rename(e->first,e->first+ ".old");
if(suc){
loadedLibraryMap.erase(e);
}
......@@ -131,7 +141,26 @@ typedef Modules::Program* (*CreateProgramm)(unsigned int index);
o["modules"] = a;
}
QString ModuleManager::getFreeAbsoluteFilePathForModule(const QString & name)const{
#ifdef Q_OS_WIN
#define SHARED_LIB_FILE_SUFFIX ".dll"
#else
#define SHARED_LIB_FILE_SUFFIX ".so"
#endif
for(int counter = 0; ;++counter){
auto fileName = name + "____" + QString::number(counter)+ SHARED_LIB_FILE_SUFFIX;
if(!QFileInfo::exists(fileName)&&!QFileInfo::exists(fileName+".old")){
Q_ASSERT(QFile::rename(name,fileName));
return fileName;
}
}
}
void ModuleManager::loadModule(QString name, bool replaceNewInPBs){
if(!QLibrary::isLibrary(name))
return;
qDebug()<<"load lib : " << name;
QLibrary lib(name);
if(lib.load()){
......@@ -140,18 +169,39 @@ typedef Modules::Program* (*CreateProgramm)(unsigned int index);
qDebug()<<"have funktion is missing";
return;
}
auto lastProgram = programms.size();
auto lastFilter = filter .size();
auto lastConsumer = consumer .size();
if(f(MODUL_TYPE::Program)){
loadType(lib,programms,"Program",lastLibraryIdentifier);
loadType(lib,programms,"Program",lastLibraryIdentifier,[&](const auto p){
if(replaceNewInPBs){
for(const auto & pb : ProgramBlockManager::model){
for(const auto & v : pb->getUsedProgramsByName(p->name())){
pb->replaceProgram(v,std::shared_ptr<Program>(p->create()));
}
}
}
});
}if(f(MODUL_TYPE::LoopProgram)){
//loadType(lib,programms,"LoopProgramm",lastLibraryIdentifier);
}if(f(MODUL_TYPE::Filter)){
loadType(lib,filter,"Filter",lastLibraryIdentifier);
loadType(lib,filter,"Filter",lastLibraryIdentifier,[&](const auto p){
if(replaceNewInPBs){
for(const auto & pb : ProgramBlockManager::model){
for(const auto & v : pb->getUsedFiltersByName(p->name())){
pb->replaceFilter(v,std::shared_ptr<Filter>(p->create()));
}
}
}
});
}if(f(MODUL_TYPE::Consumer)){
qDebug()<< "Loading Consumer";
loadType(lib,consumer,"Consumer",lastLibraryIdentifier);
loadType(lib,consumer,"Consumer",lastLibraryIdentifier,[&](const auto p){
if(replaceNewInPBs){
for(const auto & pb : ProgramBlockManager::model){
for(const auto & v : pb->getUsedConsumersByName(p->name())){
pb->replaceConsumer(v,std::shared_ptr<Consumer>(p->create()));
}
}
}
});
}
SupportAudioFunc supportAudioFunc = nullptr;
if(f(MODUL_TYPE::Audio)){
......@@ -160,25 +210,7 @@ typedef Modules::Program* (*CreateProgramm)(unsigned int index);
}
lastLibraryIdentifier++;
loadedLibraryMap.emplace_back(lib.fileName(),LibInfo{lastLibraryIdentifier,supportAudioFunc});
if(replaceNewInPBs){
for(const auto & pb : ProgramBlockManager::model){
for(;lastProgram<programms.size();lastProgram++){
for(const auto & v : pb->getUsedProgramsByName(programms[lastProgram].name())){
pb->replaceProgram(v,std::shared_ptr<Program>(programms[lastProgram].create()));
}
}
for(;lastFilter<filter.size();lastFilter++){
for(const auto & v : pb->getUsedFiltersByName(filter[lastFilter].name())){
pb->replaceFilter(v,std::shared_ptr<Filter>(filter[lastFilter].create()));
}
}
for(;lastConsumer<consumer.size();lastConsumer++){
for(const auto & v : pb->getUsedConsumersByName(consumer[lastConsumer].name())){
pb->replaceConsumer(v,std::shared_ptr<Consumer>(consumer[lastConsumer].create()));
}
}
}
}
qDebug() << lib.errorString();
}else{
qDebug()<<"Cant load lib :" << name<< " because : " << lib.errorString() ;
}
......
......@@ -214,8 +214,7 @@ signals:
std::string description_;
public:
int libraryIdentifier = -1;
Entry(const std::string& name,const std::string& description):name_(name),description_(description){}
Entry(const std::string& name,const std::string& description,CreateFunction func):createFunc(func),name_(name),description_(description){}
Entry(const std::string& name,const std::string& description,int libraryIdentifier = -1, CreateFunction func = nullptr):createFunc(func),name_(name),description_(description),libraryIdentifier(libraryIdentifier){}
const std::string& name()const{return name_;}
const std::string& description()const{return description_;}
T* create()const{
......@@ -223,6 +222,9 @@ signals:
return createFunc();
return nullptr;
}
bool operator<(const Entry<T> &other)const{
return this->name_ < other.name_;
}
};
}
......@@ -231,9 +233,11 @@ signals:
*/
class ModuleManager
{
typedef std::vector<detail::Entry<Program>> ProgrammModulContainer;
typedef std::vector<detail::Entry<Filter>> FilterModulContainer;
typedef std::vector<detail::Entry<Consumer>> ConsumerModulContainer;
template<typename T>
using ModuleContainer = std::set<T>;
typedef ModuleContainer<detail::Entry<Program>> ProgrammModuleContainer;
typedef ModuleContainer<detail::Entry<Filter>> FilterModuleContainer;
typedef ModuleContainer<detail::Entry<Consumer>> ConsumerModuleContainer;
typedef void (*SupportAudioFunc)(bool);
struct LibInfo{
int libraryIdentifier = -1;
......@@ -242,42 +246,50 @@ signals:
std::vector<std::pair<QString,LibInfo>> loadedLibraryMap;
int lastLibraryIdentifier = 0;
ModelVector<Module*> modules;
ProgrammModulContainer programms;
ProgrammModuleContainer programms;
//std::vector<detail::Entry<Programm>> programms;
FilterModulContainer filter;
ConsumerModulContainer consumer;
FilterModuleContainer filter;
ConsumerModuleContainer consumer;
Controller controller_;
FFTOutputView<float> fftOutputView;
private:
template<typename Type, typename String>
static void loadType(QLibrary & lib, std::vector<detail::Entry<Type>> &c,String name, int libraryIdentifier);
template<typename Type, typename String, typename Callback>
static void loadType(QLibrary & lib, ModuleContainer<detail::Entry<Type>> &c,String name, int libraryIdentifier, Callback = nullptr);
static SupportAudioFunc loadAudio(QLibrary & lib,Modules::FFTOutputView<float> * fftOutputView);
public:
ModuleManager();
~ModuleManager(){for(auto m : modules)delete m;}
/**
* @brief getFreeAbsoluteFilePathForModule if you have a new compiled module that is not loaded, you can get here a new free name.
* @note Important! If you use an old file name, maybe the old lib gets loaded, even when you delete the file
* @param moduleFilePath
* @return
*/
QString getFreeAbsoluteFilePathForModule(const QString &moduleFilePath)const;
void loadModules(const QJsonObject &o);
bool unloadLibrary(QString filePath);
void writeJsonObject(QJsonObject &o);
Controller & controller(){return controller_;}
static ModuleManager * singletone(){static ModuleManager m;return &m;}
/**
* @brief loadModule loads the shared library(module) given by the filePath
* @param name the filePath of the shared library that should be loaded
* @brief loadModule loads the shared library(module) given by the filePath, if fileNamePath is no shared lib, nothing will happen
* @param fileNamePath the filePath of the shared library that should be loaded
* @param replaceNewImProgramBlocks if new programs/filters/consumers are loaded and old programs/filters/consumers are found in ProgramBlocks, they get replaced by new ones
*/
void loadModule(QString name, bool replaceNewImProgramBlocks = true);
void loadModule(QString fileNamePath, bool replaceNewImProgramBlocks = true);
void loadAllModulesInDir(QDir name);
ModelVector<Module*>* getModules(){return &modules;}
const ProgrammModulContainer & getProgrammModules(){return programms;}
const FilterModulContainer & getFilterModules(){return filter;}
const ConsumerModulContainer & getConsumerModules(){return consumer;}
const ProgrammModuleContainer & getProgrammModules(){return programms;}
const FilterModuleContainer & getFilterModules(){return filter;}
const ConsumerModuleContainer & getConsumerModules(){return consumer;}
std::shared_ptr<Program> createProgramm(const std::string & name){return createByName(programms,name);}
std::shared_ptr<Filter> createFilter (const std::string & name){return createByName(filter ,name);}
std::shared_ptr<Consumer> createConsumer(const std::string & name){return createByName(consumer ,name);}
protected:
template<typename T>
static std::shared_ptr<T> createByName(const std::vector<detail::Entry<T>> & c, const std::string &name){
static std::shared_ptr<T> createByName(const std::set<detail::Entry<T>> & c, const std::string &name){
for(auto i = c.cbegin() ; i != c.cend();++i){
if(i->name() == name)
return std::shared_ptr<T>(i->create());
......@@ -291,8 +303,8 @@ signals:
typedef char const * (*GetDescriptionOfXXX)(unsigned int index);
template<typename Type, typename String >
void ModuleManager::loadType(QLibrary & lib, std::vector<detail::Entry<Type>> &c , String Typename, int libraryIdentifier){
template<typename Type, typename String,typename Callback >
void ModuleManager::loadType(QLibrary & lib, ModuleContainer<detail::Entry<Type>> &c , String Typename, int libraryIdentifier, Callback callback){
const auto getNumberOfName = std::string("getNumberOf") + Typename + "s";
const auto getNameOfName = std::string("getNameOf") + Typename;
const auto getDescriptionOfName = std::string("getDescriptionOf") + Typename;
......@@ -306,13 +318,21 @@ signals:
std::cout << "Functions are missing : " << getNumberOfName <<" : " <<getNumberOfProgramms << " , " <<getNameOfName<<" : " <<getNameOfProgramm<<" , " <<getDescriptionOfName<<" : " <<getDescriptionOfProgramm<<" , " <<createName<<" : " <<createProgramm;
return;
}
for(unsigned int i = 0 ; i < getNumberOfProgramms();++i){
for(unsigned int i = 0 ; i < getNumberOfProgramms();++i){
const auto name = getNameOfProgramm(i);
const auto desc = getDescriptionOfProgramm(i);
const auto func = [=](){return createProgramm(i);};
c.emplace_back(name,desc,func);
c.back().libraryIdentifier = libraryIdentifier;
auto iter = c.find({name,desc});
const detail::Entry<Type> * p;
if(iter!=c.cend()){ // remove old entry if exists
iter = c.erase(iter);
auto tempIter = c.emplace(name,desc,libraryIdentifier,func).first;
Q_ASSERT(tempIter != c.cend());
p = &*tempIter;
}else{
p = &*c.emplace(name,desc,libraryIdentifier,func).first;
}
callback(p);
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment