]>
Commit | Line | Data |
---|---|---|
1 | // Copyright 2016 Klemens Morgenstern | |
2 | // | |
3 | // Distributed under the Boost Software License, Version 1.0. | |
4 | // (See accompanying file LICENSE_1_0.txt | |
5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | ||
7 | #ifndef BOOST_DLL_SMART_LIBRARY_HPP_ | |
8 | #define BOOST_DLL_SMART_LIBRARY_HPP_ | |
9 | ||
10 | /// \file boost/dll/smart_library.hpp | |
11 | /// \warning Extremely experimental! Requires C++14! Will change in next version of Boost! boost/dll/smart_library.hpp is not included in boost/dll.hpp | |
12 | /// \brief Contains the boost::dll::experimental::smart_library class for loading mangled symbols. | |
13 | ||
14 | #if BOOST_COMP_GNUC || BOOST_COMP_CLANG || BOOST_COMP_HPACC || BOOST_COMP_IBM | |
15 | #include <boost/dll/detail/demangling/itanium.hpp> | |
16 | #elif BOOST_COMP_MSVC | |
17 | #include <boost/dll/detail/demangling/msvc.hpp> | |
18 | #else | |
19 | #error "Compiler not supported" | |
20 | #endif | |
21 | ||
22 | #include <boost/dll/shared_library.hpp> | |
23 | #include <boost/dll/detail/get_mem_fn_type.hpp> | |
24 | #include <boost/dll/detail/ctor_dtor.hpp> | |
25 | #include <boost/dll/detail/type_info.hpp> | |
26 | #include <boost/type_traits/is_object.hpp> | |
27 | #include <boost/type_traits/is_void.hpp> | |
28 | #include <boost/type_traits/is_function.hpp> | |
29 | #include <boost/predef/compiler.h> | |
30 | ||
31 | ||
32 | ||
33 | namespace boost { | |
34 | namespace dll { | |
35 | namespace experimental { | |
36 | ||
37 | using boost::dll::detail::constructor; | |
38 | using boost::dll::detail::destructor; | |
39 | ||
40 | /*! | |
41 | * \brief This class is an extension of \ref shared_library, which allows to load C++ symbols. | |
42 | * | |
43 | * This class allows type safe loading of overloaded functions, member-functions, constructors and variables. | |
44 | * It also allows to overwrite classes so they can be loaded, while being declared with different names. | |
45 | * | |
46 | * \warning Is still very experimental. | |
47 | * | |
48 | * Currently known limitations: | |
49 | * | |
50 | * Member functions must be defined outside of the class to be exported. That is: | |
51 | * \code | |
52 | * //not exported: | |
53 | * struct BOOST_SYMBOL_EXPORT my_class { void func() {}}; | |
54 | * //exported | |
55 | * struct BOOST_SYMBOL_EXPORT my_class { void func();}; | |
56 | * void my_class::func() {}; | |
57 | * \endcode | |
58 | * | |
59 | * With the current analysis, the first version does get exported in MSVC. | |
60 | * MinGW also does export it, BOOST_SYMBOL_EXPORT is written before it. To allow this on windows one can use | |
61 | * BOOST_DLL_MEMBER_EXPORT for this, so that MinGW and MSVC can provide those functions. This does however not work with gcc on linux. | |
62 | * | |
63 | * Direct initialization of members. | |
64 | * On linux the following member variable i will not be initialized when using the allocating contructor: | |
65 | * \code | |
66 | * struct BOOST_SYMBOL_EXPORT my_class { int i; my_class() : i(42) {} }; | |
67 | * \endcode | |
68 | * | |
69 | * This does however not happen when the value is set inside the constructor function. | |
70 | */ | |
71 | class smart_library { | |
72 | shared_library _lib; | |
73 | detail::mangled_storage_impl _storage; | |
74 | ||
75 | public: | |
76 | /*! | |
77 | * Get the underlying shared_library | |
78 | */ | |
79 | const shared_library &shared_lib() const {return _lib;} | |
80 | ||
81 | using mangled_storage = detail::mangled_storage_impl; | |
82 | /*! | |
83 | * Acces to the mangled storage, which is created on construction. | |
84 | * | |
85 | * \throw Nothing. | |
86 | */ | |
87 | const mangled_storage &symbol_storage() const {return _storage;} | |
88 | ||
89 | ///Overload, for current development. | |
90 | mangled_storage &symbol_storage() {return _storage;} | |
91 | ||
92 | //! \copydoc shared_library::shared_library() | |
93 | smart_library() BOOST_NOEXCEPT {}; | |
94 | ||
95 | //! \copydoc shared_library::shared_library(const boost::filesystem::path& lib_path, load_mode::type mode = load_mode::default_mode) | |
96 | smart_library(const boost::filesystem::path& lib_path, load_mode::type mode = load_mode::default_mode) { | |
97 | _lib.load(lib_path, mode); | |
98 | _storage.load(lib_path, mode); | |
99 | } | |
100 | ||
101 | //! \copydoc shared_library::shared_library(const boost::filesystem::path& lib_path, boost::system::error_code& ec, load_mode::type mode = load_mode::default_mode) | |
102 | smart_library(const boost::filesystem::path& lib_path, boost::system::error_code& ec, load_mode::type mode = load_mode::default_mode) { | |
103 | load(lib_path, mode, ec); | |
104 | } | |
105 | ||
106 | //! \copydoc shared_library::shared_library(const boost::filesystem::path& lib_path, load_mode::type mode, boost::system::error_code& ec) | |
107 | smart_library(const boost::filesystem::path& lib_path, load_mode::type mode, boost::system::error_code& ec) { | |
108 | load(lib_path, mode, ec); | |
109 | } | |
110 | /*! | |
111 | * copy a smart_library object. | |
112 | * | |
113 | * \param lib A smart_library to move from. | |
114 | * | |
115 | * \throw Nothing. | |
116 | */ | |
117 | smart_library(const smart_library & lib) BOOST_NOEXCEPT | |
118 | : _lib(lib._lib), _storage(lib._storage) | |
119 | {} | |
120 | /*! | |
121 | * Move a smart_library object. | |
122 | * | |
123 | * \param lib A smart_library to move from. | |
124 | * | |
125 | * \throw Nothing. | |
126 | */ | |
127 | smart_library(BOOST_RV_REF(smart_library) lib) BOOST_NOEXCEPT | |
128 | : _lib(boost::move(lib._lib)), _storage(boost::move(lib._storage)) | |
129 | {} | |
130 | ||
131 | /*! | |
132 | * Construct from a shared_library object. | |
133 | * | |
134 | * \param lib A shared_library to move from. | |
135 | * | |
136 | * \throw Nothing. | |
137 | */ | |
138 | explicit smart_library(const shared_library & lib) BOOST_NOEXCEPT | |
139 | : _lib(lib) | |
140 | { | |
141 | _storage.load(lib.location()); | |
142 | } | |
143 | /*! | |
144 | * Construct from a shared_library object. | |
145 | * | |
146 | * \param lib A shared_library to move from. | |
147 | * | |
148 | * \throw Nothing. | |
149 | */ | |
150 | explicit smart_library(BOOST_RV_REF(shared_library) lib) BOOST_NOEXCEPT | |
151 | : _lib(boost::move(static_cast<shared_library&>(lib))) | |
152 | { | |
153 | _storage.load(lib.location()); | |
154 | } | |
155 | ||
156 | /*! | |
157 | * Destroys the smart_library. | |
158 | * `unload()` is called if the DLL/DSO was loaded. If library was loaded multiple times | |
159 | * by different instances of shared_library, the actual DLL/DSO won't be unloaded until | |
160 | * there is at least one instance of shared_library. | |
161 | * | |
162 | * \throw Nothing. | |
163 | */ | |
164 | ~smart_library() BOOST_NOEXCEPT {}; | |
165 | ||
166 | //! \copydoc shared_library::load(const boost::filesystem::path& lib_path, load_mode::type mode = load_mode::default_mode) | |
167 | void load(const boost::filesystem::path& lib_path, load_mode::type mode = load_mode::default_mode) { | |
168 | boost::system::error_code ec; | |
169 | _storage.load(lib_path); | |
170 | _lib.load(lib_path, mode, ec); | |
171 | ||
172 | if (ec) { | |
173 | boost::dll::detail::report_error(ec, "load() failed"); | |
174 | } | |
175 | } | |
176 | ||
177 | //! \copydoc shared_library::load(const boost::filesystem::path& lib_path, boost::system::error_code& ec, load_mode::type mode = load_mode::default_mode) | |
178 | void load(const boost::filesystem::path& lib_path, boost::system::error_code& ec, load_mode::type mode = load_mode::default_mode) { | |
179 | ec.clear(); | |
180 | _storage.load(lib_path); | |
181 | _lib.load(lib_path, mode, ec); | |
182 | } | |
183 | ||
184 | //! \copydoc shared_library::load(const boost::filesystem::path& lib_path, load_mode::type mode, boost::system::error_code& ec) | |
185 | void load(const boost::filesystem::path& lib_path, load_mode::type mode, boost::system::error_code& ec) { | |
186 | ec.clear(); | |
187 | _storage.load(lib_path); | |
188 | _lib.load(lib_path, mode, ec); | |
189 | } | |
190 | ||
191 | /*! | |
192 | * Load a variable from the referenced library. | |
193 | * | |
194 | * Unlinke shared_library::get this function will also load scoped variables, which also includes static class members. | |
195 | * | |
196 | * \note When mangled, MSVC will also check the type. | |
197 | * | |
198 | * \param name Name of the variable | |
199 | * \tparam T Type of the variable | |
200 | * \return A reference to the variable of type T. | |
201 | * | |
202 | * \throw boost::system::system_error if symbol does not exist or if the DLL/DSO was not loaded. | |
203 | */ | |
204 | template<typename T> | |
205 | T& get_variable(const std::string &name) const { | |
206 | return _lib.get<T>(_storage.get_variable<T>(name)); | |
207 | } | |
208 | ||
209 | /*! | |
210 | * Load a function from the referenced library. | |
211 | * | |
212 | * \b Example: | |
213 | * | |
214 | * \code | |
215 | * smart_library lib("test_lib.so"); | |
216 | * typedef int (&add_ints)(int, int); | |
217 | * typedef double (&add_doubles)(double, double); | |
218 | * add_ints f1 = lib.get_function<int(int, int)> ("func_name"); | |
219 | * add_doubles f2 = lib.get_function<double(double, double)>("func_name"); | |
220 | * \endcode | |
221 | * | |
222 | * \note When mangled, MSVC will also check the return type. | |
223 | * | |
224 | * \param name Name of the function. | |
225 | * \tparam Func Type of the function, required for determining the overload | |
226 | * \return A reference to the function of type F. | |
227 | * | |
228 | * \throw boost::system::system_error if symbol does not exist or if the DLL/DSO was not loaded. | |
229 | */ | |
230 | template<typename Func> | |
231 | Func& get_function(const std::string &name) const { | |
232 | return _lib.get<Func>(_storage.get_function<Func>(name)); | |
233 | } | |
234 | ||
235 | /*! | |
236 | * Load a member-function from the referenced library. | |
237 | * | |
238 | * \b Example (import class is MyClass, which is available inside the library and the host): | |
239 | * | |
240 | * \code | |
241 | * smart_library lib("test_lib.so"); | |
242 | * | |
243 | * typedef int MyClass(*func)(int); | |
244 | * typedef int MyClass(*func_const)(int) const; | |
245 | * | |
246 | * add_ints f1 = lib.get_mem_fn<MyClass, int(int)> ("MyClass::function"); | |
247 | * add_doubles f2 = lib.get_mem_fn<const MyClass, double(double)>("MyClass::function"); | |
248 | * \endcode | |
249 | * | |
250 | * \note When mangled, MSVC will also check the return type. | |
251 | * | |
252 | * \param name Name of the function. | |
253 | * \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. | |
254 | * \tparam Func Signature of the function, required for determining the overload | |
255 | * \return A pointer to the member-function with the signature provided | |
256 | * | |
257 | * \throw boost::system::system_error if symbol does not exist or if the DLL/DSO was not loaded. | |
258 | */ | |
259 | template<typename Class, typename Func> | |
260 | typename boost::dll::detail::get_mem_fn_type<Class, Func>::mem_fn get_mem_fn(const std::string& name) const { | |
261 | return _lib.get<typename boost::dll::detail::get_mem_fn_type<Class, Func>::mem_fn>( | |
262 | _storage.get_mem_fn<Class, Func>(name) | |
263 | ); | |
264 | } | |
265 | ||
266 | /*! | |
267 | * Load a constructor from the referenced library. | |
268 | * | |
269 | * \b Example (import class is MyClass, which is available inside the library and the host): | |
270 | * | |
271 | * \code | |
272 | * smart_library lib("test_lib.so"); | |
273 | * | |
274 | * constructor<MyClass(int) f1 = lib.get_mem_fn<MyClass(int)>(); | |
275 | * \endcode | |
276 | * | |
277 | * \tparam Signature Signature of the function, required for determining the overload. The return type is the class which this is the constructor of. | |
278 | * \return A constructor object. | |
279 | * | |
280 | * \throw boost::system::system_error if symbol does not exist or if the DLL/DSO was not loaded. | |
281 | */ | |
282 | template<typename Signature> | |
283 | constructor<Signature> get_constructor() const { | |
284 | return boost::dll::detail::load_ctor<Signature>(_lib, _storage.get_constructor<Signature>()); | |
285 | } | |
286 | ||
287 | /*! | |
288 | * Load a destructor from the referenced library. | |
289 | * | |
290 | * \b Example (import class is MyClass, which is available inside the library and the host): | |
291 | * | |
292 | * \code | |
293 | * smart_library lib("test_lib.so"); | |
294 | * | |
295 | * destructor<MyClass> f1 = lib.get_mem_fn<MyClass>(); | |
296 | * \endcode | |
297 | * | |
298 | * \tparam Class The class whichs destructor shall be loaded | |
299 | * \return A destructor object. | |
300 | * | |
301 | * \throw boost::system::system_error if symbol does not exist or if the DLL/DSO was not loaded. | |
302 | * | |
303 | */ | |
304 | template<typename Class> | |
305 | destructor<Class> get_destructor() const { | |
306 | return boost::dll::detail::load_dtor<Class>(_lib, _storage.get_destructor<Class>()); | |
307 | } | |
308 | /*! | |
309 | * Load the typeinfo of the given type. | |
310 | * | |
311 | * \b Example (import class is MyClass, which is available inside the library and the host): | |
312 | * | |
313 | * \code | |
314 | * smart_library lib("test_lib.so"); | |
315 | * | |
316 | * std::type_info &ti = lib.get_Type_info<MyClass>(); | |
317 | * \endcode | |
318 | * | |
319 | * \tparam Class The class whichs typeinfo shall be loaded | |
320 | * \return A reference to a type_info object. | |
321 | * | |
322 | * \throw boost::system::system_error if symbol does not exist or if the DLL/DSO was not loaded. | |
323 | * | |
324 | */ | |
325 | template<typename Class> | |
326 | const std::type_info& get_type_info() const | |
327 | { | |
328 | return boost::dll::detail::load_type_info<Class>(_lib, _storage); | |
329 | } | |
330 | /** | |
331 | * This function can be used to add a type alias. | |
332 | * | |
333 | * This is to be used, when a class shall be imported, which is not declared on the host side. | |
334 | * | |
335 | * Example: | |
336 | * \code | |
337 | * smart_library lib("test_lib.so"); | |
338 | * | |
339 | * lib.add_type_alias<MyAlias>("MyClass"); //when using MyAlias, the library will look for MyClass | |
340 | * | |
341 | * //get the destructor of MyClass | |
342 | * destructor<MyAlias> dtor = lib.get_destructor<MyAlias>(); | |
343 | * \endcode | |
344 | * | |
345 | * | |
346 | * \param name Name of the class the alias is for. | |
347 | * | |
348 | * \attention If the alias-type is not large enough for the imported class, it will result in undefined behaviour. | |
349 | * \warning The alias will only be applied for the type signature, it will not replace the token in the scoped name. | |
350 | */ | |
351 | template<typename Alias> void add_type_alias(const std::string& name) { | |
352 | this->_storage.add_alias<Alias>(name); | |
353 | } | |
354 | ||
355 | //! \copydoc shared_library::unload() | |
356 | void unload() BOOST_NOEXCEPT { | |
357 | _storage.clear(); | |
358 | _lib.unload(); | |
359 | } | |
360 | ||
361 | //! \copydoc shared_library::is_loaded() const | |
362 | bool is_loaded() const BOOST_NOEXCEPT { | |
363 | return _lib.is_loaded(); | |
364 | } | |
365 | ||
366 | //! \copydoc shared_library::operator!() const | |
367 | bool operator!() const BOOST_NOEXCEPT { | |
368 | return !is_loaded(); | |
369 | } | |
370 | ||
371 | //! \copydoc shared_library::operator bool() const | |
372 | BOOST_EXPLICIT_OPERATOR_BOOL() | |
373 | ||
374 | //! \copydoc shared_library::has(const char* symbol_name) const | |
375 | bool has(const char* symbol_name) const BOOST_NOEXCEPT { | |
376 | return _lib.has(symbol_name); | |
377 | } | |
378 | ||
379 | //! \copydoc shared_library::has(const std::string& symbol_name) const | |
380 | bool has(const std::string& symbol_name) const BOOST_NOEXCEPT { | |
381 | return _lib.has(symbol_name); | |
382 | } | |
383 | ||
384 | //! \copydoc shared_library::assign(const shared_library& lib) | |
385 | smart_library& assign(const smart_library& lib) { | |
386 | _lib.assign(lib._lib); | |
387 | _storage.assign(lib._storage); | |
388 | return *this; | |
389 | } | |
390 | ||
391 | //! \copydoc shared_library::swap(shared_library& rhs) | |
392 | void swap(smart_library& rhs) BOOST_NOEXCEPT { | |
393 | _lib.swap(rhs._lib); | |
394 | _storage.swap(rhs._storage); | |
395 | } | |
396 | }; | |
397 | ||
398 | /// Very fast equality check that compares the actual DLL/DSO objects. Throws nothing. | |
399 | inline bool operator==(const smart_library& lhs, const smart_library& rhs) BOOST_NOEXCEPT { | |
400 | return lhs.shared_lib().native() == rhs.shared_lib().native(); | |
401 | } | |
402 | ||
403 | /// Very fast inequality check that compares the actual DLL/DSO objects. Throws nothing. | |
404 | inline bool operator!=(const smart_library& lhs, const smart_library& rhs) BOOST_NOEXCEPT { | |
405 | return lhs.shared_lib().native() != rhs.shared_lib().native(); | |
406 | } | |
407 | ||
408 | /// Compare the actual DLL/DSO objects without any guarantee to be stable between runs. Throws nothing. | |
409 | inline bool operator<(const smart_library& lhs, const smart_library& rhs) BOOST_NOEXCEPT { | |
410 | return lhs.shared_lib().native() < rhs.shared_lib().native(); | |
411 | } | |
412 | ||
413 | /// Swaps two shared libraries. Does not invalidate symbols and functions loaded from libraries. Throws nothing. | |
414 | inline void swap(smart_library& lhs, smart_library& rhs) BOOST_NOEXCEPT { | |
415 | lhs.swap(rhs); | |
416 | } | |
417 | ||
418 | ||
419 | #ifdef BOOST_DLL_DOXYGEN | |
420 | /** Helper functions for overloads. | |
421 | * | |
422 | * Gets either a variable, function or member-function, depending on the signature. | |
423 | * | |
424 | * @code | |
425 | * smart_library sm("lib.so"); | |
426 | * get<int>(sm, "space::value"); //import a variable | |
427 | * get<void(int)>(sm, "space::func"); //import a function | |
428 | * get<some_class, void(int)>(sm, "space::class_::mem_fn"); //import a member function | |
429 | * @endcode | |
430 | * | |
431 | * @param sm A reference to the @ref smart_library | |
432 | * @param name The name of the entity to import | |
433 | */ | |
434 | template<class T, class T2> | |
435 | void get(const smart_library& sm, const std::string &name); | |
436 | #endif | |
437 | ||
438 | template<class T> | |
439 | T& get(const smart_library& sm, const std::string &name, typename boost::enable_if<boost::is_object<T>,T>::type* = nullptr) | |
440 | ||
441 | { | |
442 | return sm.get_variable<T>(name); | |
443 | } | |
444 | ||
445 | template<class T> | |
446 | auto get(const smart_library& sm, const std::string &name, typename boost::enable_if<boost::is_function<T>>::type* = nullptr) | |
447 | { | |
448 | return sm.get_function<T>(name); | |
449 | } | |
450 | ||
451 | template<class Class, class Signature> | |
452 | auto get(const smart_library& sm, const std::string &name) -> typename detail::get_mem_fn_type<Class, Signature>::mem_fn | |
453 | { | |
454 | return sm.get_mem_fn<Class, Signature>(name); | |
455 | } | |
456 | ||
457 | ||
458 | } /* namespace experimental */ | |
459 | } /* namespace dll */ | |
460 | } /* namespace boost */ | |
461 | ||
462 | #endif /* BOOST_DLL_SMART_LIBRARY_HPP_ */ |