]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/dll/shared_library.hpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / boost / dll / shared_library.hpp
1 // Copyright 2014 Renato Tegon Forti, Antony Polukhin.
2 // Copyright 2015-2016 Antony Polukhin.
3 //
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)
7
8 #ifndef BOOST_DLL_SHARED_LIBRARY_HPP
9 #define BOOST_DLL_SHARED_LIBRARY_HPP
10
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.
14
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>
22
23 #if BOOST_OS_WINDOWS
24 # include <boost/dll/detail/windows/shared_library_impl.hpp>
25 #else
26 # include <boost/dll/detail/posix/shared_library_impl.hpp>
27 #endif
28
29 #ifdef BOOST_HAS_PRAGMA_ONCE
30 # pragma once
31 #endif
32
33 namespace boost { namespace dll {
34
35 /*!
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).
40 *
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.
44 *
45 * On Linux/POSIX link with library "dl". "-fvisibility=hidden" flag is also recommended for use on Linux/POSIX.
46 */
47 class shared_library
48 /// @cond
49 : private boost::dll::detail::shared_library_impl
50 /// @endcond
51 {
52 typedef boost::dll::detail::shared_library_impl base_t;
53 BOOST_COPYABLE_AND_MOVABLE(shared_library)
54
55 public:
56 #ifdef BOOST_DLL_DOXYGEN
57 typedef platform_specific native_handle_t;
58 #else
59 typedef shared_library_impl::native_handle_t native_handle_t;
60 #endif
61
62 /*!
63 * Creates in anstance that does not reference any DLL/DSO.
64 *
65 * \post this->is_loaded() returns false.
66 * \throw Nothing.
67 */
68 shared_library() BOOST_NOEXCEPT {}
69
70 /*!
71 * Copy constructor that increments the reference count of an underlying shared library.
72 * Same as calling constructor with `lib.location()` parameter.
73 *
74 * \param lib A library to copy.
75 * \post lib == *this
76 * \throw boost::system::system_error, std::bad_alloc in case of insufficient memory.
77 */
78 shared_library(const shared_library& lib)
79 : base_t()
80 {
81 assign(lib);
82 }
83
84 /*!
85 * Copy constructor that increments the reference count of an underlying shared library.
86 * Same as calling constructor with `lib.location(), ec` parameters.
87 *
88 * \param lib A shared library to copy.
89 * \param ec Variable that will be set to the result of the operation.
90 * \post lib == *this
91 * \throw std::bad_alloc in case of insufficient memory.
92 */
93 shared_library(const shared_library& lib, boost::system::error_code& ec)
94 : base_t()
95 {
96 assign(lib, ec);
97 }
98
99 /*!
100 * Move constructor. Does not invalidate existing symbols and functions loaded from lib.
101 *
102 * \param lib A shared library to move from.
103 * \post lib.is_loaded() returns false, this->is_loaded() return true.
104 * \throw Nothing.
105 */
106 shared_library(BOOST_RV_REF(shared_library) lib) BOOST_NOEXCEPT
107 : base_t(boost::move(static_cast<base_t&>(lib)))
108 {}
109
110 /*!
111 * Loads a library by specified path with a specified mode.
112 *
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.
117 */
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);
120 }
121
122 /*!
123 * Loads a library by specified path with a specified mode.
124 *
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.
130 */
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);
133 }
134
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);
138 }
139
140 /*!
141 * Assignment operator. If this->is_loaded() then calls this->unload(). Does not invalidate existing symbols and functions loaded from lib.
142 *
143 * \param lib A shared library to assign from.
144 * \post lib == *this
145 * \throw boost::system::system_error, std::bad_alloc in case of insufficient memory.
146 */
147 shared_library& operator=(BOOST_COPY_ASSIGN_REF(shared_library) lib) {
148 boost::system::error_code ec;
149 assign(lib, ec);
150 if (ec) {
151 boost::dll::detail::report_error(ec, "boost::dll::shared_library::operator= failed");
152 }
153
154 return *this;
155 }
156
157 /*!
158 * Move assignment operator. If this->is_loaded() then calls this->unload(). Does not invalidate existing symbols and functions loaded from lib.
159 *
160 * \param lib A library to move from.
161 * \post lib.is_loaded() returns false.
162 * \throw Nothing.
163 */
164 shared_library& operator=(BOOST_RV_REF(shared_library) lib) BOOST_NOEXCEPT {
165 if (lib.native() != native()) {
166 swap(lib);
167 }
168
169 return *this;
170 }
171
172 /*!
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.
176 *
177 * \throw Nothing.
178 */
179 ~shared_library() BOOST_NOEXCEPT {}
180
181 /*!
182 * Makes *this share the same shared object as lib. If *this is loaded, then unloads it.
183 *
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.
188 */
189 shared_library& assign(const shared_library& lib, boost::system::error_code& ec) {
190 ec.clear();
191
192 if (native() == lib.native()) {
193 return *this;
194 }
195
196 if (!lib) {
197 unload();
198 return *this;
199 }
200
201 boost::filesystem::path loc = lib.location(ec);
202 if (ec) {
203 return *this;
204 }
205
206 shared_library copy(loc, ec);
207 if (ec) {
208 return *this;
209 }
210
211 swap(copy);
212 return *this;
213 }
214
215 /*!
216 * Makes *this share the same shared object as lib. If *this is loaded, then unloads it.
217 *
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.
221 */
222 shared_library& assign(const shared_library& lib) {
223 boost::system::error_code ec;
224 assign(lib, ec);
225 if (ec) {
226 boost::dll::detail::report_error(ec, "boost::dll::shared_library::assign() failed");
227 }
228
229 return *this;
230 }
231
232 /*!
233 * Loads a library by specified path with a specified mode.
234 *
235 * Note that if some library is already loaded in this instance, load will
236 * call unload() and then load the new provided library.
237 *
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.
242 *
243 */
244 void load(const boost::filesystem::path& lib_path, load_mode::type mode = load_mode::default_mode) {
245 boost::system::error_code ec;
246
247 base_t::load(lib_path, mode, ec);
248
249 if (ec) {
250 boost::dll::detail::report_error(ec, "boost::dll::shared_library::load() failed");
251 }
252 }
253
254 /*!
255 * Loads a library by specified path with a specified mode.
256 *
257 * Note that if some library is already loaded in this instance, load will
258 * call unload() and then load the new provided library.
259 *
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.
265 */
266 void load(const boost::filesystem::path& lib_path, boost::system::error_code& ec, load_mode::type mode = load_mode::default_mode) {
267 ec.clear();
268 base_t::load(lib_path, mode, ec);
269 }
270
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) {
273 ec.clear();
274 base_t::load(lib_path, mode, ec);
275 }
276
277 /*!
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.
281 *
282 * \post this->is_loaded() returns false.
283 * \throw Nothing.
284 */
285 void unload() BOOST_NOEXCEPT {
286 base_t::unload();
287 }
288
289 /*!
290 * Check if an library is loaded.
291 *
292 * \return true if a library has been loaded.
293 * \throw Nothing.
294 */
295 bool is_loaded() const BOOST_NOEXCEPT {
296 return base_t::is_loaded();
297 }
298
299 /*!
300 * Check if an library is not loaded.
301 *
302 * \return true if a library has not been loaded.
303 * \throw Nothing.
304 */
305 bool operator!() const BOOST_NOEXCEPT {
306 return !is_loaded();
307 }
308
309 /*!
310 * Check if an library is loaded.
311 *
312 * \return true if a library has been loaded.
313 * \throw Nothing.
314 */
315 BOOST_EXPLICIT_OPERATOR_BOOL()
316
317 /*!
318 * Search for a given symbol on loaded library. Works for all symbols, including alias names.
319 *
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.
322 * \throw Nothing.
323 */
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;
327 }
328
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());
332 }
333
334 /*!
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`.
338 *
339 * \b Example:
340 * \code
341 * int& i0 = lib.get<int>("integer_name");
342 * int& i1 = *lib.get<int*>("integer_alias_name");
343 * \endcode
344 *
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.
349 */
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());
353 }
354
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());
359 }
360
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)
366 );
367 }
368
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)
374 );
375 }
376
377 /*!
378 * Returns a symbol (function or variable) from a shared library by alias name of the symbol.
379 *
380 * \b Example:
381 * \code
382 * int& i = lib.get_alias<int>("integer_alias_name");
383 * \endcode
384 *
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.
388 */
389 template <typename T>
390 inline T& get_alias(const char* alias_name) const {
391 return *get<T*>(alias_name);
392 }
393
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());
398 }
399
400 private:
401 /// @cond
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;
406
407 if (!is_loaded()) {
408 ec = boost::system::error_code(
409 boost::system::errc::bad_file_descriptor,
410 boost::system::generic_category()
411 );
412
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"
417 )
418 );
419 }
420
421 void* const ret = base_t::symbol_addr(sb, ec);
422 if (ec || !ret) {
423 boost::dll::detail::report_error(ec, "boost::dll::shared_library::get() failed");
424 }
425
426 return ret;
427 }
428 /// @endcond
429
430 public:
431
432 /*!
433 * Returns the native handler of the loaded library.
434 *
435 * \return Platform-specific handle.
436 */
437 native_handle_t native() const BOOST_NOEXCEPT {
438 return base_t::native();
439 }
440
441 /*!
442 * Returns full path and name of this shared object.
443 *
444 * \b Example:
445 * \code
446 * shared_library lib("test_lib.dll");
447 * filesystem::path full_path = lib.location(); // C:\Windows\System32\test_lib.dll
448 * \endcode
449 *
450 * \return Full path to the shared library.
451 * \throw boost::system::system_error, std::bad_alloc.
452 */
453 boost::filesystem::path location() const {
454 boost::system::error_code ec;
455 if (!is_loaded()) {
456 ec = boost::system::error_code(
457 boost::system::errc::bad_file_descriptor,
458 boost::system::generic_category()
459 );
460
461 boost::throw_exception(
462 boost::system::system_error(
463 ec, "boost::dll::shared_library::location() failed (no library was loaded)"
464 )
465 );
466 }
467
468 boost::filesystem::path full_path = base_t::full_module_path(ec);
469
470 if (ec) {
471 boost::dll::detail::report_error(ec, "boost::dll::shared_library::location() failed");
472 }
473
474 return full_path;
475 }
476
477 /*!
478 * Returns full path and name of shared module.
479 *
480 * \b Example:
481 * \code
482 * shared_library lib("test_lib.dll");
483 * filesystem::path full_path = lib.location(); // C:\Windows\System32\test_lib.dll
484 * \endcode
485 *
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.
489 */
490 boost::filesystem::path location(boost::system::error_code& ec) const {
491 if (!is_loaded()) {
492 ec = boost::system::error_code(
493 boost::system::errc::bad_file_descriptor,
494 boost::system::generic_category()
495 );
496
497 return boost::filesystem::path();
498 }
499
500 ec.clear();
501 return base_t::full_module_path(ec);
502 }
503
504 /*!
505 * Returns suffix of shared module:
506 * in a call to load() or the constructor/load.
507 *
508 * \return The suffix od shared module: ".dll" (Windows), ".so" (Unix/Linux/BSD), ".dylib" (MacOS/IOS)
509 */
510 static boost::filesystem::path suffix() {
511 return base_t::suffix();
512 }
513
514 /*!
515 * Swaps two libraries. Does not invalidate existing symbols and functions loaded from libraries.
516 *
517 * \param rhs Library to swap with.
518 * \throw Nothing.
519 */
520 void swap(shared_library& rhs) BOOST_NOEXCEPT {
521 base_t::swap(rhs);
522 }
523 };
524
525
526
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();
530 }
531
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();
535 }
536
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();
540 }
541
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 {
544 lhs.swap(rhs);
545 }
546
547 }} // boost::dll
548
549 #endif // BOOST_DLL_SHARED_LIBRARY_HPP
550