|
||||
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
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |