![]() |
|
|||
File indexing completed on 2025-09-17 08:25:45
0001 // Copyright 2016 Klemens Morgenstern 0002 // Copyright Antony Polukhin, 2019-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_SMART_LIBRARY_HPP_ 0009 #define BOOST_DLL_SMART_LIBRARY_HPP_ 0010 0011 /// \file boost/dll/smart_library.hpp 0012 /// \warning Experimental feature that relies on an incomplete implementation of platform specific C++ 0013 /// mangling. In case of an issue provide a PR with a fix and tests to https://github.com/boostorg/dll . 0014 /// boost/dll/smart_library.hpp is not included in boost/dll.hpp 0015 /// \brief Contains the boost::dll::experimental::smart_library class for loading mangled symbols. 0016 0017 #include <boost/dll/config.hpp> 0018 #if defined(_MSC_VER) // MSVC, Clang-cl, and ICC on Windows 0019 # include <boost/dll/detail/demangling/msvc.hpp> 0020 #else 0021 # include <boost/dll/detail/demangling/itanium.hpp> 0022 #endif 0023 0024 #if (__cplusplus < 201103L) && (!defined(_MSVC_LANG) || _MSVC_LANG < 201103L) 0025 # error This file requires C++11 at least! 0026 #endif 0027 0028 #include <boost/dll/shared_library.hpp> 0029 #include <boost/dll/detail/get_mem_fn_type.hpp> 0030 #include <boost/dll/detail/ctor_dtor.hpp> 0031 #include <boost/dll/detail/type_info.hpp> 0032 0033 #include <type_traits> 0034 #include <utility> // std::move 0035 0036 namespace boost { 0037 namespace dll { 0038 namespace experimental { 0039 0040 using boost::dll::detail::constructor; 0041 using boost::dll::detail::destructor; 0042 0043 /*! 0044 * \brief This class is an extension of \ref shared_library, which allows to load C++ symbols. 0045 * 0046 * This class allows type safe loading of overloaded functions, member-functions, constructors and variables. 0047 * It also allows to overwrite classes so they can be loaded, while being declared with different names. 0048 * 0049 * \warning Experimental feature that relies on an incomplete implementation of platform specific C++ 0050 * mangling. In case of an issue provide a PR with a fix and tests to https://github.com/boostorg/dll 0051 * 0052 * Currently known limitations: 0053 * 0054 * Member functions must be defined outside of the class to be exported. That is: 0055 * \code 0056 * //not exported: 0057 * struct BOOST_SYMBOL_EXPORT my_class { void func() {} }; 0058 * //exported 0059 * struct BOOST_SYMBOL_EXPORT my_class { void func(); }; 0060 * void my_class::func() {} 0061 * \endcode 0062 * 0063 * With the current analysis, the first version does get exported in MSVC. 0064 * MinGW also does export it, BOOST_SYMBOL_EXPORT is written before it. To allow this on windows one can use 0065 * BOOST_DLL_MEMBER_EXPORT for this, so that MinGW and MSVC can provide those functions. This does however not work with gcc on linux. 0066 * 0067 * Direct initialization of members. 0068 * On linux the following member variable i will not be initialized when using the allocating constructor: 0069 * \code 0070 * struct BOOST_SYMBOL_EXPORT my_class { int i; my_class() : i(42) {} }; 0071 * \endcode 0072 * 0073 * This does however not happen when the value is set inside the constructor function. 0074 */ 0075 class smart_library { 0076 shared_library lib_; 0077 detail::mangled_storage_impl storage_; 0078 0079 public: 0080 /*! 0081 * Get the underlying shared_library 0082 */ 0083 const shared_library &shared_lib() const noexcept { return lib_;} 0084 0085 using mangled_storage = detail::mangled_storage_impl; 0086 /*! 0087 * Access to the mangled storage, which is created on construction. 0088 * 0089 * \throw Nothing. 0090 */ 0091 const mangled_storage &symbol_storage() const noexcept { return storage_; } 0092 0093 ///Overload, for current development. 0094 mangled_storage &symbol_storage() noexcept { return storage_; } 0095 0096 //! \copydoc shared_library::shared_library() 0097 smart_library() = default; 0098 0099 //! \copydoc shared_library::shared_library(const boost::dll::fs::path& lib_path, load_mode::type mode = load_mode::default_mode) 0100 smart_library(const boost::dll::fs::path& lib_path, load_mode::type mode = load_mode::default_mode) { 0101 lib_.load(lib_path, mode); 0102 storage_.load(lib_path); 0103 } 0104 0105 //! \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) 0106 smart_library(const boost::dll::fs::path& lib_path, boost::dll::fs::error_code& ec, load_mode::type mode = load_mode::default_mode) { 0107 load(lib_path, mode, ec); 0108 } 0109 0110 //! \copydoc shared_library::shared_library(const boost::dll::fs::path& lib_path, load_mode::type mode, boost::dll::fs::error_code& ec) 0111 smart_library(const boost::dll::fs::path& lib_path, load_mode::type mode, boost::dll::fs::error_code& ec) { 0112 load(lib_path, mode, ec); 0113 } 0114 /*! 0115 * copy a smart_library object. 0116 * 0117 * \param lib A smart_library to move from. 0118 * 0119 * \throw Nothing. 0120 */ 0121 smart_library(const smart_library & lib) = default; 0122 /*! 0123 * Move a smart_library object. 0124 * 0125 * \param lib A smart_library to move from. 0126 * 0127 * \throw Nothing. 0128 */ 0129 smart_library(smart_library&& lib) = default; 0130 0131 /*! 0132 * Construct from a shared_library object. 0133 * 0134 * \param lib A shared_library to move from. 0135 * 0136 * \throw Nothing. 0137 */ 0138 explicit smart_library(const shared_library & lib) noexcept 0139 : lib_(lib) 0140 { 0141 storage_.load(lib.location()); 0142 } 0143 /*! 0144 * Construct from a shared_library object. 0145 * 0146 * \param lib A shared_library to move from. 0147 * 0148 * \throw Nothing. 0149 */ 0150 explicit smart_library(shared_library&& lib) noexcept 0151 : lib_(std::move(lib)) 0152 { 0153 storage_.load(lib.location()); 0154 } 0155 0156 /*! 0157 * Destroys the smart_library. 0158 * `unload()` is called if the DLL/DSO was loaded. If library was loaded multiple times 0159 * by different instances of shared_library, the actual DLL/DSO won't be unloaded until 0160 * there is at least one instance of shared_library. 0161 * 0162 * \throw Nothing. 0163 */ 0164 ~smart_library() = default; 0165 0166 //! \copydoc shared_library::load(const boost::dll::fs::path& lib_path, load_mode::type mode = load_mode::default_mode) 0167 void load(const boost::dll::fs::path& lib_path, load_mode::type mode = load_mode::default_mode) { 0168 boost::dll::fs::error_code ec; 0169 storage_.load(lib_path); 0170 lib_.load(lib_path, mode, ec); 0171 0172 if (ec) { 0173 boost::dll::detail::report_error(ec, "load() failed"); 0174 } 0175 } 0176 0177 //! \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) 0178 void load(const boost::dll::fs::path& lib_path, boost::dll::fs::error_code& ec, load_mode::type mode = load_mode::default_mode) { 0179 ec.clear(); 0180 storage_.load(lib_path); 0181 lib_.load(lib_path, mode, ec); 0182 } 0183 0184 //! \copydoc shared_library::load(const boost::dll::fs::path& lib_path, load_mode::type mode, boost::dll::fs::error_code& ec) 0185 void load(const boost::dll::fs::path& lib_path, load_mode::type mode, boost::dll::fs::error_code& ec) { 0186 ec.clear(); 0187 storage_.load(lib_path); 0188 lib_.load(lib_path, mode, ec); 0189 } 0190 0191 /*! 0192 * Load a variable from the referenced library. 0193 * 0194 * Unlinke shared_library::get this function will also load scoped variables, which also includes static class members. 0195 * 0196 * \note When mangled, MSVC will also check the type. 0197 * 0198 * \param name Name of the variable 0199 * \tparam T Type of the variable 0200 * \return A reference to the variable of type T. 0201 * 0202 * \throw \forcedlinkfs{system_error} if symbol does not exist or if the DLL/DSO was not loaded. 0203 */ 0204 template<typename T> 0205 T& get_variable(const std::string &name) const { 0206 return lib_.get<T>(storage_.get_variable<T>(name)); 0207 } 0208 0209 /*! 0210 * Load a function from the referenced library. 0211 * 0212 * \b Example: 0213 * 0214 * \code 0215 * smart_library lib("test_lib.so"); 0216 * typedef int (&add_ints)(int, int); 0217 * typedef double (&add_doubles)(double, double); 0218 * add_ints f1 = lib.get_function<int(int, int)> ("func_name"); 0219 * add_doubles f2 = lib.get_function<double(double, double)>("func_name"); 0220 * \endcode 0221 * 0222 * \note When mangled, MSVC will also check the return type. 0223 * 0224 * \param name Name of the function. 0225 * \tparam Func Type of the function, required for determining the overload 0226 * \return A reference to the function of type F. 0227 * 0228 * \throw \forcedlinkfs{system_error} if symbol does not exist or if the DLL/DSO was not loaded. 0229 */ 0230 template<typename Func> 0231 Func& get_function(const std::string &name) const { 0232 return lib_.get<Func>(storage_.get_function<Func>(name)); 0233 } 0234 0235 /*! 0236 * Load a member-function from the referenced library. 0237 * 0238 * \b Example (import class is MyClass, which is available inside the library and the host): 0239 * 0240 * \code 0241 * smart_library lib("test_lib.so"); 0242 * 0243 * typedef int MyClass(*func)(int); 0244 * typedef int MyClass(*func_const)(int) const; 0245 * 0246 * add_ints f1 = lib.get_mem_fn<MyClass, int(int)> ("MyClass::function"); 0247 * add_doubles f2 = lib.get_mem_fn<const MyClass, double(double)>("MyClass::function"); 0248 * \endcode 0249 * 0250 * \note When mangled, MSVC will also check the return type. 0251 * 0252 * \param name Name of the function. 0253 * \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. 0254 * \tparam Func Signature of the function, required for determining the overload 0255 * \return A pointer to the member-function with the signature provided 0256 * 0257 * \throw \forcedlinkfs{system_error} if symbol does not exist or if the DLL/DSO was not loaded. 0258 */ 0259 template<typename Class, typename Func> 0260 typename boost::dll::detail::get_mem_fn_type<Class, Func>::mem_fn get_mem_fn(const std::string& name) const { 0261 return lib_.get<typename boost::dll::detail::get_mem_fn_type<Class, Func>::mem_fn>( 0262 storage_.get_mem_fn<Class, Func>(name) 0263 ); 0264 } 0265 0266 /*! 0267 * Load a constructor from the referenced library. 0268 * 0269 * \b Example (import class is MyClass, which is available inside the library and the host): 0270 * 0271 * \code 0272 * smart_library lib("test_lib.so"); 0273 * 0274 * constructor<MyClass(int) f1 = lib.get_mem_fn<MyClass(int)>(); 0275 * \endcode 0276 * 0277 * \tparam Signature Signature of the function, required for determining the overload. The return type is the class which this is the constructor of. 0278 * \return A constructor object. 0279 * 0280 * \throw \forcedlinkfs{system_error} if symbol does not exist or if the DLL/DSO was not loaded. 0281 */ 0282 template<typename Signature> 0283 constructor<Signature> get_constructor() const { 0284 return boost::dll::detail::load_ctor<Signature>(lib_, storage_.get_constructor<Signature>()); 0285 } 0286 0287 /*! 0288 * Load a destructor from the referenced library. 0289 * 0290 * \b Example (import class is MyClass, which is available inside the library and the host): 0291 * 0292 * \code 0293 * smart_library lib("test_lib.so"); 0294 * 0295 * destructor<MyClass> f1 = lib.get_mem_fn<MyClass>(); 0296 * \endcode 0297 * 0298 * \tparam Class The class whose destructor shall be loaded 0299 * \return A destructor object. 0300 * 0301 * \throw \forcedlinkfs{system_error} if symbol does not exist or if the DLL/DSO was not loaded. 0302 * 0303 */ 0304 template<typename Class> 0305 destructor<Class> get_destructor() const { 0306 return boost::dll::detail::load_dtor<Class>(lib_, storage_.get_destructor<Class>()); 0307 } 0308 /*! 0309 * Load the typeinfo of the given type. 0310 * 0311 * \b Example (import class is MyClass, which is available inside the library and the host): 0312 * 0313 * \code 0314 * smart_library lib("test_lib.so"); 0315 * 0316 * std::type_info &ti = lib.get_Type_info<MyClass>(); 0317 * \endcode 0318 * 0319 * \tparam Class The class whose typeinfo shall be loaded 0320 * \return A reference to a type_info object. 0321 * 0322 * \throw \forcedlinkfs{system_error} if symbol does not exist or if the DLL/DSO was not loaded. 0323 * 0324 */ 0325 template<typename Class> 0326 const std::type_info& get_type_info() const 0327 { 0328 return boost::dll::detail::load_type_info<Class>(lib_, storage_); 0329 } 0330 /** 0331 * This function can be used to add a type alias. 0332 * 0333 * This is to be used, when a class shall be imported, which is not declared on the host side. 0334 * 0335 * Example: 0336 * \code 0337 * smart_library lib("test_lib.so"); 0338 * 0339 * lib.add_type_alias<MyAlias>("MyClass"); //when using MyAlias, the library will look for MyClass 0340 * 0341 * //get the destructor of MyClass 0342 * destructor<MyAlias> dtor = lib.get_destructor<MyAlias>(); 0343 * \endcode 0344 * 0345 * 0346 * \param name Name of the class the alias is for. 0347 * 0348 * \attention If the alias-type is not large enough for the imported class, it will result in undefined behaviour. 0349 * \warning The alias will only be applied for the type signature, it will not replace the token in the scoped name. 0350 */ 0351 template<typename Alias> void add_type_alias(const std::string& name) { 0352 this->storage_.add_alias<Alias>(name); 0353 } 0354 0355 //! \copydoc shared_library::unload() 0356 void unload() noexcept { 0357 storage_.clear(); 0358 lib_.unload(); 0359 } 0360 0361 //! \copydoc shared_library::is_loaded() const 0362 bool is_loaded() const noexcept { 0363 return lib_.is_loaded(); 0364 } 0365 0366 //! \copydoc shared_library::operator bool() const 0367 explicit operator bool() const noexcept { 0368 return is_loaded(); 0369 } 0370 0371 //! \copydoc shared_library::has(const char* symbol_name) const 0372 bool has(const char* symbol_name) const noexcept { 0373 return lib_.has(symbol_name); 0374 } 0375 0376 //! \copydoc shared_library::has(const std::string& symbol_name) const 0377 bool has(const std::string& symbol_name) const noexcept { 0378 return lib_.has(symbol_name); 0379 } 0380 0381 //! \copydoc shared_library::assign(const shared_library& lib) 0382 smart_library& assign(const smart_library& lib) { 0383 lib_.assign(lib.lib_); 0384 storage_.assign(lib.storage_); 0385 return *this; 0386 } 0387 0388 //! \copydoc shared_library::swap(shared_library& rhs) 0389 void swap(smart_library& rhs) noexcept { 0390 lib_.swap(rhs.lib_); 0391 storage_.swap(rhs.storage_); 0392 } 0393 }; 0394 0395 /// Very fast equality check that compares the actual DLL/DSO objects. Throws nothing. 0396 inline bool operator==(const smart_library& lhs, const smart_library& rhs) noexcept { 0397 return lhs.shared_lib().native() == rhs.shared_lib().native(); 0398 } 0399 0400 /// Very fast inequality check that compares the actual DLL/DSO objects. Throws nothing. 0401 inline bool operator!=(const smart_library& lhs, const smart_library& rhs) noexcept { 0402 return lhs.shared_lib().native() != rhs.shared_lib().native(); 0403 } 0404 0405 /// Compare the actual DLL/DSO objects without any guarantee to be stable between runs. Throws nothing. 0406 inline bool operator<(const smart_library& lhs, const smart_library& rhs) noexcept { 0407 return lhs.shared_lib().native() < rhs.shared_lib().native(); 0408 } 0409 0410 /// Swaps two shared libraries. Does not invalidate symbols and functions loaded from libraries. Throws nothing. 0411 inline void swap(smart_library& lhs, smart_library& rhs) noexcept { 0412 lhs.swap(rhs); 0413 } 0414 0415 0416 #ifdef BOOST_DLL_DOXYGEN 0417 /** Helper functions for overloads. 0418 * 0419 * Gets either a variable, function or member-function, depending on the signature. 0420 * 0421 * @code 0422 * smart_library sm("lib.so"); 0423 * get<int>(sm, "space::value"); //import a variable 0424 * get<void(int)>(sm, "space::func"); //import a function 0425 * get<some_class, void(int)>(sm, "space::class_::mem_fn"); //import a member function 0426 * @endcode 0427 * 0428 * @param sm A reference to the @ref smart_library 0429 * @param name The name of the entity to import 0430 */ 0431 template<class T, class T2> 0432 void get(const smart_library& sm, const std::string &name); 0433 #endif 0434 0435 template<class T> 0436 typename std::enable_if<std::is_object<T>::value, T&>::type get(const smart_library& sm, const std::string &name) 0437 0438 { 0439 return sm.get_variable<T>(name); 0440 } 0441 0442 template<class T> 0443 typename std::enable_if<std::is_function<T>::value, T&>::type get(const smart_library& sm, const std::string &name) 0444 { 0445 return sm.get_function<T>(name); 0446 } 0447 0448 template<class Class, class Signature> 0449 auto get(const smart_library& sm, const std::string &name) -> typename detail::get_mem_fn_type<Class, Signature>::mem_fn 0450 { 0451 return sm.get_mem_fn<Class, Signature>(name); 0452 } 0453 0454 0455 } /* namespace experimental */ 0456 } /* namespace dll */ 0457 } /* namespace boost */ 0458 0459 #endif /* BOOST_DLL_SMART_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 |
![]() ![]() |