* 'master' of https://phabricator.tomicevic.com/diffusion/MG/memgraph:
  Much better but not perfect version of dynamic compile and dynamic load code. DynamicLib class and rudimentar example.
  dynamic lib load work in progress :P
  cpp program runs compile command, test only code
This commit is contained in:
Dominik Tomičević 2015-10-27 20:22:05 +01:00
commit c9c46f6cd3
10 changed files with 301 additions and 0 deletions

1
.gitignore vendored
View File

@ -4,5 +4,6 @@
*.swp
*.swo
*.out
*.so
*.dSYM/
memgraph

12
dc/README.md Normal file
View File

@ -0,0 +1,12 @@
## Dynamic Code
```
man nm
cd memgraph/dc
cd example
clang++ -std=c++1y mysql.cpp -o ../tmp/mysql.so -shared -fPIC
clang++ -std=c++1y memsql.cpp -o ../tmp/memsql.so -shared -fPIC
cd ..
clang++ -std=c++1y test.cpp -o test.out -ldl
```

65
dc/dynamic_lib.hpp Normal file
View File

@ -0,0 +1,65 @@
#ifndef MEMGRAPH_DL_DYNAMIC_LIB_HPP
#define MEMGRAPH_DL_DYNAMIC_LIB_HPP
#include <string>
#include <stdexcept>
#include <dlfcn.h>
template<typename T>
class DynamicLib
{
public:
typename T::produce produce_method;
typename T::destruct destruct_method;
DynamicLib(const std::string& lib_path) :
lib_path(lib_path)
{
}
void load()
{
load_lib();
load_produce_func();
load_destruct_func();
}
private:
std::string lib_path;
void *dynamic_lib;
void load_lib()
{
dynamic_lib = dlopen(lib_path.c_str(), RTLD_LAZY);
if (!dynamic_lib) {
throw std::runtime_error(dlerror());
}
dlerror();
}
void load_produce_func()
{
produce_method = (typename T::produce) dlsym(
dynamic_lib,
T::produce_name.c_str()
);
const char* dlsym_error = dlerror();
if (dlsym_error) {
throw std::runtime_error(dlsym_error);
}
}
void load_destruct_func()
{
destruct_method = (typename T::destruct) dlsym(
dynamic_lib,
T::destruct_name.c_str()
);
const char *dlsym_error = dlerror();
if (dlsym_error) {
throw std::runtime_error(dlsym_error);
}
}
};
#endif

25
dc/example/db.hpp Normal file
View File

@ -0,0 +1,25 @@
#ifndef MEMGRAPH_DL_EXAMPLE_DB_HPP
#define MEMGRAPH_DL_EXAMPLE_DB_HPP
#include <iostream>
using namespace std;
class db
{
public:
// If virtual methods don't have = 0 the compiler
// won't create appropriate _ZTI symbol inside
// the .so lib. That will lead to undefined symbol
// error while the library is loading.
//
// TODO: why?
virtual void name() const = 0;
virtual void type() const = 0;
virtual ~db() {}
};
typedef db* (*produce_t)();
typedef void (*destruct_t)(db*);
#endif

28
dc/example/memsql.cpp Normal file
View File

@ -0,0 +1,28 @@
#include "db.hpp"
class memsql : public db
{
public:
void name() const override
{
cout << "MemSQL" << endl;
}
void type() const override
{
cout << "InMemory" << endl;
}
~memsql() {}
};
extern "C" db* produce()
{
return new memsql();
}
extern "C" void destruct(db* p)
{
delete p;
}

28
dc/example/mysql.cpp Normal file
View File

@ -0,0 +1,28 @@
#include "db.hpp"
class mysql : public db
{
public:
virtual void name() const
{
cout << "MySQL" << endl;
}
virtual void type() const
{
cout << "Relational" << endl;
}
~mysql() {}
};
extern "C" db* produce()
{
return new mysql();
}
extern "C" void destruct(db* p)
{
delete p;
}

28
dc/example/neo4j.cpp Normal file
View File

@ -0,0 +1,28 @@
#include "db.hpp"
class neo4j : public db
{
public:
void name() const override
{
cout << "Neo4j" << endl;
}
void type() const override
{
cout << "Graph" << endl;
}
~neo4j() {}
};
extern "C" db* produce()
{
return new neo4j();
}
extern "C" void destruct(db* p)
{
delete p;
}

28
dc/example/postgresql.cpp Normal file
View File

@ -0,0 +1,28 @@
#include "db.hpp"
class postgresql : public db
{
public:
void name() const override
{
cout << "PostgreSQL" << endl;
}
void type() const override
{
cout << "Relational" << endl;
}
~postgresql() {}
};
extern "C" db* produce()
{
return new postgresql();
}
extern "C" void destruct(db* p)
{
delete p;
}

84
dc/test.cpp Normal file
View File

@ -0,0 +1,84 @@
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <iterator>
#include <cstdlib>
#include "example/db.hpp"
#include "dynamic_lib.hpp"
using std::cout;
using std::endl;
void write(const std::string& path, const std::string& content)
{
ofstream stream;
stream.open (path.c_str());
stream << content;
stream.close();
}
std::string join(const std::vector<std::string>& strings, const char *separator)
{
std::ostringstream oss;
std::copy(strings.begin(), strings.end(),
std::ostream_iterator<std::string>(oss, separator));
return oss.str();
}
template<typename... Args>
std::string prints(const Args&... args)
{
std::vector<std::string> strings = {args...};
return join(strings, " ");
}
// dependent on specific dynamic code
// "configuration" of DynamicLib
// DynamicLib<MemgraphDynamicLib>
class MemgraphDynamicLib
{
public:
const static std::string produce_name;
const static std::string destruct_name;
typedef produce_t produce;
typedef destruct_t destruct;
};
const std::string MemgraphDynamicLib::produce_name = "produce";
const std::string MemgraphDynamicLib::destruct_name = "destruct";
int main()
{
// -- compile example
// string tmp_file_path = "tmp/tmp.cpp";
// string tmp_so_path = "tmp/tmp.so";
// string for_compile = "#include <iostream>\nint main() { std::cout << \"test\" << std::endl; return 0; }";
// write(tmp_file_path, for_compile);
// string test_command = prints("clang++", tmp_file_path, "-o", "test.out");
// system(test_command.c_str());
// -- end compile example
// -- load example
using db_lib = DynamicLib<MemgraphDynamicLib>;
db_lib mysql_db("./tmp/mysql.so");
mysql_db.load();
auto mysql = mysql_db.produce_method();
if (mysql) {
mysql->name();
}
mysql_db.destruct_method(mysql);
db_lib memsql_db("./tmp/memsql.so");
memsql_db.load();
auto memsql = memsql_db.produce_method();
if (memsql) {
memsql->name();
}
memsql_db.destruct_method(memsql);
return 0;
}

2
dc/tmp/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/*
!.gitignore