summaryrefslogtreecommitdiff
path: root/boost/dll/shared_library.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/dll/shared_library.hpp')
-rw-r--r--boost/dll/shared_library.hpp550
1 files changed, 550 insertions, 0 deletions
diff --git a/boost/dll/shared_library.hpp b/boost/dll/shared_library.hpp
new file mode 100644
index 0000000000..86aed9433e
--- /dev/null
+++ b/boost/dll/shared_library.hpp
@@ -0,0 +1,550 @@
+// Copyright 2014 Renato Tegon Forti, Antony Polukhin.
+// Copyright 2015-2016 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/config.hpp>
+#include <boost/predef/os.h>
+#include <boost/utility/enable_if.hpp>
+#include <boost/type_traits/is_member_pointer.hpp>
+#include <boost/utility/explicit_operator_bool.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
+#endif
+
+namespace 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 boost::system::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::system::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 boost::filesystem::path.
+ * \param mode A mode that will be used on library load.
+ * \throw boost::system::system_error, std::bad_alloc in case of insufficient memory.
+ */
+ explicit shared_library(const boost::filesystem::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 boost::filesystem::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::filesystem::path& lib_path, boost::system::error_code& ec, load_mode::type mode = load_mode::default_mode) {
+ shared_library::load(lib_path, mode, ec);
+ }
+
+ //! \overload shared_library(const boost::filesystem::path& lib_path, boost::system::error_code& ec, load_mode::type mode = load_mode::default_mode)
+ shared_library(const boost::filesystem::path& lib_path, load_mode::type mode, boost::system::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 boost::system::system_error, std::bad_alloc in case of insufficient memory.
+ */
+ shared_library& operator=(BOOST_COPY_ASSIGN_REF(shared_library) lib) {
+ boost::system::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::system::error_code& ec) {
+ ec.clear();
+
+ if (native() == lib.native()) {
+ return *this;
+ }
+
+ if (!lib) {
+ unload();
+ return *this;
+ }
+
+ boost::filesystem::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 boost::system::system_error, std::bad_alloc in case of insufficient memory.
+ */
+ shared_library& assign(const shared_library& lib) {
+ boost::system::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 boost::filesystem::path.
+ * \param mode A mode that will be used on library load.
+ * \throw boost::system::system_error, std::bad_alloc in case of insufficient memory.
+ *
+ */
+ void load(const boost::filesystem::path& lib_path, load_mode::type mode = load_mode::default_mode) {
+ boost::system::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 boost::filesystem::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::filesystem::path& lib_path, boost::system::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::filesystem::path& lib_path, boost::system::error_code& ec, load_mode::type mode = load_mode::default_mode)
+ void load(const boost::filesystem::path& lib_path, load_mode::type mode, boost::system::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::system::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 boost::system::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 boost::system::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::system::error_code ec;
+
+ if (!is_loaded()) {
+ ec = boost::system::error_code(
+ boost::system::errc::bad_file_descriptor,
+ boost::system::generic_category()
+ );
+
+ // report_error() calls dlsym, do not use it here!
+ boost::throw_exception(
+ boost::system::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;
+ }
+ /// @endcond
+
+public:
+
+ /*!
+ * 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 boost::system::system_error, std::bad_alloc.
+ */
+ boost::filesystem::path location() const {
+ boost::system::error_code ec;
+ if (!is_loaded()) {
+ ec = boost::system::error_code(
+ boost::system::errc::bad_file_descriptor,
+ boost::system::generic_category()
+ );
+
+ boost::throw_exception(
+ boost::system::system_error(
+ ec, "boost::dll::shared_library::location() failed (no library was loaded)"
+ )
+ );
+ }
+
+ boost::filesystem::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::filesystem::path location(boost::system::error_code& ec) const {
+ if (!is_loaded()) {
+ ec = boost::system::error_code(
+ boost::system::errc::bad_file_descriptor,
+ boost::system::generic_category()
+ );
+
+ return boost::filesystem::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::filesystem::path suffix() {
+ return base_t::suffix();
+ }
+
+ /*!
+ * 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
+