changeset 592:2bd11ea63822

Dynlib: move to bitbucket
author David Demelier <markand@malikania.fr>
date Wed, 31 Aug 2016 18:48:03 +0200
parents 3547fc5afba2
children c767f1202e8e
files CMakeLists.txt modules/dynlib/CMakeLists.txt modules/dynlib/doc/mainpage.cpp modules/dynlib/dynlib.hpp modules/dynlib/test/main.cpp modules/dynlib/test/plugin.cpp
diffstat 6 files changed, 0 insertions(+), 509 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Wed Aug 31 18:35:39 2016 +0200
+++ b/CMakeLists.txt	Wed Aug 31 18:48:03 2016 +0200
@@ -49,7 +49,6 @@
     )
 endif ()
 
-add_subdirectory(modules/dynlib)
 add_subdirectory(modules/elapsed-timer)
 add_subdirectory(modules/fs)
 add_subdirectory(modules/hash)
--- a/modules/dynlib/CMakeLists.txt	Wed Aug 31 18:35:39 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-#
-# CMakeLists.txt -- code building for common code
-#
-# 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.
-#
-
-add_library(dynlib-plugin MODULE ${CMAKE_CURRENT_SOURCE_DIR}/test/plugin.cpp)
-target_include_directories(dynlib-plugin PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
-
-code_define_module(
-    NAME dynlib
-    SOURCES dynlib.hpp
-    LIBRARIES $<$<STREQUAL:${CMAKE_SYSTEM_NAME},Linux>:dl>
-    FLAGS PLUGIN=\"$<TARGET_FILE:dynlib-plugin>\"
-)
-
-add_dependencies(test-dynlib dynlib-plugin)
--- a/modules/dynlib/doc/mainpage.cpp	Wed Aug 31 18:35:39 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/**
- * \mainpage
- *
- * Welcome to the dynlib library.
- *
- * ## Introduction
- * 
- * Opening shared libraries from C++ (e.g for plugins) is platform specific, with that class, you can open them very
- * easily.
- *
- * ## Installation
- *
- * Just copy the file dynlib.hpp and add it to your project.
- *
- * ## Overview
- *
- * This one minute tutorial shows how to load a shared library named `plugin.so` and execute a C function `say_hello`.
- *
- * ### Main
- *
- * This is the main executable that loads the `plugin.so` file.
- * 
- * ````cpp
- * #include <iostream>
- * 
- * #include "dynlib.hpp"
- * 
- * using HelloFunc = void (*)(const std::string &);
- * 
- * int main()
- * {
- *  try {
- *      Dynlib library("./plugin.so");
- *
- *      HelloFunc hello = library.sym<HelloFunc>("say_hello");
- *      hello("Test");
- *  } catch (const std::exception &error) {
- *      std::cerr << error.what() << std::endl;
- *  }
- *
- *  return 0;
- * }
- * ````
- *
- * ### Plugin
- *
- * This is the plugin that you compile as a shared library.
- *
- * For example with gcc: `gcc -fPIC -shared plugin.cpp -o plugin.so`.
- *
- * ````cpp
- * #include <iostream>
- *
- * #include "dynlib.hpp"
- *
- * extern "C" {
- *
- * DYNLIB_EXPORT void say_hello()
- * {
- *  std::cout << "Hello from the plugin!" << std::endl;
- * }
- * ````
- */
--- a/modules/dynlib/dynlib.hpp	Wed Aug 31 18:35:39 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,346 +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
- * symbols 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.require<PluginLoad>("plugin_load")();
- *      dso.require<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
-
-/**
- * \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.
-     *
-     * \param name the symbol
-     * \return the symbol
-     * \throw std::out_of_range on error
-     * \see DYNLIB_EXPORT
-     */
-    template <typename T>
-    inline T require(const std::string &name)
-    {
-        auto sym = get<T>(name);
-
-        if (!sym)
-            throw std::out_of_range(name + ": symbol not found");
-
-        return sym;
-    }
-
-    /**
-     * Get a symbol from the library or return nullptr if not found.
-     *
-     * \param name the symbol
-     * \return the symbol
-     */
-    template <typename T>
-    T get(const std::string &name) noexcept;
-};
-
-#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>
-inline T Dynlib::get(const std::string &name) noexcept
-{
-    return reinterpret_cast<T>(GetProcAddress(m_handle, name.c_str()));
-}
-
-#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>
-inline T Dynlib::get(const std::string &name) noexcept
-{
-    return reinterpret_cast<T>(dlsym(m_handle, name.c_str()));
-}
-
-#endif
-
-#endif // !DYNLIB_HPP
--- a/modules/dynlib/test/main.cpp	Wed Aug 31 18:35:39 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/*
- * main.cpp -- test the dynamic 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.
- */
-
-#include <iostream>
-
-#include <gtest/gtest.h>
-
-#include <dynlib.hpp>
-
-using Initialize = void (*)(std::string &s);
-
-TEST(Basic, initialize)
-{
-    try {
-        Dynlib library(PLUGIN);
-        Initialize init = library.require<Initialize>("initialize");
-
-        std::string expected("Hello World");
-        std::string result;
-
-        init(result);
-
-        ASSERT_EQ(expected, result);
-        ASSERT_TRUE(library.get<Initialize>("initialize"));
-    } catch (const std::runtime_error &error) {
-        FAIL() << error.what();
-    }
-}
-
-TEST(Basic, absent)
-{
-    Dynlib library(PLUGIN);
-
-    ASSERT_THROW(library.require<Initialize>("initialize_typo"), std::out_of_range);
-    ASSERT_FALSE(library.get<Initialize>("initialize_type"));
-}
-
-int main(int argc, char **argv)
-{
-    testing::InitGoogleTest(&argc, argv);
-
-    return RUN_ALL_TESTS();
-}
--- a/modules/dynlib/test/plugin.cpp	Wed Aug 31 18:35:39 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-#include <string>
-
-#include <dynlib.hpp>
-
-extern "C" {
-
-void DYNLIB_EXPORT initialize(std::string &result)
-{
-    result = "Hello World";
-}
-
-}