diff --git a/.gitignore b/.gitignore index 81a453937..1eff11582 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,6 @@ *.swp *.swo *.out +*.so *.dSYM/ memgraph diff --git a/dc/README.md b/dc/README.md new file mode 100644 index 000000000..a4ba9a8ac --- /dev/null +++ b/dc/README.md @@ -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 +``` diff --git a/dc/dynamic_lib.hpp b/dc/dynamic_lib.hpp new file mode 100644 index 000000000..d7b96e2e1 --- /dev/null +++ b/dc/dynamic_lib.hpp @@ -0,0 +1,65 @@ +#ifndef MEMGRAPH_DL_DYNAMIC_LIB_HPP +#define MEMGRAPH_DL_DYNAMIC_LIB_HPP + +#include +#include +#include + +template +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 diff --git a/dc/example/db.hpp b/dc/example/db.hpp new file mode 100644 index 000000000..2c93e4c66 --- /dev/null +++ b/dc/example/db.hpp @@ -0,0 +1,25 @@ +#ifndef MEMGRAPH_DL_EXAMPLE_DB_HPP +#define MEMGRAPH_DL_EXAMPLE_DB_HPP + +#include + +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 diff --git a/dc/example/memsql.cpp b/dc/example/memsql.cpp new file mode 100644 index 000000000..b8fa37ef4 --- /dev/null +++ b/dc/example/memsql.cpp @@ -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; +} diff --git a/dc/example/mysql.cpp b/dc/example/mysql.cpp new file mode 100644 index 000000000..3b6c1bb2c --- /dev/null +++ b/dc/example/mysql.cpp @@ -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; +} diff --git a/dc/example/neo4j.cpp b/dc/example/neo4j.cpp new file mode 100644 index 000000000..0418bed74 --- /dev/null +++ b/dc/example/neo4j.cpp @@ -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; +} diff --git a/dc/example/postgresql.cpp b/dc/example/postgresql.cpp new file mode 100644 index 000000000..34b5445fe --- /dev/null +++ b/dc/example/postgresql.cpp @@ -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; +} diff --git a/dc/test.cpp b/dc/test.cpp new file mode 100644 index 000000000..d40c2ddd3 --- /dev/null +++ b/dc/test.cpp @@ -0,0 +1,84 @@ +#include +#include +#include +#include +#include +#include +#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& strings, const char *separator) +{ + std::ostringstream oss; + std::copy(strings.begin(), strings.end(), + std::ostream_iterator(oss, separator)); + return oss.str(); +} + +template +std::string prints(const Args&... args) +{ + std::vector strings = {args...}; + return join(strings, " "); +} + +// dependent on specific dynamic code +// "configuration" of DynamicLib +// DynamicLib +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 \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; + + 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; +} diff --git a/dc/tmp/.gitignore b/dc/tmp/.gitignore new file mode 100644 index 000000000..78d910160 --- /dev/null +++ b/dc/tmp/.gitignore @@ -0,0 +1,2 @@ +/* +!.gitignore