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