1 // Copyright 2016 Klemens Morgenstern
2 // Copyright Antony Polukhin, 2019-2022
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_SMART_LIBRARY_HPP_
9 #define BOOST_DLL_SMART_LIBRARY_HPP_
11 /// \file boost/dll/smart_library.hpp
12 /// \warning Extremely experimental! Requires C++11! Will change in next version of Boost! boost/dll/smart_library.hpp is not included in boost/dll.hpp
13 /// \brief Contains the boost::dll::experimental::smart_library class for loading mangled symbols.
15 #include <boost/dll/config.hpp>
16 #if defined(_MSC_VER) // MSVC, Clang-cl, and ICC on Windows
17 # include <boost/dll/detail/demangling/msvc.hpp>
19 # include <boost/dll/detail/demangling/itanium.hpp>
22 #if (__cplusplus < 201103L) && (!defined(_MSVC_LANG) || _MSVC_LANG < 201103L)
23 # error This file requires C++11 at least!
26 #include <boost/dll/shared_library.hpp>
27 #include <boost/dll/detail/get_mem_fn_type.hpp>
28 #include <boost/dll/detail/ctor_dtor.hpp>
29 #include <boost/dll/detail/type_info.hpp>
30 #include <boost/type_traits/is_object.hpp>
31 #include <boost/type_traits/is_void.hpp>
32 #include <boost/type_traits/is_function.hpp>
38 namespace experimental {
40 using boost::dll::detail::constructor;
41 using boost::dll::detail::destructor;
44 * \brief This class is an extension of \ref shared_library, which allows to load C++ symbols.
46 * This class allows type safe loading of overloaded functions, member-functions, constructors and variables.
47 * It also allows to overwrite classes so they can be loaded, while being declared with different names.
49 * \warning Is still very experimental.
51 * Currently known limitations:
53 * Member functions must be defined outside of the class to be exported. That is:
56 * struct BOOST_SYMBOL_EXPORT my_class { void func() {}};
58 * struct BOOST_SYMBOL_EXPORT my_class { void func();};
59 * void my_class::func() {};
62 * With the current analysis, the first version does get exported in MSVC.
63 * MinGW also does export it, BOOST_SYMBOL_EXPORT is written before it. To allow this on windows one can use
64 * BOOST_DLL_MEMBER_EXPORT for this, so that MinGW and MSVC can provide those functions. This does however not work with gcc on linux.
66 * Direct initialization of members.
67 * On linux the following member variable i will not be initialized when using the allocating constructor:
69 * struct BOOST_SYMBOL_EXPORT my_class { int i; my_class() : i(42) {} };
72 * This does however not happen when the value is set inside the constructor function.
76 detail::mangled_storage_impl _storage;
80 * Get the underlying shared_library
82 const shared_library &shared_lib() const {return _lib;}
84 using mangled_storage = detail::mangled_storage_impl;
86 * Access to the mangled storage, which is created on construction.
90 const mangled_storage &symbol_storage() const {return _storage;}
92 ///Overload, for current development.
93 mangled_storage &symbol_storage() {return _storage;}
95 //! \copydoc shared_library::shared_library()
96 smart_library() BOOST_NOEXCEPT {};
98 //! \copydoc shared_library::shared_library(const boost::dll::fs::path& lib_path, load_mode::type mode = load_mode::default_mode)
99 smart_library(const boost::dll::fs::path& lib_path, load_mode::type mode = load_mode::default_mode) {
100 _lib.load(lib_path, mode);
101 _storage.load(lib_path);
104 //! \copydoc shared_library::shared_library(const boost::dll::fs::path& lib_path, boost::dll::fs::error_code& ec, load_mode::type mode = load_mode::default_mode)
105 smart_library(const boost::dll::fs::path& lib_path, boost::dll::fs::error_code& ec, load_mode::type mode = load_mode::default_mode) {
106 load(lib_path, mode, ec);
109 //! \copydoc shared_library::shared_library(const boost::dll::fs::path& lib_path, load_mode::type mode, boost::dll::fs::error_code& ec)
110 smart_library(const boost::dll::fs::path& lib_path, load_mode::type mode, boost::dll::fs::error_code& ec) {
111 load(lib_path, mode, ec);
114 * copy a smart_library object.
116 * \param lib A smart_library to move from.
120 smart_library(const smart_library & lib) BOOST_NOEXCEPT
121 : _lib(lib._lib), _storage(lib._storage)
124 * Move a smart_library object.
126 * \param lib A smart_library to move from.
130 smart_library(BOOST_RV_REF(smart_library) lib) BOOST_NOEXCEPT
131 : _lib(boost::move(lib._lib)), _storage(boost::move(lib._storage))
135 * Construct from a shared_library object.
137 * \param lib A shared_library to move from.
141 explicit smart_library(const shared_library & lib) BOOST_NOEXCEPT
144 _storage.load(lib.location());
147 * Construct from a shared_library object.
149 * \param lib A shared_library to move from.
153 explicit smart_library(BOOST_RV_REF(shared_library) lib) BOOST_NOEXCEPT
154 : _lib(boost::move(static_cast<shared_library&>(lib)))
156 _storage.load(lib.location());
160 * Destroys the smart_library.
161 * `unload()` is called if the DLL/DSO was loaded. If library was loaded multiple times
162 * by different instances of shared_library, the actual DLL/DSO won't be unloaded until
163 * there is at least one instance of shared_library.
167 ~smart_library() BOOST_NOEXCEPT {};
169 //! \copydoc shared_library::load(const boost::dll::fs::path& lib_path, load_mode::type mode = load_mode::default_mode)
170 void load(const boost::dll::fs::path& lib_path, load_mode::type mode = load_mode::default_mode) {
171 boost::dll::fs::error_code ec;
172 _storage.load(lib_path);
173 _lib.load(lib_path, mode, ec);
176 boost::dll::detail::report_error(ec, "load() failed");
180 //! \copydoc shared_library::load(const boost::dll::fs::path& lib_path, boost::dll::fs::error_code& ec, load_mode::type mode = load_mode::default_mode)
181 void load(const boost::dll::fs::path& lib_path, boost::dll::fs::error_code& ec, load_mode::type mode = load_mode::default_mode) {
183 _storage.load(lib_path);
184 _lib.load(lib_path, mode, ec);
187 //! \copydoc shared_library::load(const boost::dll::fs::path& lib_path, load_mode::type mode, boost::dll::fs::error_code& ec)
188 void load(const boost::dll::fs::path& lib_path, load_mode::type mode, boost::dll::fs::error_code& ec) {
190 _storage.load(lib_path);
191 _lib.load(lib_path, mode, ec);
195 * Load a variable from the referenced library.
197 * Unlinke shared_library::get this function will also load scoped variables, which also includes static class members.
199 * \note When mangled, MSVC will also check the type.
201 * \param name Name of the variable
202 * \tparam T Type of the variable
203 * \return A reference to the variable of type T.
205 * \throw \forcedlinkfs{system_error} if symbol does not exist or if the DLL/DSO was not loaded.
208 T& get_variable(const std::string &name) const {
209 return _lib.get<T>(_storage.get_variable<T>(name));
213 * Load a function from the referenced library.
218 * smart_library lib("test_lib.so");
219 * typedef int (&add_ints)(int, int);
220 * typedef double (&add_doubles)(double, double);
221 * add_ints f1 = lib.get_function<int(int, int)> ("func_name");
222 * add_doubles f2 = lib.get_function<double(double, double)>("func_name");
225 * \note When mangled, MSVC will also check the return type.
227 * \param name Name of the function.
228 * \tparam Func Type of the function, required for determining the overload
229 * \return A reference to the function of type F.
231 * \throw \forcedlinkfs{system_error} if symbol does not exist or if the DLL/DSO was not loaded.
233 template<typename Func>
234 Func& get_function(const std::string &name) const {
235 return _lib.get<Func>(_storage.get_function<Func>(name));
239 * Load a member-function from the referenced library.
241 * \b Example (import class is MyClass, which is available inside the library and the host):
244 * smart_library lib("test_lib.so");
246 * typedef int MyClass(*func)(int);
247 * typedef int MyClass(*func_const)(int) const;
249 * add_ints f1 = lib.get_mem_fn<MyClass, int(int)> ("MyClass::function");
250 * add_doubles f2 = lib.get_mem_fn<const MyClass, double(double)>("MyClass::function");
253 * \note When mangled, MSVC will also check the return type.
255 * \param name Name of the function.
256 * \tparam Class The class the function is a member of. If Class is const, the function will be assumed as taking a const this-pointer. The same applies for volatile.
257 * \tparam Func Signature of the function, required for determining the overload
258 * \return A pointer to the member-function with the signature provided
260 * \throw \forcedlinkfs{system_error} if symbol does not exist or if the DLL/DSO was not loaded.
262 template<typename Class, typename Func>
263 typename boost::dll::detail::get_mem_fn_type<Class, Func>::mem_fn get_mem_fn(const std::string& name) const {
264 return _lib.get<typename boost::dll::detail::get_mem_fn_type<Class, Func>::mem_fn>(
265 _storage.get_mem_fn<Class, Func>(name)
270 * Load a constructor from the referenced library.
272 * \b Example (import class is MyClass, which is available inside the library and the host):
275 * smart_library lib("test_lib.so");
277 * constructor<MyClass(int) f1 = lib.get_mem_fn<MyClass(int)>();
280 * \tparam Signature Signature of the function, required for determining the overload. The return type is the class which this is the constructor of.
281 * \return A constructor object.
283 * \throw \forcedlinkfs{system_error} if symbol does not exist or if the DLL/DSO was not loaded.
285 template<typename Signature>
286 constructor<Signature> get_constructor() const {
287 return boost::dll::detail::load_ctor<Signature>(_lib, _storage.get_constructor<Signature>());
291 * Load a destructor from the referenced library.
293 * \b Example (import class is MyClass, which is available inside the library and the host):
296 * smart_library lib("test_lib.so");
298 * destructor<MyClass> f1 = lib.get_mem_fn<MyClass>();
301 * \tparam Class The class whose destructor shall be loaded
302 * \return A destructor object.
304 * \throw \forcedlinkfs{system_error} if symbol does not exist or if the DLL/DSO was not loaded.
307 template<typename Class>
308 destructor<Class> get_destructor() const {
309 return boost::dll::detail::load_dtor<Class>(_lib, _storage.get_destructor<Class>());
312 * Load the typeinfo of the given type.
314 * \b Example (import class is MyClass, which is available inside the library and the host):
317 * smart_library lib("test_lib.so");
319 * std::type_info &ti = lib.get_Type_info<MyClass>();
322 * \tparam Class The class whose typeinfo shall be loaded
323 * \return A reference to a type_info object.
325 * \throw \forcedlinkfs{system_error} if symbol does not exist or if the DLL/DSO was not loaded.
328 template<typename Class>
329 const std::type_info& get_type_info() const
331 return boost::dll::detail::load_type_info<Class>(_lib, _storage);
334 * This function can be used to add a type alias.
336 * This is to be used, when a class shall be imported, which is not declared on the host side.
340 * smart_library lib("test_lib.so");
342 * lib.add_type_alias<MyAlias>("MyClass"); //when using MyAlias, the library will look for MyClass
344 * //get the destructor of MyClass
345 * destructor<MyAlias> dtor = lib.get_destructor<MyAlias>();
349 * \param name Name of the class the alias is for.
351 * \attention If the alias-type is not large enough for the imported class, it will result in undefined behaviour.
352 * \warning The alias will only be applied for the type signature, it will not replace the token in the scoped name.
354 template<typename Alias> void add_type_alias(const std::string& name) {
355 this->_storage.add_alias<Alias>(name);
358 //! \copydoc shared_library::unload()
359 void unload() BOOST_NOEXCEPT {
364 //! \copydoc shared_library::is_loaded() const
365 bool is_loaded() const BOOST_NOEXCEPT {
366 return _lib.is_loaded();
369 //! \copydoc shared_library::operator!() const
370 bool operator!() const BOOST_NOEXCEPT {
374 //! \copydoc shared_library::operator bool() const
375 BOOST_EXPLICIT_OPERATOR_BOOL()
377 //! \copydoc shared_library::has(const char* symbol_name) const
378 bool has(const char* symbol_name) const BOOST_NOEXCEPT {
379 return _lib.has(symbol_name);
382 //! \copydoc shared_library::has(const std::string& symbol_name) const
383 bool has(const std::string& symbol_name) const BOOST_NOEXCEPT {
384 return _lib.has(symbol_name);
387 //! \copydoc shared_library::assign(const shared_library& lib)
388 smart_library& assign(const smart_library& lib) {
389 _lib.assign(lib._lib);
390 _storage.assign(lib._storage);
394 //! \copydoc shared_library::swap(shared_library& rhs)
395 void swap(smart_library& rhs) BOOST_NOEXCEPT {
397 _storage.swap(rhs._storage);
401 /// Very fast equality check that compares the actual DLL/DSO objects. Throws nothing.
402 inline bool operator==(const smart_library& lhs, const smart_library& rhs) BOOST_NOEXCEPT {
403 return lhs.shared_lib().native() == rhs.shared_lib().native();
406 /// Very fast inequality check that compares the actual DLL/DSO objects. Throws nothing.
407 inline bool operator!=(const smart_library& lhs, const smart_library& rhs) BOOST_NOEXCEPT {
408 return lhs.shared_lib().native() != rhs.shared_lib().native();
411 /// Compare the actual DLL/DSO objects without any guarantee to be stable between runs. Throws nothing.
412 inline bool operator<(const smart_library& lhs, const smart_library& rhs) BOOST_NOEXCEPT {
413 return lhs.shared_lib().native() < rhs.shared_lib().native();
416 /// Swaps two shared libraries. Does not invalidate symbols and functions loaded from libraries. Throws nothing.
417 inline void swap(smart_library& lhs, smart_library& rhs) BOOST_NOEXCEPT {
422 #ifdef BOOST_DLL_DOXYGEN
423 /** Helper functions for overloads.
425 * Gets either a variable, function or member-function, depending on the signature.
428 * smart_library sm("lib.so");
429 * get<int>(sm, "space::value"); //import a variable
430 * get<void(int)>(sm, "space::func"); //import a function
431 * get<some_class, void(int)>(sm, "space::class_::mem_fn"); //import a member function
434 * @param sm A reference to the @ref smart_library
435 * @param name The name of the entity to import
437 template<class T, class T2>
438 void get(const smart_library& sm, const std::string &name);
442 typename boost::enable_if<boost::is_object<T>, T&>::type get(const smart_library& sm, const std::string &name)
445 return sm.get_variable<T>(name);
449 typename boost::enable_if<boost::is_function<T>, T&>::type get(const smart_library& sm, const std::string &name)
451 return sm.get_function<T>(name);
454 template<class Class, class Signature>
455 auto get(const smart_library& sm, const std::string &name) -> typename detail::get_mem_fn_type<Class, Signature>::mem_fn
457 return sm.get_mem_fn<Class, Signature>(name);
461 } /* namespace experimental */
462 } /* namespace dll */
463 } /* namespace boost */
465 #endif /* BOOST_DLL_SMART_LIBRARY_HPP_ */