1 // Copyright 2014 Renato Tegon Forti, Antony Polukhin.
2 // Copyright 2015-2016 Antony Polukhin.
4 // Distributed under the Boost Software License, Version 1.0.
5 // (See accompanying file LICENSE_1_0.txt
6 // or copy at http://www.boost.org/LICENSE_1_0.txt)
8 #ifndef BOOST_DLL_SHARED_LIBRARY_HPP
9 #define BOOST_DLL_SHARED_LIBRARY_HPP
11 /// \file boost/dll/shared_library.hpp
12 /// \brief Contains the boost::dll::shared_library class, core class for all the
13 /// DLL/DSO operations.
15 #include <boost/config.hpp>
16 #include <boost/predef/os.h>
17 #include <boost/utility/enable_if.hpp>
18 #include <boost/type_traits/is_member_pointer.hpp>
19 #include <boost/utility/explicit_operator_bool.hpp>
20 #include <boost/dll/detail/system_error.hpp>
21 #include <boost/dll/detail/aggressive_ptr_cast.hpp>
24 # include <boost/dll/detail/windows/shared_library_impl.hpp>
26 # include <boost/dll/detail/posix/shared_library_impl.hpp>
29 #ifdef BOOST_HAS_PRAGMA_ONCE
33 namespace boost { namespace dll {
36 * \brief This class can be used to load a
37 * Dynamic link libraries (DLL's) or Shared Libraries, also know
38 * as dynamic shared objects (DSO's) and get their exported
39 * symbols (functions and variables).
41 * shared_library instances share reference count to an actual loaded DLL/DSO, so it
42 * is safe and memory efficient to have multiple instances of shared_library referencing the same DLL/DSO
43 * even if those instances were loaded using different paths (relative + absolute) referencing the same object.
45 * On Linux/POSIX link with library "dl". "-fvisibility=hidden" flag is also recommended for use on Linux/POSIX.
49 : private boost::dll::detail::shared_library_impl
52 typedef boost::dll::detail::shared_library_impl base_t;
53 BOOST_COPYABLE_AND_MOVABLE(shared_library)
56 #ifdef BOOST_DLL_DOXYGEN
57 typedef platform_specific native_handle_t;
59 typedef shared_library_impl::native_handle_t native_handle_t;
63 * Creates in anstance that does not reference any DLL/DSO.
65 * \post this->is_loaded() returns false.
68 shared_library() BOOST_NOEXCEPT {}
71 * Copy constructor that increments the reference count of an underlying shared library.
72 * Same as calling constructor with `lib.location()` parameter.
74 * \param lib A library to copy.
76 * \throw boost::system::system_error, std::bad_alloc in case of insufficient memory.
78 shared_library(const shared_library& lib)
85 * Copy constructor that increments the reference count of an underlying shared library.
86 * Same as calling constructor with `lib.location(), ec` parameters.
88 * \param lib A shared library to copy.
89 * \param ec Variable that will be set to the result of the operation.
91 * \throw std::bad_alloc in case of insufficient memory.
93 shared_library(const shared_library& lib, boost::system::error_code& ec)
100 * Move constructor. Does not invalidate existing symbols and functions loaded from lib.
102 * \param lib A shared library to move from.
103 * \post lib.is_loaded() returns false, this->is_loaded() return true.
106 shared_library(BOOST_RV_REF(shared_library) lib) BOOST_NOEXCEPT
107 : base_t(boost::move(static_cast<base_t&>(lib)))
111 * Loads a library by specified path with a specified mode.
113 * \param lib_path Library file name. Can handle std::string, const char*, std::wstring,
114 * const wchar_t* or boost::filesystem::path.
115 * \param mode A mode that will be used on library load.
116 * \throw boost::system::system_error, std::bad_alloc in case of insufficient memory.
118 explicit shared_library(const boost::filesystem::path& lib_path, load_mode::type mode = load_mode::default_mode) {
119 shared_library::load(lib_path, mode);
123 * Loads a library by specified path with a specified mode.
125 * \param lib_path Library file name. Can handle std::string, const char*, std::wstring,
126 * const wchar_t* or boost::filesystem::path.
127 * \param mode A mode that will be used on library load.
128 * \param ec Variable that will be set to the result of the operation.
129 * \throw std::bad_alloc in case of insufficient memory.
131 shared_library(const boost::filesystem::path& lib_path, boost::system::error_code& ec, load_mode::type mode = load_mode::default_mode) {
132 shared_library::load(lib_path, mode, ec);
135 //! \overload shared_library(const boost::filesystem::path& lib_path, boost::system::error_code& ec, load_mode::type mode = load_mode::default_mode)
136 shared_library(const boost::filesystem::path& lib_path, load_mode::type mode, boost::system::error_code& ec) {
137 shared_library::load(lib_path, mode, ec);
141 * Assignment operator. If this->is_loaded() then calls this->unload(). Does not invalidate existing symbols and functions loaded from lib.
143 * \param lib A shared library to assign from.
145 * \throw boost::system::system_error, std::bad_alloc in case of insufficient memory.
147 shared_library& operator=(BOOST_COPY_ASSIGN_REF(shared_library) lib) {
148 boost::system::error_code ec;
151 boost::dll::detail::report_error(ec, "boost::dll::shared_library::operator= failed");
158 * Move assignment operator. If this->is_loaded() then calls this->unload(). Does not invalidate existing symbols and functions loaded from lib.
160 * \param lib A library to move from.
161 * \post lib.is_loaded() returns false.
164 shared_library& operator=(BOOST_RV_REF(shared_library) lib) BOOST_NOEXCEPT {
165 if (lib.native() != native()) {
173 * Destroys the object by calling `unload()`. If library was loaded multiple times
174 * by different instances, the actual DLL/DSO won't be unloaded until
175 * there is at least one instance that references the DLL/DSO.
179 ~shared_library() BOOST_NOEXCEPT {}
182 * Makes *this share the same shared object as lib. If *this is loaded, then unloads it.
184 * \post lib.location() == this->location(), lib == *this
185 * \param lib A library to copy.
186 * \param ec Variable that will be set to the result of the operation.
187 * \throw std::bad_alloc in case of insufficient memory.
189 shared_library& assign(const shared_library& lib, boost::system::error_code& ec) {
192 if (native() == lib.native()) {
201 boost::filesystem::path loc = lib.location(ec);
206 shared_library copy(loc, ec);
216 * Makes *this share the same shared object as lib. If *this is loaded, then unloads it.
218 * \param lib A library instance to assign from.
219 * \post lib.location() == this->location()
220 * \throw boost::system::system_error, std::bad_alloc in case of insufficient memory.
222 shared_library& assign(const shared_library& lib) {
223 boost::system::error_code ec;
226 boost::dll::detail::report_error(ec, "boost::dll::shared_library::assign() failed");
233 * Loads a library by specified path with a specified mode.
235 * Note that if some library is already loaded in this instance, load will
236 * call unload() and then load the new provided library.
238 * \param lib_path Library file name. Can handle std::string, const char*, std::wstring,
239 * const wchar_t* or boost::filesystem::path.
240 * \param mode A mode that will be used on library load.
241 * \throw boost::system::system_error, std::bad_alloc in case of insufficient memory.
244 void load(const boost::filesystem::path& lib_path, load_mode::type mode = load_mode::default_mode) {
245 boost::system::error_code ec;
247 base_t::load(lib_path, mode, ec);
250 boost::dll::detail::report_error(ec, "boost::dll::shared_library::load() failed");
255 * Loads a library by specified path with a specified mode.
257 * Note that if some library is already loaded in this instance, load will
258 * call unload() and then load the new provided library.
260 * \param lib_path Library file name. Can handle std::string, const char*, std::wstring,
261 * const wchar_t* or boost::filesystem::path.
262 * \param ec Variable that will be set to the result of the operation.
263 * \param mode A mode that will be used on library load.
264 * \throw std::bad_alloc in case of insufficient memory.
266 void load(const boost::filesystem::path& lib_path, boost::system::error_code& ec, load_mode::type mode = load_mode::default_mode) {
268 base_t::load(lib_path, mode, ec);
271 //! \overload void load(const boost::filesystem::path& lib_path, boost::system::error_code& ec, load_mode::type mode = load_mode::default_mode)
272 void load(const boost::filesystem::path& lib_path, load_mode::type mode, boost::system::error_code& ec) {
274 base_t::load(lib_path, mode, ec);
278 * Unloads a shared library. If library was loaded multiple times
279 * by different instances, the actual DLL/DSO won't be unloaded until
280 * there is at least one instance that references the DLL/DSO.
282 * \post this->is_loaded() returns false.
285 void unload() BOOST_NOEXCEPT {
290 * Check if an library is loaded.
292 * \return true if a library has been loaded.
295 bool is_loaded() const BOOST_NOEXCEPT {
296 return base_t::is_loaded();
300 * Check if an library is not loaded.
302 * \return true if a library has not been loaded.
305 bool operator!() const BOOST_NOEXCEPT {
310 * Check if an library is loaded.
312 * \return true if a library has been loaded.
315 BOOST_EXPLICIT_OPERATOR_BOOL()
318 * Search for a given symbol on loaded library. Works for all symbols, including alias names.
320 * \param symbol_name Null-terminated symbol name. Can handle std::string, char*, const char*.
321 * \return `true` if the loaded library contains a symbol with a given name.
324 bool has(const char* symbol_name) const BOOST_NOEXCEPT {
325 boost::system::error_code ec;
326 return is_loaded() && !!base_t::symbol_addr(symbol_name, ec) && !ec;
329 //! \overload bool has(const char* symbol_name) const
330 bool has(const std::string& symbol_name) const BOOST_NOEXCEPT {
331 return has(symbol_name.c_str());
335 * Returns reference to the symbol (function or variable) with the given name from the loaded library.
336 * This call will always succeed and throw nothing if call to `has(const char* )`
337 * member function with the same symbol name returned `true`.
341 * int& i0 = lib.get<int>("integer_name");
342 * int& i1 = *lib.get<int*>("integer_alias_name");
345 * \tparam T Type of the symbol that we are going to import. Must be explicitly specified.
346 * \param symbol_name Null-terminated symbol name. Can handle std::string, char*, const char*.
347 * \return Reference to the symbol.
348 * \throw boost::system::system_error if symbol does not exist or if the DLL/DSO was not loaded.
350 template <typename T>
351 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 {
352 return get<T>(symbol_name.c_str());
355 //! \overload T& get(const std::string& symbol_name) const
356 template <typename T>
357 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 {
358 return get<T>(symbol_name.c_str());
361 //! \overload T& get(const std::string& symbol_name) const
362 template <typename T>
363 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 {
364 return boost::dll::detail::aggressive_ptr_cast<T>(
365 get_void(symbol_name)
369 //! \overload T& get(const std::string& symbol_name) const
370 template <typename T>
371 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 {
372 return *boost::dll::detail::aggressive_ptr_cast<T*>(
373 get_void(symbol_name)
378 * Returns a symbol (function or variable) from a shared library by alias name of the symbol.
382 * int& i = lib.get_alias<int>("integer_alias_name");
385 * \tparam T Type of the symbol that we are going to import. Must be explicitly specified..
386 * \param alias_name Null-terminated alias symbol name. Can handle std::string, char*, const char*.
387 * \throw boost::system::system_error if symbol does not exist or if the DLL/DSO was not loaded.
389 template <typename T>
390 inline T& get_alias(const char* alias_name) const {
391 return *get<T*>(alias_name);
394 //! \overload T& get_alias(const char* alias_name) const
395 template <typename T>
396 inline T& get_alias(const std::string& alias_name) const {
397 return *get<T*>(alias_name.c_str());
402 // get_void is required to reduce binary size: it does not depend on a template
403 // parameter and will be instantiated only once.
404 void* get_void(const char* sb) const {
405 boost::system::error_code ec;
408 ec = boost::system::error_code(
409 boost::system::errc::bad_file_descriptor,
410 boost::system::generic_category()
413 // report_error() calls dlsym, do not use it here!
414 boost::throw_exception(
415 boost::system::system_error(
416 ec, "boost::dll::shared_library::get() failed: no library was loaded"
421 void* const ret = base_t::symbol_addr(sb, ec);
423 boost::dll::detail::report_error(ec, "boost::dll::shared_library::get() failed");
433 * Returns the native handler of the loaded library.
435 * \return Platform-specific handle.
437 native_handle_t native() const BOOST_NOEXCEPT {
438 return base_t::native();
442 * Returns full path and name of this shared object.
446 * shared_library lib("test_lib.dll");
447 * filesystem::path full_path = lib.location(); // C:\Windows\System32\test_lib.dll
450 * \return Full path to the shared library.
451 * \throw boost::system::system_error, std::bad_alloc.
453 boost::filesystem::path location() const {
454 boost::system::error_code ec;
456 ec = boost::system::error_code(
457 boost::system::errc::bad_file_descriptor,
458 boost::system::generic_category()
461 boost::throw_exception(
462 boost::system::system_error(
463 ec, "boost::dll::shared_library::location() failed (no library was loaded)"
468 boost::filesystem::path full_path = base_t::full_module_path(ec);
471 boost::dll::detail::report_error(ec, "boost::dll::shared_library::location() failed");
478 * Returns full path and name of shared module.
482 * shared_library lib("test_lib.dll");
483 * filesystem::path full_path = lib.location(); // C:\Windows\System32\test_lib.dll
486 * \param ec Variable that will be set to the result of the operation.
487 * \return Full path to the shared library.
488 * \throw std::bad_alloc.
490 boost::filesystem::path location(boost::system::error_code& ec) const {
492 ec = boost::system::error_code(
493 boost::system::errc::bad_file_descriptor,
494 boost::system::generic_category()
497 return boost::filesystem::path();
501 return base_t::full_module_path(ec);
505 * Returns suffix of shared module:
506 * in a call to load() or the constructor/load.
508 * \return The suffix od shared module: ".dll" (Windows), ".so" (Unix/Linux/BSD), ".dylib" (MacOS/IOS)
510 static boost::filesystem::path suffix() {
511 return base_t::suffix();
515 * Swaps two libraries. Does not invalidate existing symbols and functions loaded from libraries.
517 * \param rhs Library to swap with.
520 void swap(shared_library& rhs) BOOST_NOEXCEPT {
527 /// Very fast equality check that compares the actual DLL/DSO objects. Throws nothing.
528 inline bool operator==(const shared_library& lhs, const shared_library& rhs) BOOST_NOEXCEPT {
529 return lhs.native() == rhs.native();
532 /// Very fast inequality check that compares the actual DLL/DSO objects. Throws nothing.
533 inline bool operator!=(const shared_library& lhs, const shared_library& rhs) BOOST_NOEXCEPT {
534 return lhs.native() != rhs.native();
537 /// Compare the actual DLL/DSO objects without any guarantee to be stable between runs. Throws nothing.
538 inline bool operator<(const shared_library& lhs, const shared_library& rhs) BOOST_NOEXCEPT {
539 return lhs.native() < rhs.native();
542 /// Swaps two shared libraries. Does not invalidate symbols and functions loaded from libraries. Throws nothing.
543 inline void swap(shared_library& lhs, shared_library& rhs) BOOST_NOEXCEPT {
549 #endif // BOOST_DLL_SHARED_LIBRARY_HPP