You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

435 lines
14 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: unixstl/dl/module.hpp (originally MXModule.h, ::SynesisUnix)
  3. *
  4. * Purpose: Contains the module class.
  5. *
  6. * Created: 30th October 1997
  7. * Updated: 12th August 2010
  8. *
  9. * Home: http://stlsoft.org/
  10. *
  11. * Copyright (c) 1997-2010, Matthew Wilson and Synesis Software
  12. * All rights reserved.
  13. *
  14. * Redistribution and use in source and binary forms, with or without
  15. * modification, are permitted provided that the following conditions are met:
  16. *
  17. * - Redistributions of source code must retain the above copyright notice, this
  18. * list of conditions and the following disclaimer.
  19. * - Redistributions in binary form must reproduce the above copyright notice,
  20. * this list of conditions and the following disclaimer in the documentation
  21. * and/or other materials provided with the distribution.
  22. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of
  23. * any contributors may be used to endorse or promote products derived from
  24. * this software without specific prior written permission.
  25. *
  26. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  27. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  30. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  31. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  32. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  33. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  34. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  35. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  36. * POSSIBILITY OF SUCH DAMAGE.
  37. *
  38. * ////////////////////////////////////////////////////////////////////// */
  39. /** \file unixstl/dl/module.hpp
  40. *
  41. * \brief [C++ only] Definition of the unixstl::module class
  42. * (\ref group__library__dl "DL" Library).
  43. */
  44. #ifndef UNIXSTL_INCL_UNIXSTL_DL_HPP_MODULE
  45. #define UNIXSTL_INCL_UNIXSTL_DL_HPP_MODULE
  46. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  47. # define UNIXSTL_VER_UNIXSTL_DL_HPP_MODULE_MAJOR 6
  48. # define UNIXSTL_VER_UNIXSTL_DL_HPP_MODULE_MINOR 3
  49. # define UNIXSTL_VER_UNIXSTL_DL_HPP_MODULE_REVISION 1
  50. # define UNIXSTL_VER_UNIXSTL_DL_HPP_MODULE_EDIT 220
  51. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  52. /* /////////////////////////////////////////////////////////////////////////
  53. * Compatibility
  54. */
  55. /*
  56. */
  57. /* /////////////////////////////////////////////////////////////////////////
  58. * Includes
  59. */
  60. #ifndef UNIXSTL_INCL_UNIXSTL_H_UNIXSTL
  61. # include <unixstl/unixstl.h>
  62. #endif /* !UNIXSTL_INCL_UNIXSTL_H_UNIXSTL */
  63. #ifndef UNIXSTL_INCL_UNIXSTL_HPP_ERROR_UNIX_EXCEPTIONS
  64. # include <unixstl/error/exceptions.hpp>
  65. #endif /* !UNIXSTL_INCL_UNIXSTL_ERROR_HPP_UNIX_EXCEPTIONS */
  66. #ifndef STLSOFT_INCL_STLSOFT_SHIMS_ACCESS_HPP_STRING
  67. # include <stlsoft/shims/access/string.hpp>
  68. #endif /* !STLSOFT_INCL_STLSOFT_SHIMS_ACCESS_HPP_STRING */
  69. #ifndef UNIXSTL_INCL_UNIXSTL_SHIMS_ACCESS_HPP_STRING
  70. # include <unixstl/shims/access/string.hpp>
  71. #endif /* !UNIXSTL_INCL_UNIXSTL_SHIMS_ACCESS_HPP_STRING */
  72. #ifndef STLSOFT_INCL_H_DLFCN
  73. # define STLSOFT_INCL_H_DLFCN
  74. # include <dlfcn.h>
  75. #endif /* !STLSOFT_INCL_H_DLFCN */
  76. #ifndef STLSOFT_INCL_H_ERRNO
  77. # define STLSOFT_INCL_H_ERRNO
  78. # include <errno.h>
  79. #endif /* !STLSOFT_INCL_H_ERRNO */
  80. /* /////////////////////////////////////////////////////////////////////////
  81. * Namespace
  82. */
  83. #ifndef _UNIXSTL_NO_NAMESPACE
  84. # if defined(_STLSOFT_NO_NAMESPACE) || \
  85. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  86. /* There is no stlsoft namespace, so must define ::unixstl */
  87. namespace unixstl
  88. {
  89. # else
  90. /* Define stlsoft::unixstl_project */
  91. namespace stlsoft
  92. {
  93. namespace unixstl_project
  94. {
  95. # endif /* _STLSOFT_NO_NAMESPACE */
  96. #endif /* !_UNIXSTL_NO_NAMESPACE */
  97. /* /////////////////////////////////////////////////////////////////////////
  98. * Classes
  99. */
  100. /** \brief Class for manipulating dynamically loaded libraries
  101. *
  102. * \ingroup group__library__dl
  103. */
  104. class module
  105. {
  106. public:
  107. /// \brief The handle type
  108. typedef void* module_handle_type;
  109. /// \brief The handle type
  110. ///
  111. /// \note This member type is required to make it compatible with
  112. /// the STLSoft get_module_handle access shim
  113. typedef void* handle_type;
  114. /// \brief The class type
  115. typedef module class_type;
  116. /// \brief The entry point type
  117. typedef void* proc_pointer_type;
  118. public:
  119. typedef handle_type resource_type;
  120. /// \name Construction
  121. /// @{
  122. public:
  123. /// \brief Constructs by loading the named module
  124. ///
  125. /// \param moduleName The file name of the executable module to be loaded.
  126. /// \param mode The loading mode (as used by <code>::dlopen()</code>).
  127. ///
  128. /// \note If exception-handling is being used, then this throws a
  129. /// \link unixstl::unix_exception unix_exception\endlink
  130. /// if the module cannot be loaded
  131. ss_explicit_k module(us_char_a_t const* moduleName, int mode = RTLD_NOW);
  132. /// \brief Constructs by loading the named module
  133. ///
  134. /// \param moduleName The file name of the executable module to be loaded.
  135. /// \param mode The loading mode (as used by <code>::dlopen()</code>).
  136. ///
  137. /// \note If exception-handling is being used, then this throws a
  138. /// \link unixstl::unix_exception unix_exception\endlink
  139. /// if the module cannot be loaded
  140. ss_explicit_k module(us_char_w_t const* moduleName, int mode = RTLD_NOW);
  141. #if defined(STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT)
  142. /// \brief Constructs by loading the named module
  143. ///
  144. /// \param moduleName The file name of the executable module to be
  145. /// loaded. The argument may be of any type for which the
  146. /// \ref group__concept__shim__string_access "string access shim"
  147. /// stlsoft::c_str_ptr is defined.
  148. /// \param mode The loading mode (as used by <code>::dlopen()</code>).
  149. ///
  150. /// \note If exception-handling is being used, then this throws a
  151. /// \link unixstl::unix_exception unix_exception\endlink
  152. /// if the module cannot be loaded
  153. template <ss_typename_param_k S>
  154. ss_explicit_k module(S const& moduleName, int mode = RTLD_NOW)
  155. : m_hmodule(load(moduleName, mode))
  156. {
  157. # ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  158. if(NULL == m_hmodule)
  159. {
  160. STLSOFT_THROW_X(unix_exception("Cannot load module", errno));
  161. }
  162. # endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  163. }
  164. #endif /* STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT */
  165. /// \brief Constructs by taking ownership of the given handle
  166. ///
  167. /// \note If exception-handling is being used, then this throws a
  168. /// \link unixstl::unix_exception unix_exception\endlink
  169. /// if the handle is NULL.
  170. ss_explicit_k module(module_handle_type hmodule);
  171. /// \brief Closes the module handle
  172. ~module() stlsoft_throw_0();
  173. /// @}
  174. /// \name Static operations
  175. /// @{
  176. public:
  177. /// \brief Loads the named module, returning its handle, which the
  178. /// caller must close with unload().
  179. ///
  180. /// \param moduleName The file name of the executable module to be loaded.
  181. /// \param mode The loading mode (as used by <code>::dlopen()</code>).
  182. ///
  183. /// \return The module handle, or NULL if no matching module found.
  184. static module_handle_type load(us_char_a_t const* moduleName, int mode = RTLD_NOW);
  185. /// \brief Loads the named module, returning its handle, which the
  186. /// caller must close with unload().
  187. ///
  188. /// \param moduleName The file name of the executable module to be loaded.
  189. /// \param mode The loading mode (as used by <code>::dlopen()</code>).
  190. ///
  191. /// \return The module handle, or NULL if no matching module found.
  192. static module_handle_type load(us_char_w_t const* moduleName, int mode = RTLD_NOW);
  193. #if defined(STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT)
  194. /// \brief Loads the named module, returning its handle, which the
  195. /// caller must close with unload().
  196. ///
  197. /// \param moduleName The file name of the executable module to be
  198. /// loaded. The argument may be of any type for which the
  199. /// \ref group__concept__shim__string_access "string access shim"
  200. /// stlsoft::c_str_ptr is defined.
  201. /// \param mode The loading mode (as used by <code>::dlopen()</code>).
  202. ///
  203. /// \return The module handle, or NULL if no matching module found.
  204. template <ss_typename_param_k S>
  205. static module_handle_type load(S const& moduleName, int mode = RTLD_NOW)
  206. {
  207. return class_type::load(stlsoft_ns_qual(c_str_ptr)(moduleName), mode);
  208. }
  209. #endif /* STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT */
  210. /// \brief Closes the given module handle
  211. static void unload(module_handle_type hmodule) stlsoft_throw_0();
  212. /// \brief Looks up the named symbol from the given module
  213. ///
  214. /// \return A pointer to the named symbol, or NULL if not found
  215. static proc_pointer_type get_symbol(module_handle_type hmodule, us_char_a_t const* symbolName);
  216. #if defined(STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT)
  217. /// \brief Looks up a named symbol from the given module into a typed function pointer variable.
  218. ///
  219. /// \return A pointer to the named symbol, or NULL if not found.
  220. template <ss_typename_param_k F>
  221. static proc_pointer_type get_symbol(module_handle_type hmodule, us_char_a_t const* symbolName, F &f)
  222. {
  223. proc_pointer_type proc = class_type::get_symbol(hmodule, symbolName);
  224. f = reinterpret_cast<F>(proc);
  225. return proc;
  226. }
  227. #endif /* STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT */
  228. /// @}
  229. /// \name Operations
  230. /// @{
  231. public:
  232. /// \brief Closes the module handle
  233. void unload() stlsoft_throw_0();
  234. /// \brief Yields the module handle to the caller
  235. module_handle_type detach();
  236. /// @}
  237. /// \name Lookup Operations
  238. /// @{
  239. public:
  240. /// \brief Looks up the named symbol.
  241. ///
  242. /// \return A pointer to the named symbol, or NULL if not found
  243. proc_pointer_type get_symbol(us_char_a_t const* symbolName);
  244. #if defined(STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT)
  245. /// \brief Looks up a named symbol into a typed function pointer variable.
  246. ///
  247. /// \return A pointer to the named symbol, or NULL if not found.
  248. template <ss_typename_param_k F>
  249. proc_pointer_type get_symbol(us_char_a_t const* symbolName, F &f)
  250. {
  251. return class_type::get_symbol(m_hmodule, symbolName, f);
  252. }
  253. #endif /* STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT */
  254. /// @}
  255. /// \name Accessors
  256. /// @{
  257. public:
  258. /// \brief Provides access to the underlying module handle
  259. module_handle_type get_module_handle() const;
  260. /// @}
  261. /// \name Implementation
  262. /// @{
  263. private:
  264. /// @}
  265. /// \name Member Variables
  266. /// @{
  267. private:
  268. module_handle_type m_hmodule;
  269. /// @}
  270. /// \name Not to be implemented
  271. /// @{
  272. private:
  273. module(class_type const&);
  274. class_type& operator =(class_type const&);
  275. /// @}
  276. };
  277. /* /////////////////////////////////////////////////////////////////////////
  278. * Access shims
  279. */
  280. /** \brief Returns the module handle for the given module
  281. *
  282. * \ingroup group__concept__shim__module_attribute
  283. */
  284. inline void *get_module_handle(unixstl_ns_qual(module) const& m)
  285. {
  286. return m.get_module_handle();
  287. }
  288. /* /////////////////////////////////////////////////////////////////////////
  289. * Unit-testing
  290. */
  291. #ifdef STLSOFT_UNITTEST
  292. # include "./unittest/module_unittest_.h"
  293. #endif /* STLSOFT_UNITTEST */
  294. /* /////////////////////////////////////////////////////////////////////////
  295. * Implementation
  296. */
  297. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  298. inline module::module(us_char_a_t const* moduleName, int mode)
  299. : m_hmodule(load(moduleName, mode))
  300. {
  301. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  302. if(NULL == m_hmodule)
  303. {
  304. STLSOFT_THROW_X(unix_exception("Cannot load module", errno));
  305. }
  306. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  307. }
  308. inline module::module(us_char_w_t const* moduleName, int mode)
  309. : m_hmodule(load(moduleName, mode))
  310. {
  311. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  312. if(NULL == m_hmodule)
  313. {
  314. STLSOFT_THROW_X(unix_exception("Cannot load module", errno));
  315. }
  316. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  317. }
  318. inline module::module(module::module_handle_type hmodule)
  319. : m_hmodule(hmodule)
  320. {
  321. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  322. if(NULL == m_hmodule)
  323. {
  324. STLSOFT_THROW_X(unix_exception("Cannot load module", errno));
  325. }
  326. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  327. }
  328. inline module::~module() stlsoft_throw_0()
  329. {
  330. unload(m_hmodule);
  331. }
  332. inline void module::unload() stlsoft_throw_0()
  333. {
  334. if(NULL != m_hmodule)
  335. {
  336. unload(m_hmodule);
  337. m_hmodule = NULL;
  338. }
  339. }
  340. inline module::module_handle_type module::detach()
  341. {
  342. module_handle_type h;
  343. h = m_hmodule;
  344. m_hmodule = NULL;
  345. return h;
  346. }
  347. inline /* static */ module::module_handle_type module::load(us_char_a_t const* moduleName, int mode)
  348. {
  349. return ::dlopen(moduleName, mode);
  350. }
  351. inline /* static */ void module::unload(module::module_handle_type hmodule) stlsoft_throw_0()
  352. {
  353. if(NULL != hmodule)
  354. {
  355. ::dlclose(hmodule);
  356. }
  357. }
  358. inline /* static */ module::proc_pointer_type module::get_symbol(module::module_handle_type hmodule, us_char_a_t const* symbolName)
  359. {
  360. return ::dlsym(hmodule, symbolName);
  361. }
  362. inline module::proc_pointer_type module::get_symbol(us_char_a_t const* symbolName)
  363. {
  364. return get_symbol(m_hmodule, symbolName);
  365. }
  366. inline module::module_handle_type module::get_module_handle() const
  367. {
  368. return m_hmodule;
  369. }
  370. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  371. /* ////////////////////////////////////////////////////////////////////// */
  372. #ifndef _UNIXSTL_NO_NAMESPACE
  373. # if defined(_STLSOFT_NO_NAMESPACE) || \
  374. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  375. } // namespace unixstl
  376. # else
  377. } // namespace unixstl_project
  378. } // namespace stlsoft
  379. # endif /* _STLSOFT_NO_NAMESPACE */
  380. #endif /* !_UNIXSTL_NO_NAMESPACE */
  381. /* ////////////////////////////////////////////////////////////////////// */
  382. #endif /* UNIXSTL_INCL_UNIXSTL_DL_HPP_MODULE */
  383. /* ///////////////////////////// end of file //////////////////////////// */