dynl.c 12 KB

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