Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:30:45

0001 // Copyright 2014 Renato Tegon Forti, Antony Polukhin.
0002 // Copyright Antony Polukhin, 2015-2023.
0003 //
0004 // Distributed under the Boost Software License, Version 1.0.
0005 // (See accompanying file LICENSE_1_0.txt
0006 // or copy at http://www.boost.org/LICENSE_1_0.txt)
0007 
0008 #ifndef BOOST_DLL_SHARED_LIBRARY_HPP
0009 #define BOOST_DLL_SHARED_LIBRARY_HPP
0010 
0011 /// \file boost/dll/shared_library.hpp
0012 /// \brief Contains the boost::dll::shared_library class, core class for all the
0013 /// DLL/DSO operations.
0014 
0015 #include <boost/dll/config.hpp>
0016 #include <boost/predef/os.h>
0017 #include <boost/core/enable_if.hpp>
0018 #include <boost/core/explicit_operator_bool.hpp>
0019 #include <boost/type_traits/is_member_pointer.hpp>
0020 #include <boost/dll/detail/system_error.hpp>
0021 #include <boost/dll/detail/aggressive_ptr_cast.hpp>
0022 
0023 #if BOOST_OS_WINDOWS
0024 #   include <boost/dll/detail/windows/shared_library_impl.hpp>
0025 #else
0026 #   include <boost/dll/detail/posix/shared_library_impl.hpp>
0027 #endif
0028 
0029 #ifdef BOOST_HAS_PRAGMA_ONCE
0030 # pragma once
0031 #endif
0032 
0033 namespace boost { namespace dll {
0034 
0035 /*!
0036 * \brief This class can be used to load a
0037 *        Dynamic link libraries (DLL's) or Shared Libraries, also know
0038 *        as dynamic shared objects (DSO's) and get their exported
0039 *        symbols (functions and variables).
0040 *
0041 * shared_library instances share reference count to an actual loaded DLL/DSO, so it
0042 * is safe and memory efficient to have multiple instances of shared_library referencing the same DLL/DSO
0043 * even if those instances were loaded using different paths (relative + absolute) referencing the same object.
0044 *
0045 * On Linux/POSIX link with library "dl". "-fvisibility=hidden" flag is also recommended for use on Linux/POSIX.
0046 */
0047 class shared_library
0048 /// @cond
0049     : private boost::dll::detail::shared_library_impl
0050 /// @endcond
0051 {
0052     typedef boost::dll::detail::shared_library_impl base_t;
0053     BOOST_COPYABLE_AND_MOVABLE(shared_library)
0054 
0055 public:
0056 #ifdef BOOST_DLL_DOXYGEN
0057     typedef platform_specific native_handle_t;
0058 #else
0059     typedef shared_library_impl::native_handle_t native_handle_t;
0060 #endif
0061 
0062     /*!
0063     * Creates in anstance that does not reference any DLL/DSO.
0064     *
0065     * \post this->is_loaded() returns false.
0066     * \throw Nothing.
0067     */
0068     shared_library() BOOST_NOEXCEPT {}
0069 
0070     /*!
0071     * Copy constructor that increments the reference count of an underlying shared library.
0072     * Same as calling constructor with `lib.location()` parameter.
0073     *
0074     * \param lib A library to copy.
0075     * \post lib == *this
0076     * \throw \forcedlinkfs{system_error}, std::bad_alloc in case of insufficient memory.
0077     */
0078     shared_library(const shared_library& lib)
0079         : base_t()
0080     {
0081         assign(lib);
0082     }
0083 
0084     /*!
0085     * Copy constructor that increments the reference count of an underlying shared library.
0086     * Same as calling constructor with `lib.location(), ec` parameters.
0087     *
0088     * \param lib A shared library to copy.
0089     * \param ec Variable that will be set to the result of the operation.
0090     * \post lib == *this
0091     * \throw std::bad_alloc in case of insufficient memory.
0092     */
0093     shared_library(const shared_library& lib, boost::dll::fs::error_code& ec)
0094         : base_t()
0095     {
0096         assign(lib, ec);
0097     }
0098 
0099     /*!
0100     * Move constructor. Does not invalidate existing symbols and functions loaded from lib.
0101     *
0102     * \param lib A shared library to move from.
0103     * \post lib.is_loaded() returns false, this->is_loaded() return true.
0104     * \throw Nothing.
0105     */
0106     shared_library(BOOST_RV_REF(shared_library) lib) BOOST_NOEXCEPT
0107         : base_t(boost::move(static_cast<base_t&>(lib)))
0108     {}
0109 
0110     /*!
0111     * Loads a library by specified path with a specified mode.
0112     *
0113     * \param lib_path Library file name. Can handle std::string, const char*, std::wstring,
0114     *           const wchar_t* or \forcedlinkfs{path}.
0115     * \param mode A mode that will be used on library load.
0116     * \throw \forcedlinkfs{system_error}, std::bad_alloc in case of insufficient memory.
0117     */
0118     explicit shared_library(const boost::dll::fs::path& lib_path, load_mode::type mode = load_mode::default_mode) {
0119         shared_library::load(lib_path, mode);
0120     }
0121 
0122     /*!
0123     * Loads a library by specified path with a specified mode.
0124     *
0125     * \param lib_path Library file name. Can handle std::string, const char*, std::wstring,
0126     *           const wchar_t* or \forcedlinkfs{path}.
0127     * \param mode A mode that will be used on library load.
0128     * \param ec Variable that will be set to the result of the operation.
0129     * \throw std::bad_alloc in case of insufficient memory.
0130     */
0131     shared_library(const boost::dll::fs::path& lib_path, boost::dll::fs::error_code& ec, load_mode::type mode = load_mode::default_mode) {
0132         shared_library::load(lib_path, mode, ec);
0133     }
0134 
0135     //! \overload shared_library(const boost::dll::fs::path& lib_path, boost::dll::fs::error_code& ec, load_mode::type mode = load_mode::default_mode)
0136     shared_library(const boost::dll::fs::path& lib_path, load_mode::type mode, boost::dll::fs::error_code& ec) {
0137         shared_library::load(lib_path, mode, ec);
0138     }
0139 
0140     /*!
0141     * Assignment operator. If this->is_loaded() then calls this->unload(). Does not invalidate existing symbols and functions loaded from lib.
0142     *
0143     * \param lib A shared library to assign from.
0144     * \post lib == *this
0145     * \throw \forcedlinkfs{system_error}, std::bad_alloc in case of insufficient memory.
0146     */
0147     shared_library& operator=(BOOST_COPY_ASSIGN_REF(shared_library) lib) {
0148         boost::dll::fs::error_code ec;
0149         assign(lib, ec);
0150         if (ec) {
0151             boost::dll::detail::report_error(ec, "boost::dll::shared_library::operator= failed");
0152         }
0153 
0154         return *this;
0155     }
0156 
0157     /*!
0158     * Move assignment operator. If this->is_loaded() then calls this->unload(). Does not invalidate existing symbols and functions loaded from lib.
0159     *
0160     * \param lib A library to move from.
0161     * \post lib.is_loaded() returns false.
0162     * \throw Nothing.
0163     */
0164     shared_library& operator=(BOOST_RV_REF(shared_library) lib) BOOST_NOEXCEPT {
0165         if (lib.native() != native()) {
0166             swap(lib);
0167         }
0168 
0169         return *this;
0170     }
0171 
0172     /*!
0173     * Destroys the object by calling `unload()`. If library was loaded multiple times
0174     * by different instances, the actual DLL/DSO won't be unloaded until
0175     * there is at least one instance that references the DLL/DSO.
0176     *
0177     * \throw Nothing.
0178     */
0179     ~shared_library() BOOST_NOEXCEPT {}
0180 
0181     /*!
0182     * Makes *this share the same shared object as lib. If *this is loaded, then unloads it.
0183     *
0184     * \post lib.location() == this->location(), lib == *this
0185     * \param lib A library to copy.
0186     * \param ec Variable that will be set to the result of the operation.
0187     * \throw std::bad_alloc in case of insufficient memory.
0188     */
0189     shared_library& assign(const shared_library& lib, boost::dll::fs::error_code& ec) {
0190         ec.clear();
0191 
0192         if (native() == lib.native()) {
0193             return *this;
0194         }
0195 
0196         if (!lib) {
0197             unload();
0198             return *this;
0199         }
0200 
0201         boost::dll::fs::path loc = lib.location(ec);
0202         if (ec) {
0203             return *this;
0204         }
0205 
0206         shared_library copy(loc, ec);
0207         if (ec) {
0208             return *this;
0209         }
0210 
0211         swap(copy);
0212         return *this;
0213     }
0214 
0215     /*!
0216     * Makes *this share the same shared object as lib. If *this is loaded, then unloads it.
0217     *
0218     * \param lib A library instance to assign from.
0219     * \post lib.location() == this->location()
0220     * \throw \forcedlinkfs{system_error}, std::bad_alloc in case of insufficient memory.
0221     */
0222     shared_library& assign(const shared_library& lib) {
0223         boost::dll::fs::error_code ec;
0224         assign(lib, ec);
0225         if (ec) {
0226             boost::dll::detail::report_error(ec, "boost::dll::shared_library::assign() failed");
0227         }
0228 
0229         return *this;
0230     }
0231 
0232     /*!
0233     * Loads a library by specified path with a specified mode.
0234     *
0235     * Note that if some library is already loaded in this instance, load will
0236     * call unload() and then load the new provided library.
0237     *
0238     * \param lib_path Library file name. Can handle std::string, const char*, std::wstring,
0239     *           const wchar_t* or \forcedlinkfs{path}.
0240     * \param mode A mode that will be used on library load.
0241     * \throw \forcedlinkfs{system_error}, std::bad_alloc in case of insufficient memory.
0242     *
0243     */
0244     void load(const boost::dll::fs::path& lib_path, load_mode::type mode = load_mode::default_mode) {
0245         boost::dll::fs::error_code ec;
0246 
0247         base_t::load(lib_path, mode, ec);
0248 
0249         if (ec) {
0250             boost::dll::detail::report_error(ec, "boost::dll::shared_library::load() failed");
0251         }
0252     }
0253 
0254     /*!
0255     * Loads a library by specified path with a specified mode.
0256     *
0257     * Note that if some library is already loaded in this instance, load will
0258     * call unload() and then load the new provided library.
0259     *
0260     * \param lib_path Library file name. Can handle std::string, const char*, std::wstring,
0261     *           const wchar_t* or \forcedlinkfs{path}.
0262     * \param ec Variable that will be set to the result of the operation.
0263     * \param mode A mode that will be used on library load.
0264     * \throw std::bad_alloc in case of insufficient memory.
0265     */
0266     void load(const boost::dll::fs::path& lib_path, boost::dll::fs::error_code& ec, load_mode::type mode = load_mode::default_mode) {
0267         ec.clear();
0268         base_t::load(lib_path, mode, ec);
0269     }
0270 
0271     //! \overload void load(const boost::dll::fs::path& lib_path, boost::dll::fs::error_code& ec, load_mode::type mode = load_mode::default_mode)
0272     void load(const boost::dll::fs::path& lib_path, load_mode::type mode, boost::dll::fs::error_code& ec) {
0273         ec.clear();
0274         base_t::load(lib_path, mode, ec);
0275     }
0276 
0277     /*!
0278     * Unloads a shared library.  If library was loaded multiple times
0279     * by different instances, the actual DLL/DSO won't be unloaded until
0280     * there is at least one instance that references the DLL/DSO.
0281     *
0282     * \post this->is_loaded() returns false.
0283     * \throw Nothing.
0284     */
0285     void unload() BOOST_NOEXCEPT {
0286         base_t::unload();
0287     }
0288 
0289     /*!
0290     * Check if an library is loaded.
0291     *
0292     * \return true if a library has been loaded.
0293     * \throw Nothing.
0294     */
0295     bool is_loaded() const BOOST_NOEXCEPT {
0296         return base_t::is_loaded();
0297     }
0298 
0299     /*!
0300     * Check if an library is not loaded.
0301     *
0302     * \return true if a library has not been loaded.
0303     * \throw Nothing.
0304     */
0305     bool operator!() const BOOST_NOEXCEPT {
0306         return !is_loaded();
0307     }
0308 
0309     /*!
0310     * Check if an library is loaded.
0311     *
0312     * \return true if a library has been loaded.
0313     * \throw Nothing.
0314     */
0315     BOOST_EXPLICIT_OPERATOR_BOOL()
0316 
0317     /*!
0318     * Search for a given symbol on loaded library. Works for all symbols, including alias names.
0319     *
0320     * \param symbol_name Null-terminated symbol name. Can handle std::string, char*, const char*.
0321     * \return `true` if the loaded library contains a symbol with a given name.
0322     * \throw Nothing.
0323     */
0324     bool has(const char* symbol_name) const BOOST_NOEXCEPT {
0325         boost::dll::fs::error_code ec;
0326         return is_loaded() && !!base_t::symbol_addr(symbol_name, ec) && !ec;
0327     }
0328 
0329     //! \overload bool has(const char* symbol_name) const
0330     bool has(const std::string& symbol_name) const BOOST_NOEXCEPT {
0331         return has(symbol_name.c_str());
0332     }
0333 
0334     /*!
0335     * Returns reference to the symbol (function or variable) with the given name from the loaded library.
0336     * This call will always succeed and throw nothing if call to `has(const char* )`
0337     * member function with the same symbol name returned `true`.
0338     *
0339     * \b Example:
0340     * \code
0341     * int& i0 = lib.get<int>("integer_name");
0342     * int& i1 = *lib.get<int*>("integer_alias_name");
0343     * \endcode
0344     *
0345     * \tparam T Type of the symbol that we are going to import. Must be explicitly specified.
0346     * \param symbol_name Null-terminated symbol name. Can handle std::string, char*, const char*.
0347     * \return Reference to the symbol.
0348     * \throw \forcedlinkfs{system_error} if symbol does not exist or if the DLL/DSO was not loaded.
0349     */
0350     template <typename T>
0351     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 {
0352         return get<T>(symbol_name.c_str());
0353     }
0354 
0355     //! \overload T& get(const std::string& symbol_name) const
0356     template <typename T>
0357     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 {
0358         return get<T>(symbol_name.c_str());
0359     }
0360 
0361     //! \overload T& get(const std::string& symbol_name) const
0362     template <typename T>
0363     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 {
0364         return boost::dll::detail::aggressive_ptr_cast<T>(
0365             get_void(symbol_name)
0366         );
0367     }
0368 
0369     //! \overload T& get(const std::string& symbol_name) const
0370     template <typename T>
0371     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 {
0372         return *boost::dll::detail::aggressive_ptr_cast<T*>(
0373             get_void(symbol_name)
0374         );
0375     }
0376 
0377     /*!
0378     * Returns a symbol (function or variable) from a shared library by alias name of the symbol.
0379     *
0380     * \b Example:
0381     * \code
0382     * int& i = lib.get_alias<int>("integer_alias_name");
0383     * \endcode
0384     *
0385     * \tparam T Type of the symbol that we are going to import. Must be explicitly specified..
0386     * \param alias_name Null-terminated alias symbol name. Can handle std::string, char*, const char*.
0387     * \throw \forcedlinkfs{system_error} if symbol does not exist or if the DLL/DSO was not loaded.
0388     */
0389     template <typename T>
0390     inline T& get_alias(const char* alias_name) const {
0391         return *get<T*>(alias_name);
0392     }
0393 
0394     //! \overload T& get_alias(const char* alias_name) const
0395     template <typename T>
0396     inline T& get_alias(const std::string& alias_name) const {
0397         return *get<T*>(alias_name.c_str());
0398     }
0399 
0400 private:
0401     /// @cond
0402     // get_void is required to reduce binary size: it does not depend on a template
0403     // parameter and will be instantiated only once.
0404     void* get_void(const char* sb) const {
0405         boost::dll::fs::error_code ec;
0406 
0407         if (!is_loaded()) {
0408             ec = boost::dll::fs::make_error_code(
0409                 boost::dll::fs::errc::bad_file_descriptor
0410             );
0411 
0412             // report_error() calls dlsym, do not use it here!
0413             boost::throw_exception(
0414                 boost::dll::fs::system_error(
0415                     ec, "boost::dll::shared_library::get() failed: no library was loaded"
0416                 )
0417             );
0418         }
0419 
0420         void* const ret = base_t::symbol_addr(sb, ec);
0421         if (ec || !ret) {
0422             boost::dll::detail::report_error(ec, "boost::dll::shared_library::get() failed");
0423         }
0424 
0425         return ret;
0426     }
0427     /// @endcond
0428 
0429 public:
0430 
0431     /*!
0432     * Returns the native handler of the loaded library.
0433     *
0434     * \return Platform-specific handle.
0435     */
0436     native_handle_t native() const BOOST_NOEXCEPT {
0437         return base_t::native();
0438     }
0439 
0440    /*!
0441     * Returns full path and name of this shared object.
0442     *
0443     * \b Example:
0444     * \code
0445     * shared_library lib("test_lib.dll");
0446     * filesystem::path full_path = lib.location(); // C:\Windows\System32\test_lib.dll
0447     * \endcode
0448     *
0449     * \return Full path to the shared library.
0450     * \throw \forcedlinkfs{system_error}, std::bad_alloc.
0451     */
0452     boost::dll::fs::path location() const {
0453         boost::dll::fs::error_code ec;
0454         if (!is_loaded()) {
0455             ec = boost::dll::fs::make_error_code(
0456                 boost::dll::fs::errc::bad_file_descriptor
0457             );
0458 
0459             boost::throw_exception(
0460                 boost::dll::fs::system_error(
0461                     ec, "boost::dll::shared_library::location() failed (no library was loaded)"
0462                 )
0463             );
0464         }
0465 
0466         boost::dll::fs::path full_path = base_t::full_module_path(ec);
0467 
0468         if (ec) {
0469             boost::dll::detail::report_error(ec, "boost::dll::shared_library::location() failed");
0470         }
0471 
0472         return full_path;
0473     }
0474 
0475    /*!
0476     * Returns full path and name of shared module.
0477     *
0478     * \b Example:
0479     * \code
0480     * shared_library lib("test_lib.dll");
0481     * filesystem::path full_path = lib.location(); // C:\Windows\System32\test_lib.dll
0482     * \endcode
0483     *
0484     * \param ec Variable that will be set to the result of the operation.
0485     * \return Full path to the shared library.
0486     * \throw std::bad_alloc.
0487     */
0488     boost::dll::fs::path location(boost::dll::fs::error_code& ec) const {
0489         if (!is_loaded()) {
0490             ec = boost::dll::fs::make_error_code(
0491                 boost::dll::fs::errc::bad_file_descriptor
0492             );
0493 
0494             return boost::dll::fs::path();
0495         }
0496 
0497         ec.clear();
0498         return base_t::full_module_path(ec);
0499     }
0500 
0501     /*!
0502     * Returns suffix of shared module:
0503     * in a call to load() or the constructor/load.
0504     *
0505     * \return The suffix od shared module: ".dll" (Windows), ".so" (Unix/Linux/BSD), ".dylib" (MacOS/IOS)
0506     */
0507     static boost::dll::fs::path suffix() {
0508         return base_t::suffix();
0509     }
0510 
0511     /*!
0512     * Returns the decorated path to a shared module name, i.e. with needed prefix/suffix added.
0513     *
0514     * \b Recommendations: Use `load` with `load_mode::append_decorations` instead of constructing the decorated path via `decorate()` and loading by it.
0515     *
0516     * For instance, for a path like "path/to/boost" it returns :
0517     * - path/to/libboost.so on posix platforms
0518     * - path/to/libboost.dylib on OSX
0519     * - path/to/boost.dll on Windows
0520     *
0521     * Method handles both relative and absolute paths.
0522     *
0523     * - Windows note: `decorate()` does not prepend "lib" to the decorated path. Use `load` with `load_mode::append_decorations` for MinGW compatibility purpose.
0524     * - Posix note: if the initial module name is already prepended with lib, only the suffix() is appended to the path
0525     *
0526     * \param sl the module name and path to decorate - for instance : /usr/lib/boost
0527     *
0528     * \return The decorated unportable path that may not exists in the filesystem or could be wrong due to platform specifics.
0529     */
0530     static boost::dll::fs::path decorate(const boost::dll::fs::path& sl) {
0531         return base_t::decorate(sl);
0532     }
0533 
0534     /*!
0535     * Swaps two libraries. Does not invalidate existing symbols and functions loaded from libraries.
0536     *
0537     * \param rhs Library to swap with.
0538     * \throw Nothing.
0539     */
0540     void swap(shared_library& rhs) BOOST_NOEXCEPT {
0541         base_t::swap(rhs);
0542     }
0543 };
0544 
0545 
0546 
0547 /// Very fast equality check that compares the actual DLL/DSO objects. Throws nothing.
0548 inline bool operator==(const shared_library& lhs, const shared_library& rhs) BOOST_NOEXCEPT {
0549     return lhs.native() == rhs.native();
0550 }
0551 
0552 /// Very fast inequality check that compares the actual DLL/DSO objects. Throws nothing.
0553 inline bool operator!=(const shared_library& lhs, const shared_library& rhs) BOOST_NOEXCEPT {
0554     return lhs.native() != rhs.native();
0555 }
0556 
0557 /// Compare the actual DLL/DSO objects without any guarantee to be stable between runs. Throws nothing.
0558 inline bool operator<(const shared_library& lhs, const shared_library& rhs) BOOST_NOEXCEPT {
0559     return lhs.native() < rhs.native();
0560 }
0561 
0562 /// Swaps two shared libraries. Does not invalidate symbols and functions loaded from libraries. Throws nothing.
0563 inline void swap(shared_library& lhs, shared_library& rhs) BOOST_NOEXCEPT {
0564     lhs.swap(rhs);
0565 }
0566 
0567 }} // boost::dll
0568 
0569 #endif // BOOST_DLL_SHARED_LIBRARY_HPP