| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569 | // Copyright 2014 Renato Tegon Forti, Antony Polukhin.// Copyright 2015-2019 Antony Polukhin.//// Distributed under the Boost Software License, Version 1.0.// (See accompanying file LICENSE_1_0.txt// or copy at http://www.boost.org/LICENSE_1_0.txt)#ifndef BOOST_DLL_SHARED_LIBRARY_HPP#define BOOST_DLL_SHARED_LIBRARY_HPP/// \file boost/dll/shared_library.hpp/// \brief Contains the boost::dll::shared_library class, core class for all the/// DLL/DSO operations.#include <boost/dll/config.hpp>#include <boost/predef/os.h>#include <boost/core/enable_if.hpp>#include <boost/core/explicit_operator_bool.hpp>#include <boost/type_traits/is_member_pointer.hpp>#include <boost/dll/detail/system_error.hpp>#include <boost/dll/detail/aggressive_ptr_cast.hpp>#if BOOST_OS_WINDOWS#   include <boost/dll/detail/windows/shared_library_impl.hpp>#else#   include <boost/dll/detail/posix/shared_library_impl.hpp>#endif#ifdef BOOST_HAS_PRAGMA_ONCE# pragma once#endifnamespace boost { namespace dll {/*!* \brief This class can be used to load a*        Dynamic link libraries (DLL's) or Shared Libraries, also know*        as dynamic shared objects (DSO's) and get their exported*        symbols (functions and variables).** shared_library instances share reference count to an actual loaded DLL/DSO, so it* is safe and memory efficient to have multiple instances of shared_library referencing the same DLL/DSO* even if those instances were loaded using different paths (relative + absolute) referencing the same object.** On Linux/POSIX link with library "dl". "-fvisibility=hidden" flag is also recommended for use on Linux/POSIX.*/class shared_library/// @cond    : private boost::dll::detail::shared_library_impl/// @endcond{    typedef boost::dll::detail::shared_library_impl base_t;    BOOST_COPYABLE_AND_MOVABLE(shared_library)public:#ifdef BOOST_DLL_DOXYGEN    typedef platform_specific native_handle_t;#else    typedef shared_library_impl::native_handle_t native_handle_t;#endif    /*!    * Creates in anstance that does not reference any DLL/DSO.    *    * \post this->is_loaded() returns false.    * \throw Nothing.    */    shared_library() BOOST_NOEXCEPT {}    /*!    * Copy constructor that increments the reference count of an underlying shared library.    * Same as calling constructor with `lib.location()` parameter.    *    * \param lib A library to copy.    * \post lib == *this    * \throw \forcedlinkfs{system_error}, std::bad_alloc in case of insufficient memory.    */    shared_library(const shared_library& lib)        : base_t()    {        assign(lib);    }    /*!    * Copy constructor that increments the reference count of an underlying shared library.    * Same as calling constructor with `lib.location(), ec` parameters.    *    * \param lib A shared library to copy.    * \param ec Variable that will be set to the result of the operation.    * \post lib == *this    * \throw std::bad_alloc in case of insufficient memory.    */    shared_library(const shared_library& lib, boost::dll::fs::error_code& ec)        : base_t()    {        assign(lib, ec);    }    /*!    * Move constructor. Does not invalidate existing symbols and functions loaded from lib.    *    * \param lib A shared library to move from.    * \post lib.is_loaded() returns false, this->is_loaded() return true.    * \throw Nothing.    */    shared_library(BOOST_RV_REF(shared_library) lib) BOOST_NOEXCEPT        : base_t(boost::move(static_cast<base_t&>(lib)))    {}    /*!    * Loads a library by specified path with a specified mode.    *    * \param lib_path Library file name. Can handle std::string, const char*, std::wstring,    *           const wchar_t* or \forcedlinkfs{path}.    * \param mode A mode that will be used on library load.    * \throw \forcedlinkfs{system_error}, std::bad_alloc in case of insufficient memory.    */    explicit shared_library(const boost::dll::fs::path& lib_path, load_mode::type mode = load_mode::default_mode) {        shared_library::load(lib_path, mode);    }    /*!    * Loads a library by specified path with a specified mode.    *    * \param lib_path Library file name. Can handle std::string, const char*, std::wstring,    *           const wchar_t* or \forcedlinkfs{path}.    * \param mode A mode that will be used on library load.    * \param ec Variable that will be set to the result of the operation.    * \throw std::bad_alloc in case of insufficient memory.    */    shared_library(const boost::dll::fs::path& lib_path, boost::dll::fs::error_code& ec, load_mode::type mode = load_mode::default_mode) {        shared_library::load(lib_path, mode, ec);    }    //! \overload shared_library(const boost::dll::fs::path& lib_path, boost::dll::fs::error_code& ec, load_mode::type mode = load_mode::default_mode)    shared_library(const boost::dll::fs::path& lib_path, load_mode::type mode, boost::dll::fs::error_code& ec) {        shared_library::load(lib_path, mode, ec);    }    /*!    * Assignment operator. If this->is_loaded() then calls this->unload(). Does not invalidate existing symbols and functions loaded from lib.    *    * \param lib A shared library to assign from.    * \post lib == *this    * \throw \forcedlinkfs{system_error}, std::bad_alloc in case of insufficient memory.    */    shared_library& operator=(BOOST_COPY_ASSIGN_REF(shared_library) lib) {        boost::dll::fs::error_code ec;        assign(lib, ec);        if (ec) {            boost::dll::detail::report_error(ec, "boost::dll::shared_library::operator= failed");        }        return *this;    }    /*!    * Move assignment operator. If this->is_loaded() then calls this->unload(). Does not invalidate existing symbols and functions loaded from lib.    *    * \param lib A library to move from.    * \post lib.is_loaded() returns false.    * \throw Nothing.    */    shared_library& operator=(BOOST_RV_REF(shared_library) lib) BOOST_NOEXCEPT {        if (lib.native() != native()) {            swap(lib);        }        return *this;    }    /*!    * Destroys the object by calling `unload()`. If library was loaded multiple times    * by different instances, the actual DLL/DSO won't be unloaded until    * there is at least one instance that references the DLL/DSO.    *    * \throw Nothing.    */    ~shared_library() BOOST_NOEXCEPT {}    /*!    * Makes *this share the same shared object as lib. If *this is loaded, then unloads it.    *    * \post lib.location() == this->location(), lib == *this    * \param lib A library to copy.    * \param ec Variable that will be set to the result of the operation.    * \throw std::bad_alloc in case of insufficient memory.    */    shared_library& assign(const shared_library& lib, boost::dll::fs::error_code& ec) {        ec.clear();        if (native() == lib.native()) {            return *this;        }        if (!lib) {            unload();            return *this;        }        boost::dll::fs::path loc = lib.location(ec);        if (ec) {            return *this;        }        shared_library copy(loc, ec);        if (ec) {            return *this;        }        swap(copy);        return *this;    }    /*!    * Makes *this share the same shared object as lib. If *this is loaded, then unloads it.    *    * \param lib A library instance to assign from.    * \post lib.location() == this->location()    * \throw \forcedlinkfs{system_error}, std::bad_alloc in case of insufficient memory.    */    shared_library& assign(const shared_library& lib) {        boost::dll::fs::error_code ec;        assign(lib, ec);        if (ec) {            boost::dll::detail::report_error(ec, "boost::dll::shared_library::assign() failed");        }        return *this;    }    /*!    * Loads a library by specified path with a specified mode.    *    * Note that if some library is already loaded in this instance, load will    * call unload() and then load the new provided library.    *    * \param lib_path Library file name. Can handle std::string, const char*, std::wstring,    *           const wchar_t* or \forcedlinkfs{path}.    * \param mode A mode that will be used on library load.    * \throw \forcedlinkfs{system_error}, std::bad_alloc in case of insufficient memory.    *    */    void load(const boost::dll::fs::path& lib_path, load_mode::type mode = load_mode::default_mode) {        boost::dll::fs::error_code ec;        base_t::load(lib_path, mode, ec);        if (ec) {            boost::dll::detail::report_error(ec, "boost::dll::shared_library::load() failed");        }    }    /*!    * Loads a library by specified path with a specified mode.    *    * Note that if some library is already loaded in this instance, load will    * call unload() and then load the new provided library.    *    * \param lib_path Library file name. Can handle std::string, const char*, std::wstring,    *           const wchar_t* or \forcedlinkfs{path}.    * \param ec Variable that will be set to the result of the operation.    * \param mode A mode that will be used on library load.    * \throw std::bad_alloc in case of insufficient memory.    */    void load(const boost::dll::fs::path& lib_path, boost::dll::fs::error_code& ec, load_mode::type mode = load_mode::default_mode) {        ec.clear();        base_t::load(lib_path, mode, ec);    }    //! \overload void load(const boost::dll::fs::path& lib_path, boost::dll::fs::error_code& ec, load_mode::type mode = load_mode::default_mode)    void load(const boost::dll::fs::path& lib_path, load_mode::type mode, boost::dll::fs::error_code& ec) {        ec.clear();        base_t::load(lib_path, mode, ec);    }    /*!    * Unloads a shared library.  If library was loaded multiple times    * by different instances, the actual DLL/DSO won't be unloaded until    * there is at least one instance that references the DLL/DSO.    *    * \post this->is_loaded() returns false.    * \throw Nothing.    */    void unload() BOOST_NOEXCEPT {        base_t::unload();    }    /*!    * Check if an library is loaded.    *    * \return true if a library has been loaded.    * \throw Nothing.    */    bool is_loaded() const BOOST_NOEXCEPT {        return base_t::is_loaded();    }    /*!    * Check if an library is not loaded.    *    * \return true if a library has not been loaded.    * \throw Nothing.    */    bool operator!() const BOOST_NOEXCEPT {        return !is_loaded();    }    /*!    * Check if an library is loaded.    *    * \return true if a library has been loaded.    * \throw Nothing.    */    BOOST_EXPLICIT_OPERATOR_BOOL()    /*!    * Search for a given symbol on loaded library. Works for all symbols, including alias names.    *    * \param symbol_name Null-terminated symbol name. Can handle std::string, char*, const char*.    * \return `true` if the loaded library contains a symbol with a given name.    * \throw Nothing.    */    bool has(const char* symbol_name) const BOOST_NOEXCEPT {        boost::dll::fs::error_code ec;        return is_loaded() && !!base_t::symbol_addr(symbol_name, ec) && !ec;    }    //! \overload bool has(const char* symbol_name) const    bool has(const std::string& symbol_name) const BOOST_NOEXCEPT {        return has(symbol_name.c_str());    }    /*!    * Returns reference to the symbol (function or variable) with the given name from the loaded library.    * This call will always succeed and throw nothing if call to `has(const char* )`    * member function with the same symbol name returned `true`.    *    * \b Example:    * \code    * int& i0 = lib.get<int>("integer_name");    * int& i1 = *lib.get<int*>("integer_alias_name");    * \endcode    *    * \tparam T Type of the symbol that we are going to import. Must be explicitly specified.    * \param symbol_name Null-terminated symbol name. Can handle std::string, char*, const char*.    * \return Reference to the symbol.    * \throw \forcedlinkfs{system_error} if symbol does not exist or if the DLL/DSO was not loaded.    */    template <typename T>    inline typename boost::enable_if_c<boost::is_member_pointer<T>::value || boost::is_reference<T>::value, T>::type  get(const std::string& symbol_name) const {        return get<T>(symbol_name.c_str());    }    //! \overload T& get(const std::string& symbol_name) const    template <typename T>    inline typename boost::disable_if_c<boost::is_member_pointer<T>::value || boost::is_reference<T>::value, T&>::type get(const std::string& symbol_name) const {        return get<T>(symbol_name.c_str());    }    //! \overload T& get(const std::string& symbol_name) const    template <typename T>    inline typename boost::enable_if_c<boost::is_member_pointer<T>::value || boost::is_reference<T>::value, T>::type get(const char* symbol_name) const {        return boost::dll::detail::aggressive_ptr_cast<T>(            get_void(symbol_name)        );    }    //! \overload T& get(const std::string& symbol_name) const    template <typename T>    inline typename boost::disable_if_c<boost::is_member_pointer<T>::value || boost::is_reference<T>::value, T&>::type get(const char* symbol_name) const {        return *boost::dll::detail::aggressive_ptr_cast<T*>(            get_void(symbol_name)        );    }    /*!    * Returns a symbol (function or variable) from a shared library by alias name of the symbol.    *    * \b Example:    * \code    * int& i = lib.get_alias<int>("integer_alias_name");    * \endcode    *    * \tparam T Type of the symbol that we are going to import. Must be explicitly specified..    * \param alias_name Null-terminated alias symbol name. Can handle std::string, char*, const char*.    * \throw \forcedlinkfs{system_error} if symbol does not exist or if the DLL/DSO was not loaded.    */    template <typename T>    inline T& get_alias(const char* alias_name) const {        return *get<T*>(alias_name);    }    //! \overload T& get_alias(const char* alias_name) const    template <typename T>    inline T& get_alias(const std::string& alias_name) const {        return *get<T*>(alias_name.c_str());    }private:    /// @cond    // get_void is required to reduce binary size: it does not depend on a template    // parameter and will be instantiated only once.    void* get_void(const char* sb) const {        boost::dll::fs::error_code ec;        if (!is_loaded()) {            ec = boost::dll::fs::make_error_code(                boost::dll::fs::errc::bad_file_descriptor            );            // report_error() calls dlsym, do not use it here!            boost::throw_exception(                boost::dll::fs::system_error(                    ec, "boost::dll::shared_library::get() failed: no library was loaded"                )            );        }        void* const ret = base_t::symbol_addr(sb, ec);        if (ec || !ret) {            boost::dll::detail::report_error(ec, "boost::dll::shared_library::get() failed");        }        return ret;    }    /// @endcondpublic:    /*!    * Returns the native handler of the loaded library.    *    * \return Platform-specific handle.    */    native_handle_t native() const BOOST_NOEXCEPT {        return base_t::native();    }   /*!    * Returns full path and name of this shared object.    *    * \b Example:    * \code    * shared_library lib("test_lib.dll");    * filesystem::path full_path = lib.location(); // C:\Windows\System32\test_lib.dll    * \endcode    *    * \return Full path to the shared library.    * \throw \forcedlinkfs{system_error}, std::bad_alloc.    */    boost::dll::fs::path location() const {        boost::dll::fs::error_code ec;        if (!is_loaded()) {            ec = boost::dll::fs::make_error_code(                boost::dll::fs::errc::bad_file_descriptor            );            boost::throw_exception(                boost::dll::fs::system_error(                    ec, "boost::dll::shared_library::location() failed (no library was loaded)"                )            );        }        boost::dll::fs::path full_path = base_t::full_module_path(ec);        if (ec) {            boost::dll::detail::report_error(ec, "boost::dll::shared_library::location() failed");        }        return full_path;    }   /*!    * Returns full path and name of shared module.    *    * \b Example:    * \code    * shared_library lib("test_lib.dll");    * filesystem::path full_path = lib.location(); // C:\Windows\System32\test_lib.dll    * \endcode    *    * \param ec Variable that will be set to the result of the operation.    * \return Full path to the shared library.    * \throw std::bad_alloc.    */    boost::dll::fs::path location(boost::dll::fs::error_code& ec) const {        if (!is_loaded()) {            ec = boost::dll::fs::make_error_code(                boost::dll::fs::errc::bad_file_descriptor            );            return boost::dll::fs::path();        }        ec.clear();        return base_t::full_module_path(ec);    }    /*!    * Returns suffix of shared module:    * in a call to load() or the constructor/load.    *    * \return The suffix od shared module: ".dll" (Windows), ".so" (Unix/Linux/BSD), ".dylib" (MacOS/IOS)    */    static boost::dll::fs::path suffix() {        return base_t::suffix();    }    /*!    * Returns the decorated path to a shared module name, i.e. with needed prefix/suffix added.    *    * \b Recommendations: Use `load` with `load_mode::append_decorations` instead of constructing the decorated path via `decorate()` and loading by it.    *    * For instance, for a path like "path/to/boost" it returns :    * - path/to/libboost.so on posix platforms    * - path/to/libboost.dylib on OSX    * - path/to/boost.dll on Windows    *    * Method handles both relative and absolute paths.    *    * - Windows note: `decorate()` does not prepend "lib" to the decorated path. Use `load` with `load_mode::append_decorations` for MinGW compatibility purpose.    * - Posix note: if the initial module name is already prepended with lib, only the suffix() is appended to the path    *    * \param sl the module name and path to decorate - for instance : /usr/lib/boost    *    * \return The decorated unportable path that may not exists in the filesystem or could be wrong due to platform specifics.    */    static boost::dll::fs::path decorate(const boost::dll::fs::path& sl) {        return base_t::decorate(sl);    }    /*!    * Swaps two libraries. Does not invalidate existing symbols and functions loaded from libraries.    *    * \param rhs Library to swap with.    * \throw Nothing.    */    void swap(shared_library& rhs) BOOST_NOEXCEPT {        base_t::swap(rhs);    }};/// Very fast equality check that compares the actual DLL/DSO objects. Throws nothing.inline bool operator==(const shared_library& lhs, const shared_library& rhs) BOOST_NOEXCEPT {    return lhs.native() == rhs.native();}/// Very fast inequality check that compares the actual DLL/DSO objects. Throws nothing.inline bool operator!=(const shared_library& lhs, const shared_library& rhs) BOOST_NOEXCEPT {    return lhs.native() != rhs.native();}/// Compare the actual DLL/DSO objects without any guarantee to be stable between runs. Throws nothing.inline bool operator<(const shared_library& lhs, const shared_library& rhs) BOOST_NOEXCEPT {    return lhs.native() < rhs.native();}/// Swaps two shared libraries. Does not invalidate symbols and functions loaded from libraries. Throws nothing.inline void swap(shared_library& lhs, shared_library& rhs) BOOST_NOEXCEPT {    lhs.swap(rhs);}}} // boost::dll#endif // BOOST_DLL_SHARED_LIBRARY_HPP
 |