From 120743e59c4dab339de499ce3090203517437e35 Mon Sep 17 00:00:00 2001 From: Marko Budiselic Date: Sun, 25 Oct 2015 16:11:52 +0100 Subject: [PATCH] Much better but not perfect version of dynamic compile and dynamic load code. DynamicLib class and rudimentar example. --- dc/README.md | 5 ++++ dc/dynamic_lib.hpp | 65 ++++++++++++++++++++++++++++++++++++++++++++ dc/example/db.hpp | 10 +++++-- dc/test.cpp | 68 +++++++++++++++++++++++----------------------- 4 files changed, 112 insertions(+), 36 deletions(-) create mode 100644 dc/dynamic_lib.hpp diff --git a/dc/README.md b/dc/README.md index 116d58797..a4ba9a8ac 100644 --- a/dc/README.md +++ b/dc/README.md @@ -1,7 +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 index a507968df..2c93e4c66 100644 --- a/dc/example/db.hpp +++ b/dc/example/db.hpp @@ -8,8 +8,14 @@ using namespace std; class db { public: - virtual void name() const; - virtual void type() const; + // 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() {} }; diff --git a/dc/test.cpp b/dc/test.cpp index ba582ad92..d40c2ddd3 100644 --- a/dc/test.cpp +++ b/dc/test.cpp @@ -4,12 +4,11 @@ #include #include #include -#include #include "example/db.hpp" +#include "dynamic_lib.hpp" -// TODO: clang++ file.cpp -o file.so -shared -fPIC - -using namespace std; +using std::cout; +using std::endl; void write(const std::string& path, const std::string& content) { @@ -34,39 +33,24 @@ std::string prints(const Args&... args) return join(strings, " "); } -db* database(const std::string& lib_path, const std::string& factory_method) +// dependent on specific dynamic code +// "configuration" of DynamicLib +// DynamicLib +class MemgraphDynamicLib { - // load lib - void* db_lib = dlopen(lib_path.c_str(), RTLD_LAZY); - if (!db_lib) { - cerr << "Cannot load library: " << dlerror() << '\n'; - return nullptr; - } - dlerror(); - - // load produce method - produce_t produce_db = (produce_t) dlsym(db_lib, factory_method.c_str()); - const char* dlsym_error = dlerror(); - if (dlsym_error) { - cerr << "Cannot load symbol create: " << dlsym_error << '\n'; - return nullptr; - } - - // load destroy method - // destruct_t destruct_db = (destruct_t) dlsym(db_lib, "destruct"); - // dlsym_error = dlerror(); - // if (dlsym_error) { - // cerr << "Cannot load symbol destroy: " << dlsym_error << '\n'; - // return nullptr; - // } - - db *instance = produce_db(); - - return instance; -} +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; }"; @@ -74,11 +58,27 @@ int main() // 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 - db *mysql = database("./tmp/mysql.so", "produce"); + // -- 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; }