]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/dll/shared_library.hpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / boost / dll / shared_library.hpp
CommitLineData
7c673cae 1// Copyright 2014 Renato Tegon Forti, Antony Polukhin.
1e59de90 2// Copyright Antony Polukhin, 2015-2022.
7c673cae
FG
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
92f5a8d4 15#include <boost/dll/config.hpp>
7c673cae 16#include <boost/predef/os.h>
11fdf7f2
TL
17#include <boost/core/enable_if.hpp>
18#include <boost/core/explicit_operator_bool.hpp>
7c673cae 19#include <boost/type_traits/is_member_pointer.hpp>
7c673cae
FG
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
33namespace 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*/
47class 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
55public:
56#ifdef BOOST_DLL_DOXYGEN
57 typedef platform_specific native_handle_t;
92f5a8d4 58#else
7c673cae
FG
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
92f5a8d4 76 * \throw \forcedlinkfs{system_error}, std::bad_alloc in case of insufficient memory.
7c673cae
FG
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 */
92f5a8d4 93 shared_library(const shared_library& lib, boost::dll::fs::error_code& ec)
7c673cae
FG
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,
92f5a8d4 114 * const wchar_t* or \forcedlinkfs{path}.
7c673cae 115 * \param mode A mode that will be used on library load.
92f5a8d4 116 * \throw \forcedlinkfs{system_error}, std::bad_alloc in case of insufficient memory.
7c673cae 117 */
92f5a8d4 118 explicit shared_library(const boost::dll::fs::path& lib_path, load_mode::type mode = load_mode::default_mode) {
7c673cae
FG
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,
92f5a8d4 126 * const wchar_t* or \forcedlinkfs{path}.
7c673cae
FG
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 */
92f5a8d4 131 shared_library(const boost::dll::fs::path& lib_path, boost::dll::fs::error_code& ec, load_mode::type mode = load_mode::default_mode) {
7c673cae
FG
132 shared_library::load(lib_path, mode, ec);
133 }
134
92f5a8d4
TL
135 //! \overload shared_library(const boost::dll::fs::path& lib_path, boost::dll::fs::error_code& ec, load_mode::type mode = load_mode::default_mode)
136 shared_library(const boost::dll::fs::path& lib_path, load_mode::type mode, boost::dll::fs::error_code& ec) {
7c673cae
FG
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
92f5a8d4 145 * \throw \forcedlinkfs{system_error}, std::bad_alloc in case of insufficient memory.
7c673cae
FG
146 */
147 shared_library& operator=(BOOST_COPY_ASSIGN_REF(shared_library) lib) {
92f5a8d4 148 boost::dll::fs::error_code ec;
7c673cae
FG
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 */
92f5a8d4 189 shared_library& assign(const shared_library& lib, boost::dll::fs::error_code& ec) {
7c673cae
FG
190 ec.clear();
191
192 if (native() == lib.native()) {
193 return *this;
194 }
195
196 if (!lib) {
197 unload();
198 return *this;
199 }
200
92f5a8d4 201 boost::dll::fs::path loc = lib.location(ec);
7c673cae
FG
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()
92f5a8d4 220 * \throw \forcedlinkfs{system_error}, std::bad_alloc in case of insufficient memory.
7c673cae
FG
221 */
222 shared_library& assign(const shared_library& lib) {
92f5a8d4 223 boost::dll::fs::error_code ec;
7c673cae
FG
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,
92f5a8d4 239 * const wchar_t* or \forcedlinkfs{path}.
7c673cae 240 * \param mode A mode that will be used on library load.
92f5a8d4 241 * \throw \forcedlinkfs{system_error}, std::bad_alloc in case of insufficient memory.
7c673cae
FG
242 *
243 */
92f5a8d4
TL
244 void load(const boost::dll::fs::path& lib_path, load_mode::type mode = load_mode::default_mode) {
245 boost::dll::fs::error_code ec;
7c673cae
FG
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,
92f5a8d4 261 * const wchar_t* or \forcedlinkfs{path}.
7c673cae
FG
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 */
92f5a8d4 266 void load(const boost::dll::fs::path& lib_path, boost::dll::fs::error_code& ec, load_mode::type mode = load_mode::default_mode) {
7c673cae
FG
267 ec.clear();
268 base_t::load(lib_path, mode, ec);
269 }
270
92f5a8d4
TL
271 //! \overload void load(const boost::dll::fs::path& lib_path, boost::dll::fs::error_code& ec, load_mode::type mode = load_mode::default_mode)
272 void load(const boost::dll::fs::path& lib_path, load_mode::type mode, boost::dll::fs::error_code& ec) {
7c673cae
FG
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 {
92f5a8d4 325 boost::dll::fs::error_code ec;
7c673cae
FG
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.
92f5a8d4 348 * \throw \forcedlinkfs{system_error} if symbol does not exist or if the DLL/DSO was not loaded.
7c673cae
FG
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*.
92f5a8d4 387 * \throw \forcedlinkfs{system_error} if symbol does not exist or if the DLL/DSO was not loaded.
7c673cae
FG
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
400private:
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 {
92f5a8d4 405 boost::dll::fs::error_code ec;
7c673cae
FG
406
407 if (!is_loaded()) {
92f5a8d4
TL
408 ec = boost::dll::fs::make_error_code(
409 boost::dll::fs::errc::bad_file_descriptor
7c673cae
FG
410 );
411
412 // report_error() calls dlsym, do not use it here!
413 boost::throw_exception(
92f5a8d4 414 boost::dll::fs::system_error(
7c673cae
FG
415 ec, "boost::dll::shared_library::get() failed: no library was loaded"
416 )
417 );
418 }
419
420 void* const ret = base_t::symbol_addr(sb, ec);
421 if (ec || !ret) {
422 boost::dll::detail::report_error(ec, "boost::dll::shared_library::get() failed");
423 }
424
425 return ret;
426 }
427 /// @endcond
428
429public:
430
431 /*!
432 * Returns the native handler of the loaded library.
433 *
434 * \return Platform-specific handle.
435 */
436 native_handle_t native() const BOOST_NOEXCEPT {
437 return base_t::native();
438 }
439
440 /*!
441 * Returns full path and name of this shared object.
442 *
443 * \b Example:
444 * \code
445 * shared_library lib("test_lib.dll");
446 * filesystem::path full_path = lib.location(); // C:\Windows\System32\test_lib.dll
447 * \endcode
448 *
449 * \return Full path to the shared library.
92f5a8d4 450 * \throw \forcedlinkfs{system_error}, std::bad_alloc.
7c673cae 451 */
92f5a8d4
TL
452 boost::dll::fs::path location() const {
453 boost::dll::fs::error_code ec;
7c673cae 454 if (!is_loaded()) {
92f5a8d4
TL
455 ec = boost::dll::fs::make_error_code(
456 boost::dll::fs::errc::bad_file_descriptor
7c673cae
FG
457 );
458
459 boost::throw_exception(
92f5a8d4 460 boost::dll::fs::system_error(
7c673cae
FG
461 ec, "boost::dll::shared_library::location() failed (no library was loaded)"
462 )
463 );
464 }
465
92f5a8d4 466 boost::dll::fs::path full_path = base_t::full_module_path(ec);
7c673cae
FG
467
468 if (ec) {
469 boost::dll::detail::report_error(ec, "boost::dll::shared_library::location() failed");
470 }
471
472 return full_path;
473 }
474
475 /*!
476 * Returns full path and name of shared module.
477 *
478 * \b Example:
479 * \code
480 * shared_library lib("test_lib.dll");
481 * filesystem::path full_path = lib.location(); // C:\Windows\System32\test_lib.dll
482 * \endcode
483 *
484 * \param ec Variable that will be set to the result of the operation.
485 * \return Full path to the shared library.
486 * \throw std::bad_alloc.
487 */
92f5a8d4 488 boost::dll::fs::path location(boost::dll::fs::error_code& ec) const {
7c673cae 489 if (!is_loaded()) {
92f5a8d4
TL
490 ec = boost::dll::fs::make_error_code(
491 boost::dll::fs::errc::bad_file_descriptor
7c673cae
FG
492 );
493
92f5a8d4 494 return boost::dll::fs::path();
7c673cae
FG
495 }
496
497 ec.clear();
498 return base_t::full_module_path(ec);
499 }
500
501 /*!
502 * Returns suffix of shared module:
503 * in a call to load() or the constructor/load.
504 *
505 * \return The suffix od shared module: ".dll" (Windows), ".so" (Unix/Linux/BSD), ".dylib" (MacOS/IOS)
506 */
92f5a8d4 507 static boost::dll::fs::path suffix() {
7c673cae
FG
508 return base_t::suffix();
509 }
510
92f5a8d4
TL
511 /*!
512 * Returns the decorated path to a shared module name, i.e. with needed prefix/suffix added.
513 *
514 * \b Recommendations: Use `load` with `load_mode::append_decorations` instead of constructing the decorated path via `decorate()` and loading by it.
515 *
516 * For instance, for a path like "path/to/boost" it returns :
517 * - path/to/libboost.so on posix platforms
518 * - path/to/libboost.dylib on OSX
519 * - path/to/boost.dll on Windows
520 *
521 * Method handles both relative and absolute paths.
522 *
523 * - Windows note: `decorate()` does not prepend "lib" to the decorated path. Use `load` with `load_mode::append_decorations` for MinGW compatibility purpose.
524 * - Posix note: if the initial module name is already prepended with lib, only the suffix() is appended to the path
525 *
526 * \param sl the module name and path to decorate - for instance : /usr/lib/boost
527 *
528 * \return The decorated unportable path that may not exists in the filesystem or could be wrong due to platform specifics.
529 */
530 static boost::dll::fs::path decorate(const boost::dll::fs::path& sl) {
531 return base_t::decorate(sl);
532 }
533
7c673cae
FG
534 /*!
535 * Swaps two libraries. Does not invalidate existing symbols and functions loaded from libraries.
536 *
537 * \param rhs Library to swap with.
538 * \throw Nothing.
539 */
540 void swap(shared_library& rhs) BOOST_NOEXCEPT {
541 base_t::swap(rhs);
542 }
543};
544
545
546
547/// Very fast equality check that compares the actual DLL/DSO objects. Throws nothing.
548inline bool operator==(const shared_library& lhs, const shared_library& rhs) BOOST_NOEXCEPT {
549 return lhs.native() == rhs.native();
550}
551
552/// Very fast inequality check that compares the actual DLL/DSO objects. Throws nothing.
553inline bool operator!=(const shared_library& lhs, const shared_library& rhs) BOOST_NOEXCEPT {
554 return lhs.native() != rhs.native();
555}
556
557/// Compare the actual DLL/DSO objects without any guarantee to be stable between runs. Throws nothing.
558inline bool operator<(const shared_library& lhs, const shared_library& rhs) BOOST_NOEXCEPT {
559 return lhs.native() < rhs.native();
560}
561
562/// Swaps two shared libraries. Does not invalidate symbols and functions loaded from libraries. Throws nothing.
563inline void swap(shared_library& lhs, shared_library& rhs) BOOST_NOEXCEPT {
564 lhs.swap(rhs);
565}
566
567}} // boost::dll
568
569#endif // BOOST_DLL_SHARED_LIBRARY_HPP