Back to home page

EIC code displayed by LXR

 
 

    


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_ */