dynl.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. /* dynl.c - dynamic linking
  2. *
  3. * Copyright (C) 1990, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000, 2001, 2002,
  4. * 2003, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public License
  8. * as published by the Free Software Foundation; either version 3 of
  9. * the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19. * 02110-1301 USA
  20. */
  21. #ifdef HAVE_CONFIG_H
  22. # include <config.h>
  23. #endif
  24. #include <alloca.h>
  25. #include <string.h>
  26. /* "dynl.c" dynamically link&load object files.
  27. Author: Aubrey Jaffer
  28. Modified for libguile by Marius Vollmer */
  29. #if 0 /* Disabled until we know for sure that it isn't needed */
  30. /* XXX - This is only here to drag in a definition of __eprintf. This
  31. is needed for proper operation of dynamic linking. The real
  32. solution would probably be a shared libgcc. */
  33. #undef NDEBUG
  34. #include <assert.h>
  35. static void
  36. maybe_drag_in_eprintf ()
  37. {
  38. assert (!maybe_drag_in_eprintf);
  39. }
  40. #endif
  41. #include <stdlib.h>
  42. #include <stdio.h>
  43. #include <string.h>
  44. #include "libguile/_scm.h"
  45. #include "libguile/libpath.h"
  46. #include "libguile/dynl.h"
  47. #include "libguile/smob.h"
  48. #include "libguile/keywords.h"
  49. #include "libguile/ports.h"
  50. #include "libguile/strings.h"
  51. #include "libguile/deprecation.h"
  52. #include "libguile/validate.h"
  53. #include "libguile/dynwind.h"
  54. #include "libguile/foreign.h"
  55. #include "libguile/gc.h"
  56. #include <ltdl.h>
  57. /*
  58. From the libtool manual: "Note that libltdl is not threadsafe,
  59. i.e. a multithreaded application has to use a mutex for libltdl.".
  60. Guile does not currently support pre-emptive threads, so there is no
  61. mutex. Previously SCM_CRITICAL_SECTION_START and
  62. SCM_CRITICAL_SECTION_END were used: they are mentioned here in case
  63. somebody is grepping for thread problems ;)
  64. */
  65. /* njrev: not threadsafe, protection needed as described above */
  66. /* LT_PATH_SEP-separated extension library search path, searched last */
  67. static char *system_extensions_path;
  68. static void *
  69. sysdep_dynl_link (const char *fname, const char *subr)
  70. {
  71. lt_dlhandle handle;
  72. if (fname == NULL)
  73. /* Return a handle for the program as a whole. */
  74. handle = lt_dlopen (NULL);
  75. else
  76. {
  77. handle = lt_dlopenext (fname);
  78. if (handle == NULL
  79. #ifdef LT_DIRSEP_CHAR
  80. && strchr (fname, LT_DIRSEP_CHAR) == NULL
  81. #endif
  82. && strchr (fname, '/') == NULL)
  83. {
  84. /* FNAME contains no directory separators and was not in the
  85. usual library search paths, so now we search for it in
  86. SYSTEM_EXTENSIONS_PATH. */
  87. char *fname_attempt
  88. = scm_gc_malloc_pointerless (strlen (system_extensions_path)
  89. + strlen (fname) + 2,
  90. "dynl fname_attempt");
  91. char *path; /* remaining path to search */
  92. char *end; /* end of current path component */
  93. char *s;
  94. /* Iterate over the components of SYSTEM_EXTENSIONS_PATH */
  95. for (path = system_extensions_path;
  96. *path != '\0';
  97. path = (*end == '\0') ? end : (end + 1))
  98. {
  99. /* Find end of path component */
  100. end = strchr (path, LT_PATHSEP_CHAR);
  101. if (end == NULL)
  102. end = strchr (path, '\0');
  103. /* Skip empty path components */
  104. if (path == end)
  105. continue;
  106. /* Construct FNAME_ATTEMPT, starting with path component */
  107. s = fname_attempt;
  108. memcpy (s, path, end - path);
  109. s += end - path;
  110. /* Append directory separator, but avoid duplicates */
  111. if (s[-1] != '/'
  112. #ifdef LT_DIRSEP_CHAR
  113. && s[-1] != LT_DIRSEP_CHAR
  114. #endif
  115. )
  116. *s++ = '/';
  117. /* Finally, append FNAME (including null terminator) */
  118. strcpy (s, fname);
  119. /* Try to load it, and terminate the search if successful */
  120. handle = lt_dlopenext (fname_attempt);
  121. if (handle != NULL)
  122. break;
  123. }
  124. }
  125. }
  126. if (handle == NULL)
  127. {
  128. SCM fn;
  129. SCM msg;
  130. fn = fname != NULL ? scm_from_locale_string (fname) : SCM_BOOL_F;
  131. msg = scm_from_locale_string (lt_dlerror ());
  132. scm_misc_error (subr, "file: ~S, message: ~S", scm_list_2 (fn, msg));
  133. }
  134. return (void *) handle;
  135. }
  136. static void
  137. sysdep_dynl_unlink (void *handle, const char *subr)
  138. {
  139. if (lt_dlclose ((lt_dlhandle) handle))
  140. {
  141. scm_misc_error (subr, (char *) lt_dlerror (), SCM_EOL);
  142. }
  143. }
  144. static void *
  145. sysdep_dynl_value (const char *symb, void *handle, const char *subr)
  146. {
  147. void *fptr;
  148. fptr = lt_dlsym ((lt_dlhandle) handle, symb);
  149. if (!fptr)
  150. scm_misc_error (subr, "Symbol not found: ~a",
  151. scm_list_1 (scm_from_locale_string (symb)));
  152. return fptr;
  153. }
  154. static void
  155. sysdep_dynl_init ()
  156. {
  157. char *env;
  158. lt_dlinit ();
  159. /* Initialize 'system_extensions_path' from
  160. $GUILE_SYSTEM_EXTENSIONS_PATH, or if that's not set:
  161. <SCM_LIB_DIR> <LT_PATHSEP_CHAR> <SCM_EXTENSIONS_DIR>.
  162. 'lt_dladdsearchdir' can't be used because it is searched before
  163. the system-dependent search path, which is the one 'libtool
  164. --mode=execute -dlopen' fiddles with (info "(libtool) Libltdl
  165. Interface"). See
  166. <http://lists.gnu.org/archive/html/guile-devel/2010-11/msg00095.html>.
  167. The environment variables $LTDL_LIBRARY_PATH and $LD_LIBRARY_PATH
  168. can't be used because they would be propagated to subprocesses
  169. which may cause problems for other programs. See
  170. <http://lists.gnu.org/archive/html/guile-devel/2012-09/msg00037.html> */
  171. env = getenv ("GUILE_SYSTEM_EXTENSIONS_PATH");
  172. if (env)
  173. system_extensions_path = env;
  174. else
  175. {
  176. system_extensions_path
  177. = scm_gc_malloc_pointerless (strlen (SCM_LIB_DIR)
  178. + strlen (SCM_EXTENSIONS_DIR) + 2,
  179. "system_extensions_path");
  180. sprintf (system_extensions_path, "%s%c%s",
  181. SCM_LIB_DIR, LT_PATHSEP_CHAR, SCM_EXTENSIONS_DIR);
  182. }
  183. }
  184. scm_t_bits scm_tc16_dynamic_obj;
  185. #define DYNL_FILENAME SCM_SMOB_OBJECT
  186. #define DYNL_HANDLE(x) ((void *) SCM_SMOB_DATA_2 (x))
  187. #define SET_DYNL_HANDLE(x, v) (SCM_SET_SMOB_DATA_2 ((x), (scm_t_bits) (v)))
  188. static int
  189. dynl_obj_print (SCM exp, SCM port, scm_print_state *pstate)
  190. {
  191. scm_puts_unlocked ("#<dynamic-object ", port);
  192. scm_iprin1 (DYNL_FILENAME (exp), port, pstate);
  193. if (DYNL_HANDLE (exp) == NULL)
  194. scm_puts_unlocked (" (unlinked)", port);
  195. scm_putc_unlocked ('>', port);
  196. return 1;
  197. }
  198. SCM_DEFINE (scm_dynamic_link, "dynamic-link", 0, 1, 0,
  199. (SCM filename),
  200. "Find the shared object (shared library) denoted by\n"
  201. "@var{filename} and link it into the running Guile\n"
  202. "application. The returned\n"
  203. "scheme object is a ``handle'' for the library which can\n"
  204. "be passed to @code{dynamic-func}, @code{dynamic-call} etc.\n\n"
  205. "Searching for object files is system dependent. Normally,\n"
  206. "if @var{filename} does have an explicit directory it will\n"
  207. "be searched for in locations\n"
  208. "such as @file{/usr/lib} and @file{/usr/local/lib}.\n\n"
  209. "When @var{filename} is omitted, a @dfn{global symbol handle} is\n"
  210. "returned. This handle provides access to the symbols\n"
  211. "available to the program at run-time, including those exported\n"
  212. "by the program itself and the shared libraries already loaded.\n")
  213. #define FUNC_NAME s_scm_dynamic_link
  214. {
  215. void *handle;
  216. char *file;
  217. scm_dynwind_begin (0);
  218. if (SCM_UNBNDP (filename))
  219. file = NULL;
  220. else
  221. {
  222. file = scm_to_locale_string (filename);
  223. scm_dynwind_free (file);
  224. }
  225. handle = sysdep_dynl_link (file, FUNC_NAME);
  226. scm_dynwind_end ();
  227. SCM_RETURN_NEWSMOB2 (scm_tc16_dynamic_obj,
  228. SCM_UNBNDP (filename)
  229. ? SCM_UNPACK (SCM_BOOL_F) : SCM_UNPACK (filename),
  230. handle);
  231. }
  232. #undef FUNC_NAME
  233. SCM_DEFINE (scm_dynamic_object_p, "dynamic-object?", 1, 0, 0,
  234. (SCM obj),
  235. "Return @code{#t} if @var{obj} is a dynamic object handle,\n"
  236. "or @code{#f} otherwise.")
  237. #define FUNC_NAME s_scm_dynamic_object_p
  238. {
  239. return scm_from_bool (SCM_TYP16_PREDICATE (scm_tc16_dynamic_obj, obj));
  240. }
  241. #undef FUNC_NAME
  242. SCM_DEFINE (scm_dynamic_unlink, "dynamic-unlink", 1, 0, 0,
  243. (SCM dobj),
  244. "Unlink a dynamic object from the application, if possible. The\n"
  245. "object must have been linked by @code{dynamic-link}, with \n"
  246. "@var{dobj} the corresponding handle. After this procedure\n"
  247. "is called, the handle can no longer be used to access the\n"
  248. "object.")
  249. #define FUNC_NAME s_scm_dynamic_unlink
  250. {
  251. /*fixme* GC-problem */
  252. SCM_VALIDATE_SMOB (SCM_ARG1, dobj, dynamic_obj);
  253. if (DYNL_HANDLE (dobj) == NULL) {
  254. SCM_MISC_ERROR ("Already unlinked: ~S", scm_list_1 (dobj));
  255. } else {
  256. sysdep_dynl_unlink (DYNL_HANDLE (dobj), FUNC_NAME);
  257. SET_DYNL_HANDLE (dobj, NULL);
  258. return SCM_UNSPECIFIED;
  259. }
  260. }
  261. #undef FUNC_NAME
  262. SCM_DEFINE (scm_dynamic_pointer, "dynamic-pointer", 2, 0, 0,
  263. (SCM name, SCM dobj),
  264. "Return a ``wrapped pointer'' to the symbol @var{name}\n"
  265. "in the shared object referred to by @var{dobj}. The returned\n"
  266. "pointer points to a C object.\n\n"
  267. "Regardless whether your C compiler prepends an underscore\n"
  268. "@samp{_} to the global names in a program, you should\n"
  269. "@strong{not} include this underscore in @var{name}\n"
  270. "since it will be added automatically when necessary.")
  271. #define FUNC_NAME s_scm_dynamic_pointer
  272. {
  273. void *val;
  274. SCM_VALIDATE_STRING (1, name);
  275. SCM_VALIDATE_SMOB (SCM_ARG2, dobj, dynamic_obj);
  276. if (DYNL_HANDLE (dobj) == NULL)
  277. SCM_MISC_ERROR ("Already unlinked: ~S", dobj);
  278. else
  279. {
  280. char *chars;
  281. scm_dynwind_begin (0);
  282. chars = scm_to_locale_string (name);
  283. scm_dynwind_free (chars);
  284. val = sysdep_dynl_value (chars, DYNL_HANDLE (dobj), FUNC_NAME);
  285. scm_dynwind_end ();
  286. return scm_from_pointer (val, NULL);
  287. }
  288. }
  289. #undef FUNC_NAME
  290. SCM_DEFINE (scm_dynamic_func, "dynamic-func", 2, 0, 0,
  291. (SCM name, SCM dobj),
  292. "Return a ``handle'' for the function @var{name} in the\n"
  293. "shared object referred to by @var{dobj}. The handle\n"
  294. "can be passed to @code{dynamic-call} to actually\n"
  295. "call the function.\n\n"
  296. "Regardless whether your C compiler prepends an underscore\n"
  297. "@samp{_} to the global names in a program, you should\n"
  298. "@strong{not} include this underscore in @var{name}\n"
  299. "since it will be added automatically when necessary.")
  300. #define FUNC_NAME s_scm_dynamic_func
  301. {
  302. return scm_dynamic_pointer (name, dobj);
  303. }
  304. #undef FUNC_NAME
  305. SCM_DEFINE (scm_dynamic_call, "dynamic-call", 2, 0, 0,
  306. (SCM func, SCM dobj),
  307. "Call a C function in a dynamic object. Two styles of\n"
  308. "invocation are supported:\n\n"
  309. "@itemize @bullet\n"
  310. "@item @var{func} can be a function handle returned by\n"
  311. "@code{dynamic-func}. In this case @var{dobj} is\n"
  312. "ignored\n"
  313. "@item @var{func} can be a string with the name of the\n"
  314. "function to call, with @var{dobj} the handle of the\n"
  315. "dynamic object in which to find the function.\n"
  316. "This is equivalent to\n"
  317. "@smallexample\n\n"
  318. "(dynamic-call (dynamic-func @var{func} @var{dobj}) #f)\n"
  319. "@end smallexample\n"
  320. "@end itemize\n\n"
  321. "In either case, the function is passed no arguments\n"
  322. "and its return value is ignored.")
  323. #define FUNC_NAME s_scm_dynamic_call
  324. {
  325. void (*fptr) (void);
  326. if (scm_is_string (func))
  327. func = scm_dynamic_func (func, dobj);
  328. SCM_VALIDATE_POINTER (SCM_ARG1, func);
  329. fptr = SCM_POINTER_VALUE (func);
  330. fptr ();
  331. return SCM_UNSPECIFIED;
  332. }
  333. #undef FUNC_NAME
  334. void
  335. scm_init_dynamic_linking ()
  336. {
  337. scm_tc16_dynamic_obj = scm_make_smob_type ("dynamic-object", 0);
  338. scm_set_smob_print (scm_tc16_dynamic_obj, dynl_obj_print);
  339. sysdep_dynl_init ();
  340. #include "libguile/dynl.x"
  341. }
  342. /*
  343. Local Variables:
  344. c-file-style: "gnu"
  345. End:
  346. */