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> &params)
     : 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