dynl.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  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. /* "dynl.c" dynamically link&load object files.
  26. Author: Aubrey Jaffer
  27. Modified for libguile by Marius Vollmer */
  28. #if 0 /* Disabled until we know for sure that it isn't needed */
  29. /* XXX - This is only here to drag in a definition of __eprintf. This
  30. is needed for proper operation of dynamic linking. The real
  31. solution would probably be a shared libgcc. */
  32. #undef NDEBUG
  33. #include <assert.h>
  34. static void
  35. maybe_drag_in_eprintf ()
  36. {
  37. assert (!maybe_drag_in_eprintf);
  38. }
  39. #endif
  40. #include <stdlib.h>
  41. #include <stdio.h>
  42. #include <string.h>
  43. #include "libguile/_scm.h"
  44. #include "libguile/libpath.h"
  45. #include "libguile/dynl.h"
  46. #include "libguile/smob.h"
  47. #include "libguile/keywords.h"
  48. #include "libguile/ports.h"
  49. #include "libguile/strings.h"
  50. #include "libguile/deprecation.h"
  51. #include "libguile/validate.h"
  52. #include "libguile/dynwind.h"
  53. #include "libguile/foreign.h"
  54. #include <ltdl.h>
  55. /*
  56. From the libtool manual: "Note that libltdl is not threadsafe,
  57. i.e. a multithreaded application has to use a mutex for libltdl.".
  58. Guile does not currently support pre-emptive threads, so there is no
  59. mutex. Previously SCM_CRITICAL_SECTION_START and
  60. SCM_CRITICAL_SECTION_END were used: they are mentioned here in case
  61. somebody is grepping for thread problems ;)
  62. */
  63. /* njrev: not threadsafe, protection needed as described above */
  64. static void *
  65. sysdep_dynl_link (const char *fname, const char *subr)
  66. {
  67. lt_dlhandle handle;
  68. if (fname != NULL)
  69. handle = lt_dlopenext (fname);
  70. else
  71. /* Return a handle for the program as a whole. */
  72. handle = lt_dlopen (NULL);
  73. if (NULL == handle)
  74. {
  75. SCM fn;
  76. SCM msg;
  77. fn = fname != NULL ? scm_from_locale_string (fname) : SCM_BOOL_F;
  78. msg = scm_from_locale_string (lt_dlerror ());
  79. scm_misc_error (subr, "file: ~S, message: ~S", scm_list_2 (fn, msg));
  80. }
  81. return (void *) handle;
  82. }
  83. static void
  84. sysdep_dynl_unlink (void *handle, const char *subr)
  85. {
  86. if (lt_dlclose ((lt_dlhandle) handle))
  87. {
  88. scm_misc_error (subr, (char *) lt_dlerror (), SCM_EOL);
  89. }
  90. }
  91. static void *
  92. sysdep_dynl_value (const char *symb, void *handle, const char *subr)
  93. {
  94. void *fptr;
  95. fptr = lt_dlsym ((lt_dlhandle) handle, symb);
  96. if (!fptr)
  97. scm_misc_error (subr, "Symbol not found: ~a",
  98. scm_list_1 (scm_from_locale_string (symb)));
  99. return fptr;
  100. }
  101. /* Augment environment variable VARIABLE with VALUE, assuming VARIABLE
  102. is a path kind of variable. */
  103. static void
  104. augment_env (const char *variable, const char *value)
  105. {
  106. const char *env;
  107. env = getenv (variable);
  108. if (env != NULL)
  109. {
  110. char *new_value;
  111. static const char path_sep[] = { LT_PATHSEP_CHAR, 0 };
  112. new_value = alloca (strlen (env) + strlen (value) + 2);
  113. strcpy (new_value, env);
  114. strcat (new_value, path_sep);
  115. strcat (new_value, value);
  116. setenv (variable, new_value, 1);
  117. }
  118. else
  119. setenv (variable, value, 1);
  120. }
  121. static void
  122. sysdep_dynl_init ()
  123. {
  124. char *env;
  125. lt_dlinit ();
  126. env = getenv ("GUILE_SYSTEM_EXTENSIONS_PATH");
  127. if (env && strcmp (env, "") == 0)
  128. /* special-case interpret system-ltdl-path=="" as meaning no system path,
  129. which is the case during the build */
  130. ;
  131. else if (env)
  132. /* FIXME: should this be a colon-separated path? Or is the only point to
  133. allow the build system to turn off the installed extensions path? */
  134. lt_dladdsearchdir (env);
  135. else
  136. {
  137. /* Add SCM_LIB_DIR and SCM_EXTENSIONS_DIR to the loader's search
  138. path. `lt_dladdsearchdir' and $LTDL_LIBRARY_PATH can't be used
  139. for that because they are searched before the system-dependent
  140. search path, which is the one `libtool --mode=execute -dlopen'
  141. fiddles with (info "(libtool) Libltdl Interface"). See
  142. <http://lists.gnu.org/archive/html/guile-devel/2010-11/msg00095.html>
  143. for details. */
  144. augment_env (SHARED_LIBRARY_PATH_VARIABLE, SCM_LIB_DIR);
  145. augment_env (SHARED_LIBRARY_PATH_VARIABLE, SCM_EXTENSIONS_DIR);
  146. }
  147. }
  148. scm_t_bits scm_tc16_dynamic_obj;
  149. #define DYNL_FILENAME SCM_SMOB_OBJECT
  150. #define DYNL_HANDLE(x) ((void *) SCM_SMOB_DATA_2 (x))
  151. #define SET_DYNL_HANDLE(x, v) (SCM_SET_SMOB_DATA_2 ((x), (scm_t_bits) (v)))
  152. static int
  153. dynl_obj_print (SCM exp, SCM port, scm_print_state *pstate)
  154. {
  155. scm_puts_unlocked ("#<dynamic-object ", port);
  156. scm_iprin1 (DYNL_FILENAME (exp), port, pstate);
  157. if (DYNL_HANDLE (exp) == NULL)
  158. scm_puts_unlocked (" (unlinked)", port);
  159. scm_putc_unlocked ('>', port);
  160. return 1;
  161. }
  162. SCM_DEFINE (scm_dynamic_link, "dynamic-link", 0, 1, 0,
  163. (SCM filename),
  164. "Find the shared object (shared library) denoted by\n"
  165. "@var{filename} and link it into the running Guile\n"
  166. "application. The returned\n"
  167. "scheme object is a ``handle'' for the library which can\n"
  168. "be passed to @code{dynamic-func}, @code{dynamic-call} etc.\n\n"
  169. "Searching for object files is system dependent. Normally,\n"
  170. "if @var{filename} does have an explicit directory it will\n"
  171. "be searched for in locations\n"
  172. "such as @file{/usr/lib} and @file{/usr/local/lib}.\n\n"
  173. "When @var{filename} is omitted, a @dfn{global symbol handle} is\n"
  174. "returned. This handle provides access to the symbols\n"
  175. "available to the program at run-time, including those exported\n"
  176. "by the program itself and the shared libraries already loaded.\n")
  177. #define FUNC_NAME s_scm_dynamic_link
  178. {
  179. void *handle;
  180. char *file;
  181. scm_dynwind_begin (0);
  182. if (SCM_UNBNDP (filename))
  183. file = NULL;
  184. else
  185. {
  186. file = scm_to_locale_string (filename);
  187. scm_dynwind_free (file);
  188. }
  189. handle = sysdep_dynl_link (file, FUNC_NAME);
  190. scm_dynwind_end ();
  191. SCM_RETURN_NEWSMOB2 (scm_tc16_dynamic_obj,
  192. SCM_UNBNDP (filename)
  193. ? SCM_UNPACK (SCM_BOOL_F) : SCM_UNPACK (filename),
  194. handle);
  195. }
  196. #undef FUNC_NAME
  197. SCM_DEFINE (scm_dynamic_object_p, "dynamic-object?", 1, 0, 0,
  198. (SCM obj),
  199. "Return @code{#t} if @var{obj} is a dynamic object handle,\n"
  200. "or @code{#f} otherwise.")
  201. #define FUNC_NAME s_scm_dynamic_object_p
  202. {
  203. return scm_from_bool (SCM_TYP16_PREDICATE (scm_tc16_dynamic_obj, obj));
  204. }
  205. #undef FUNC_NAME
  206. SCM_DEFINE (scm_dynamic_unlink, "dynamic-unlink", 1, 0, 0,
  207. (SCM dobj),
  208. "Unlink a dynamic object from the application, if possible. The\n"
  209. "object must have been linked by @code{dynamic-link}, with \n"
  210. "@var{dobj} the corresponding handle. After this procedure\n"
  211. "is called, the handle can no longer be used to access the\n"
  212. "object.")
  213. #define FUNC_NAME s_scm_dynamic_unlink
  214. {
  215. /*fixme* GC-problem */
  216. SCM_VALIDATE_SMOB (SCM_ARG1, dobj, dynamic_obj);
  217. if (DYNL_HANDLE (dobj) == NULL) {
  218. SCM_MISC_ERROR ("Already unlinked: ~S", scm_list_1 (dobj));
  219. } else {
  220. sysdep_dynl_unlink (DYNL_HANDLE (dobj), FUNC_NAME);
  221. SET_DYNL_HANDLE (dobj, NULL);
  222. return SCM_UNSPECIFIED;
  223. }
  224. }
  225. #undef FUNC_NAME
  226. SCM_DEFINE (scm_dynamic_pointer, "dynamic-pointer", 2, 0, 0,
  227. (SCM name, SCM dobj),
  228. "Return a ``wrapped pointer'' to the symbol @var{name}\n"
  229. "in the shared object referred to by @var{dobj}. The returned\n"
  230. "pointer points to a C object.\n\n"
  231. "Regardless whether your C compiler prepends an underscore\n"
  232. "@samp{_} to the global names in a program, you should\n"
  233. "@strong{not} include this underscore in @var{name}\n"
  234. "since it will be added automatically when necessary.")
  235. #define FUNC_NAME s_scm_dynamic_pointer
  236. {
  237. void *val;
  238. SCM_VALIDATE_STRING (1, name);
  239. SCM_VALIDATE_SMOB (SCM_ARG2, dobj, dynamic_obj);
  240. if (DYNL_HANDLE (dobj) == NULL)
  241. SCM_MISC_ERROR ("Already unlinked: ~S", dobj);
  242. else
  243. {
  244. char *chars;
  245. scm_dynwind_begin (0);
  246. chars = scm_to_locale_string (name);
  247. scm_dynwind_free (chars);
  248. val = sysdep_dynl_value (chars, DYNL_HANDLE (dobj), FUNC_NAME);
  249. scm_dynwind_end ();
  250. return scm_from_pointer (val, NULL);
  251. }
  252. }
  253. #undef FUNC_NAME
  254. SCM_DEFINE (scm_dynamic_func, "dynamic-func", 2, 0, 0,
  255. (SCM name, SCM dobj),
  256. "Return a ``handle'' for the function @var{name} in the\n"
  257. "shared object referred to by @var{dobj}. The handle\n"
  258. "can be passed to @code{dynamic-call} to actually\n"
  259. "call the function.\n\n"
  260. "Regardless whether your C compiler prepends an underscore\n"
  261. "@samp{_} to the global names in a program, you should\n"
  262. "@strong{not} include this underscore in @var{name}\n"
  263. "since it will be added automatically when necessary.")
  264. #define FUNC_NAME s_scm_dynamic_func
  265. {
  266. return scm_dynamic_pointer (name, dobj);
  267. }
  268. #undef FUNC_NAME
  269. SCM_DEFINE (scm_dynamic_call, "dynamic-call", 2, 0, 0,
  270. (SCM func, SCM dobj),
  271. "Call a C function in a dynamic object. Two styles of\n"
  272. "invocation are supported:\n\n"
  273. "@itemize @bullet\n"
  274. "@item @var{func} can be a function handle returned by\n"
  275. "@code{dynamic-func}. In this case @var{dobj} is\n"
  276. "ignored\n"
  277. "@item @var{func} can be a string with the name of the\n"
  278. "function to call, with @var{dobj} the handle of the\n"
  279. "dynamic object in which to find the function.\n"
  280. "This is equivalent to\n"
  281. "@smallexample\n\n"
  282. "(dynamic-call (dynamic-func @var{func} @var{dobj}) #f)\n"
  283. "@end smallexample\n"
  284. "@end itemize\n\n"
  285. "In either case, the function is passed no arguments\n"
  286. "and its return value is ignored.")
  287. #define FUNC_NAME s_scm_dynamic_call
  288. {
  289. void (*fptr) (void);
  290. if (scm_is_string (func))
  291. func = scm_dynamic_func (func, dobj);
  292. SCM_VALIDATE_POINTER (SCM_ARG1, func);
  293. fptr = SCM_POINTER_VALUE (func);
  294. fptr ();
  295. return SCM_UNSPECIFIED;
  296. }
  297. #undef FUNC_NAME
  298. void
  299. scm_init_dynamic_linking ()
  300. {
  301. scm_tc16_dynamic_obj = scm_make_smob_type ("dynamic-object", 0);
  302. scm_set_smob_print (scm_tc16_dynamic_obj, dynl_obj_print);
  303. sysdep_dynl_init ();
  304. #include "libguile/dynl.x"
  305. }
  306. /*
  307. Local Variables:
  308. c-file-style: "gnu"
  309. End:
  310. */