Mercurial > malikania
changeset 40:1e206fdc7021
Server: switch to Boost.DLL, closes #583
author | David Demelier <markand@malikania.fr> |
---|---|
date | Sun, 27 Nov 2016 20:00:13 +0100 |
parents | 56ab2f0c90dc |
children | 3645200f46bf |
files | CMakeLists.txt database/sqlite/src/account.cpp database/sqlite/src/driver.cpp libserver/CMakeLists.txt libserver/malikania/dao-account.cpp libserver/malikania/database.cpp libserver/malikania/database.hpp libserver/malikania/dynlib.hpp |
diffstat | 8 files changed, 56 insertions(+), 380 deletions(-) [+] |
line wrap: on
line diff
--- a/CMakeLists.txt Sun Nov 27 18:00:49 2016 +0100 +++ b/CMakeLists.txt Sun Nov 27 20:00:13 2016 +0100 @@ -43,8 +43,9 @@ include_directories(${CMAKE_BINARY_DIR}) enable_testing() +find_package(Boost REQUIRED COMPONENTS filesystem system) +find_package(OpenSSL REQUIRED) find_package(ZIP REQUIRED) -find_package(OpenSSL REQUIRED) add_subdirectory(extern) add_subdirectory(database)
--- a/database/sqlite/src/account.cpp Sun Nov 27 18:00:49 2016 +0100 +++ b/database/sqlite/src/account.cpp Sun Nov 27 20:00:13 2016 +0100 @@ -16,10 +16,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <boost/dll.hpp> + #include <vector> #include <malikania/account.hpp> -#include <malikania/dynlib.hpp> #include "driver.hpp" @@ -86,7 +87,7 @@ extern "C" { -DYNLIB_EXPORT void malikania_account_create(Account& account) +BOOST_SYMBOL_EXPORT void malikania_account_create(Account& account) { auto stmt = sqlite::prepare(create_query); @@ -103,7 +104,7 @@ account.setId(sqlite3_last_insert_rowid(sqlite::database.get())); } -DYNLIB_EXPORT void malikania_account_update(Account& account) +BOOST_SYMBOL_EXPORT void malikania_account_update(Account& account) { auto stmt = sqlite::prepare(update_query); @@ -119,7 +120,7 @@ } } -DYNLIB_EXPORT void malikania_account_remove(const Account& account) +BOOST_SYMBOL_EXPORT void malikania_account_remove(const Account& account) { auto stmt = sqlite::prepare(delete_query); @@ -130,7 +131,7 @@ } } -DYNLIB_EXPORT Account malikania_account_get(std::uint64_t id) +BOOST_SYMBOL_EXPORT Account malikania_account_get(std::uint64_t id) { auto stmt = sqlite::prepare(get_query); @@ -143,7 +144,7 @@ return to_account(stmt); } -DYNLIB_EXPORT std::vector<Account> malikania_account_list() +BOOST_SYMBOL_EXPORT std::vector<Account> malikania_account_list() { auto stmt = sqlite::prepare(list_query); @@ -156,14 +157,14 @@ return list; } -DYNLIB_EXPORT void malikania_account_clear() +BOOST_SYMBOL_EXPORT void malikania_account_clear() { if (sqlite3_exec(sqlite::database.get(), clear_query.c_str(), nullptr, nullptr, nullptr) != SQLITE_OK) { throw std::runtime_error(sqlite3_errmsg(sqlite::database.get())); } } -DYNLIB_EXPORT std::uint64_t malikania_account_count() +BOOST_SYMBOL_EXPORT std::uint64_t malikania_account_count() { auto stmt = sqlite::prepare(count_query);
--- a/database/sqlite/src/driver.cpp Sun Nov 27 18:00:49 2016 +0100 +++ b/database/sqlite/src/driver.cpp Sun Nov 27 20:00:13 2016 +0100 @@ -1,8 +1,8 @@ +#include <boost/dll.hpp> + #include <unordered_map> #include <string> -#include <malikania/dynlib.hpp> - #include "driver.hpp" namespace sqlite { @@ -24,7 +24,7 @@ extern "C" { -DYNLIB_EXPORT void malikania_driver_load(const std::unordered_map<std::string, std::string>& params) +BOOST_SYMBOL_EXPORT void malikania_driver_load(const std::unordered_map<std::string, std::string>& params) { auto path = params.find("path"); @@ -48,7 +48,7 @@ #endif } -DYNLIB_EXPORT void malikania_driver_unload() +BOOST_SYMBOL_EXPORT void malikania_driver_unload() { // Explicit destruction, optional. sqlite::database = nullptr;
--- a/libserver/CMakeLists.txt Sun Nov 27 18:00:49 2016 +0100 +++ b/libserver/CMakeLists.txt Sun Nov 27 20:00:13 2016 +0100 @@ -23,7 +23,6 @@ ${libmlk-server_SOURCE_DIR}/malikania/account.hpp ${libmlk-server_SOURCE_DIR}/malikania/dao-account.hpp ${libmlk-server_SOURCE_DIR}/malikania/database.hpp - ${libmlk-server_SOURCE_DIR}/malikania/dynlib.hpp ) set( @@ -35,7 +34,10 @@ malikania_create_library( TARGET libmlk-server SOURCES ${HEADERS} ${SOURCES} - LIBRARIES libcommon + LIBRARIES + ${Boost_LIBRARIES} + libcommon + PUBLIC_INCLUDES + ${Boost_INCLUDE_DIRS} + ${libmlk-server_SOURCE_DIR} ) - -target_include_directories(libmlk-server PUBLIC ${libmlk-server_SOURCE_DIR})
--- a/libserver/malikania/dao-account.cpp Sun Nov 27 18:00:49 2016 +0100 +++ b/libserver/malikania/dao-account.cpp Sun Nov 27 20:00:13 2016 +0100 @@ -22,47 +22,47 @@ namespace malikania { -using Create = void (*)(Account &); -using Remove = void (*)(const Account &); -using Update = void (*)(Account &); -using Get = Account (*)(std::uint64_t); -using List = std::vector<Account> (*)(); -using Count = std::uint64_t (*)(); -using Clear = void (*)(); +using Create = void (Account&); +using Remove = void (const Account&); +using Update = void (Account&); +using Get = Account (std::uint64_t); +using List = std::vector<Account> (); +using Count = std::uint64_t (); +using Clear = void (); void AccountDao::create(Account &account) { - m_database.handle().sym<Create>("malikania_account_create")(account); + m_database.handle().get<Create>("malikania_account_create")(account); } void AccountDao::remove(const Account &account) { - m_database.handle().sym<Remove>("malikania_account_remove")(account); + m_database.handle().get<Remove>("malikania_account_remove")(account); } void AccountDao::update(Account &account) { - m_database.handle().sym<Update>("malikania_account_update")(account); + m_database.handle().get<Update>("malikania_account_update")(account); } Account AccountDao::get(uint64_t id) { - return m_database.handle().sym<Get>("malikania_account_get")(id); + return m_database.handle().get<Get>("malikania_account_get")(id); } std::vector<Account> AccountDao::list() { - return m_database.handle().sym<List>("malikania_account_list")(); + return m_database.handle().get<List>("malikania_account_list")(); } std::uint64_t AccountDao::count() { - return m_database.handle().sym<Count>("malikania_account_count")(); + return m_database.handle().get<Count>("malikania_account_count")(); } void AccountDao::clear() { - m_database.handle().sym<Clear>("malikania_account_clear")(); + m_database.handle().get<Clear>("malikania_account_clear")(); } } // !malikania
--- a/libserver/malikania/database.cpp Sun Nov 27 18:00:49 2016 +0100 +++ b/libserver/malikania/database.cpp Sun Nov 27 20:00:13 2016 +0100 @@ -20,20 +20,18 @@ namespace malikania { -using Load = void (*)(const std::unordered_map<std::string, std::string> &); -using Unload = void (*)(); - -// TODO: is path is relative, search for it +using Load = void (const std::unordered_map<std::string, std::string>&); +using Unload = void (); Database::Database(const std::string &path, const std::unordered_map<std::string, std::string> ¶ms) : m_dso(path) { - m_dso.sym<Load>("malikania_driver_load")(params); + m_dso.get<Load>("malikania_driver_load")(params); } Database::~Database() { - m_dso.sym<Unload>("malikania_driver_unload")(); + m_dso.get<Unload>("malikania_driver_unload")(); } } // !malikania
--- a/libserver/malikania/database.hpp Sun Nov 27 18:00:49 2016 +0100 +++ b/libserver/malikania/database.hpp Sun Nov 27 20:00:13 2016 +0100 @@ -24,11 +24,11 @@ * \brief Generic database loader. */ +#include <boost/dll.hpp> + #include <string> #include <unordered_map> -#include "dynlib.hpp" - namespace malikania { /** @@ -36,7 +36,7 @@ */ class Database { private: - Dynlib m_dso; + boost::dll::shared_library m_dso; public: /** @@ -56,9 +56,21 @@ ~Database(); /** - * Get the associated dynlib handle. + * Get the associated dso handle. + * + * \return the handle */ - inline Dynlib &handle() noexcept + inline const boost::dll::shared_library& handle() const noexcept + { + return m_dso; + } + + /** + * Overloaded function + * + * \return the handle + */ + inline boost::dll::shared_library& handle() noexcept { return m_dso; }
--- a/libserver/malikania/dynlib.hpp Sun Nov 27 18:00:49 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,338 +0,0 @@ -/* - * dynlib.hpp -- portable shared library loader - * - * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef DYNLIB_HPP -#define DYNLIB_HPP - -/** - * \file dynlib.hpp - * \brief Portable shared library loader. - * \author David Demelier <markand@malikania.fr> - */ - -/** - * \page Dynlib Dynlib - * \brief Portable shared library loader. - * - * The dynlib module let you open shared libraries dynamically at runtime. - * - * ## Operating system support - * - * | System | Support | Remarks | - * |---------|---------|--------------------| - * | Apple | Ok | | - * | FreeBSD | Ok | | - * | Linux | Ok | Needs -ldl library | - * | Windows | Ok | | - * - * ## How to export symbols - * - * When you want to dynamically load symbols from your shared library, make sure they are in a `extern "C"` block, if - * not they will be [mangled][name-mangling]. - * - * Note, this does not mean that you can't write C++ code, it just mean that you can't use namespaces and function - * overloading. - * - * Example of **plugin.cpp**: - * - * ````cpp - * #include <iostream> - * - * #include "dynlib.hpp" - * - * extern "C" { - * - * DYNLIB_EXPORT void plugin_load() - * { - * std::cout << "Loading plugin" << std::endl; - * } - * - * DYNLIB_EXPORT void plugin_unload() - * { - * std::cout << "Unloading plugin" << std::endl; - * } - * - * } - * ```` - * - * The \ref DYNLIB_EXPORT macro is necessary on some platforms to be sure that symbol will be visible. Make sure you always - * add it before any function. - * - * To compile, see your compiler documentation or build system. For gcc you can use the following: - * - * ```` - * gcc -std=c++14 -shared plugin.cpp -o plugin.so - * ```` - * - * ## How to load the library - * - * The dynlib module will search for the library in various places, thus you can use relative paths names but be sure - * that the library can be found. Otherwise, just use an absolute path to the file. - * - * ````cpp - * #include <iostream> - * - * #include "dynlib.hpp" - * - * int main() - * { - * try { - * Dynlib dso("./plugin" DYNLIB_SUFFIX); - * } catch (const std::exception &ex) { - * std::cerr << ex.what() << std::endl; - * } - * - * return 0; - * } - * ```` - * - * ## How to load symbol - * - * The last part is symbol loading, you muse use raw C function pointer and the Dynlib::sym function. - * - * ````cpp - * #include <iostream> - * - * #include "dynlib.hpp" - * - * using PluginLoad = void (*)(); - * using PluginUnload = void (*)(); - * - * int main() - * { - * try { - * Dynlib dso("./plugin" DYNLIB_SUFFIX); - * - * dso.sym<PluginLoad>("plugin_load")(); - * dso.sym<PluginUnload>("plugin_unload")(); - * } catch (const std::exception &ex) { - * std::cerr << ex.what() << std::endl; - * } - * - * return 0; - * } - * ```` - * - * [name-mangling]: https://en.wikipedia.org/wiki/Name_mangling - */ - -#include <stdexcept> -#include <string> - -#if defined(_WIN32) -# include <Windows.h> -#else -# include <dlfcn.h> -#endif - -/** - * \brief Export the symbol. - * - * This is required on some platforms and you should put it before your function signature. - * - * \code{.cpp} - * extern "C" { - * - * DYNLIB_EXPORT void my_function() - * { - * } - * - * } - * \endcode - */ -#if defined(_WIN32) -# define DYNLIB_EXPORT __declspec(dllexport) -#else -# define DYNLIB_EXPORT -#endif - -/** - * \brief Usual suffix for the library. - * - * This macro expands to the suffix convention for this platform. - * - * \code{.cpp} - * Dynlib library("./myplugin" DYNLIB_SUFFIX); - * \endcode - * - * \note Don't use the suffix expanded value shown in Doxygen as it may be wrong. - */ -#if defined(_WIN32) -# define DYNLIB_SUFFIX ".dll" -#elif defined(__APPLE__) -# define DYNLIB_SUFFIX ".dylib" -#else -# define DYNLIB_SUFFIX ".so" -#endif - -namespace malikania { - -/** - * \class Dynlib - * \brief Load a dynamic module. - * - * This class is a portable wrapper to load shared libraries on supported systems. - */ -class Dynlib { -private: -#if defined(_WIN32) - using Handle = HMODULE; - using Sym = FARPROC; -#else - using Handle = void *; - using Sym = void *; -#endif - -public: - /** - * \brief Policy for symbol resolution. - */ - enum Policy { - Immediately, //!< load symbols immediately - Lazy //!< load symbols when needed - }; - -private: - Handle m_handle; - - Dynlib(const Dynlib &) = delete; - Dynlib &operator=(const Dynlib &) = delete; - - Dynlib(Dynlib &&) = delete; - Dynlib &operator=(Dynlib &&) = delete; - -#if defined(_WIN32) - std::string error() - { - LPSTR error = nullptr; - std::string errmsg; - - FormatMessageA( - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPSTR)&error, 0, NULL); - - if (error) { - errmsg = std::string(error); - LocalFree(error); - } - - return errmsg; - } -#endif - -public: - /** - * Constructor to load a shared module. - * - * \param path the absolute path - * \param policy the policy to load - * \throw std::runtime_error on error - */ - Dynlib(const std::string &path, Policy policy = Immediately); - - /** - * Close the library automatically. - */ - ~Dynlib(); - - /** - * Get a symbol from the library. - * - * On some platforms the symbol must be manually exported. - * - * \param name the symbol - * \return the symbol - * \throw std::runtime_error on error - * \see DYNLIB_EXPORT - */ - template <typename T> - T sym(const std::string &name); -}; - -#if defined(_WIN32) - -/* - * Windows implementation - * ------------------------------------------------------------------ - */ - -inline Dynlib::Dynlib(const std::string &path, Policy) -{ - m_handle = LoadLibraryA(path.c_str()); - - if (m_handle == nullptr) - throw std::runtime_error(error()); -} - -inline Dynlib::~Dynlib() -{ - FreeLibrary(m_handle); - m_handle = nullptr; -} - -template <typename T> -T Dynlib::sym(const std::string &name) -{ - Sym sym = GetProcAddress(m_handle, name.c_str()); - - if (sym == nullptr) - throw std::runtime_error(error()); - - return reinterpret_cast<T>(sym); -} - -#else - -/* - * Unix implementation - * ------------------------------------------------------------------ - */ - -inline Dynlib::Dynlib(const std::string &path, Policy policy) -{ - m_handle = dlopen(path.c_str(), policy == Immediately ? RTLD_NOW : RTLD_LAZY); - - if (m_handle == nullptr) - throw std::runtime_error(dlerror()); -} - -inline Dynlib::~Dynlib() -{ - dlclose(m_handle); - m_handle = nullptr; -} - -template <typename T> -T Dynlib::sym(const std::string &name) -{ - Sym sym = dlsym(m_handle, name.c_str()); - - if (sym == nullptr) - throw std::runtime_error(dlerror()); - - return reinterpret_cast<T>(sym); -} - -#endif - -} // !malikania - -#endif // !DYNLIB_HPP