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