Provide `int', `long', `size_t', etc. in `(system foreign)'.
[bpt/guile.git] / libguile / dynl.c
CommitLineData
1edae076
MV
1/* dynl.c - dynamic linking
2 *
4d3526d0 3 * Copyright (C) 1990, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000, 2001, 2002,
e773b1e6 4 * 2003, 2008, 2009, 2010 Free Software Foundation, Inc.
1edae076 5 *
73be1d9e 6 * This library is free software; you can redistribute it and/or
53befeb7
NJ
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.
1edae076 10 *
53befeb7
NJ
11 * This library is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
1edae076 15 *
73be1d9e
MV
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
53befeb7
NJ
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301 USA
73be1d9e 20 */
1edae076 21
1bbd0b84
GB
22
23
dbb605f5
LC
24#ifdef HAVE_CONFIG_H
25# include <config.h>
26#endif
27
1edae076
MV
28/* "dynl.c" dynamically link&load object files.
29 Author: Aubrey Jaffer
30 Modified for libguile by Marius Vollmer */
31
104d4533 32#if 0 /* Disabled until we know for sure that it isn't needed */
80bc7890
MV
33/* XXX - This is only here to drag in a definition of __eprintf. This
34 is needed for proper operation of dynamic linking. The real
35 solution would probably be a shared libgcc. */
36
37#undef NDEBUG
38#include <assert.h>
39
40static void
41maybe_drag_in_eprintf ()
42{
43 assert (!maybe_drag_in_eprintf);
44}
104d4533 45#endif
80bc7890 46
96599e6a 47#include <stdio.h>
13070bd3
DH
48#include <string.h>
49
a0599745 50#include "libguile/_scm.h"
eb350124 51#include "libguile/libpath.h"
a0599745
MD
52#include "libguile/dynl.h"
53#include "libguile/smob.h"
54#include "libguile/keywords.h"
55#include "libguile/ports.h"
56#include "libguile/strings.h"
a0e0793f 57#include "libguile/deprecation.h"
c96d76b8 58#include "libguile/lang.h"
a0599745 59#include "libguile/validate.h"
7f9994d9 60#include "libguile/dynwind.h"
e773b1e6 61#include "libguile/foreign.h"
408ea28a 62
a8255dca 63#include <ltdl.h>
4feb69af 64
c2cbcc57
HWN
65/*
66 From the libtool manual: "Note that libltdl is not threadsafe,
67 i.e. a multithreaded application has to use a mutex for libltdl.".
68
9de87eea
MV
69 Guile does not currently support pre-emptive threads, so there is no
70 mutex. Previously SCM_CRITICAL_SECTION_START and
71 SCM_CRITICAL_SECTION_END were used: they are mentioned here in case
72 somebody is grepping for thread problems ;)
732b9327 73*/
e45947bf 74/* njrev: not threadsafe, protection needed as described above */
732b9327 75
4feb69af 76static void *
af45e3b0 77sysdep_dynl_link (const char *fname, const char *subr)
4feb69af 78{
a8255dca
MV
79 lt_dlhandle handle;
80 handle = lt_dlopenext (fname);
4feb69af
MV
81 if (NULL == handle)
82 {
01449aa5
DH
83 SCM fn;
84 SCM msg;
85
cc95e00a 86 fn = scm_from_locale_string (fname);
a8255dca 87 msg = scm_from_locale_string (lt_dlerror ());
1afff620 88 scm_misc_error (subr, "file: ~S, message: ~S", scm_list_2 (fn, msg));
4feb69af
MV
89 }
90 return (void *) handle;
91}
92
93static void
94sysdep_dynl_unlink (void *handle, const char *subr)
95{
a8255dca 96 if (lt_dlclose ((lt_dlhandle) handle))
4feb69af 97 {
a8255dca 98 scm_misc_error (subr, (char *) lt_dlerror (), SCM_EOL);
4feb69af
MV
99 }
100}
101
102static void *
52fd9639 103sysdep_dynl_value (const char *symb, void *handle, const char *subr)
4feb69af
MV
104{
105 void *fptr;
106
a8255dca 107 fptr = lt_dlsym ((lt_dlhandle) handle, symb);
4feb69af
MV
108 if (!fptr)
109 {
a8255dca 110 scm_misc_error (subr, (char *) lt_dlerror (), SCM_EOL);
4feb69af
MV
111 }
112 return fptr;
113}
114
115static void
116sysdep_dynl_init ()
117{
eb350124
AW
118 char *env;
119
a8255dca 120 lt_dlinit ();
eb350124 121
28af5ee5 122 env = getenv ("GUILE_SYSTEM_EXTENSIONS_PATH");
eb350124
AW
123 if (env && strcmp (env, "") == 0)
124 /* special-case interpret system-ltdl-path=="" as meaning no system path,
125 which is the case during the build */
126 ;
127 else if (env)
28af5ee5
AW
128 /* FIXME: should this be a colon-separated path? Or is the only point to
129 allow the build system to turn off the installed extensions path? */
eb350124 130 lt_dladdsearchdir (env);
eb350124 131 else
28af5ee5
AW
132 {
133 lt_dladdsearchdir (SCM_LIB_DIR);
134 lt_dladdsearchdir (SCM_EXTENSIONS_DIR);
135 }
4feb69af
MV
136}
137
92c2555f 138scm_t_bits scm_tc16_dynamic_obj;
80bc7890 139
f5710d53
MV
140#define DYNL_FILENAME SCM_SMOB_OBJECT
141#define DYNL_HANDLE(x) ((void *) SCM_SMOB_DATA_2 (x))
2ff08405 142#define SET_DYNL_HANDLE(x, v) (SCM_SET_SMOB_DATA_2 ((x), (scm_t_bits) (v)))
7cf1a27e 143
7cf1a27e 144
e841c3e0 145
80bc7890 146static int
e841c3e0 147dynl_obj_print (SCM exp, SCM port, scm_print_state *pstate)
80bc7890 148{
7cf1a27e
MD
149 scm_puts ("#<dynamic-object ", port);
150 scm_iprin1 (DYNL_FILENAME (exp), port, pstate);
151 if (DYNL_HANDLE (exp) == NULL)
152 scm_puts (" (unlinked)", port);
153 scm_putc ('>', port);
154 return 1;
80bc7890
MV
155}
156
8e3ab003 157
af45e3b0 158SCM_DEFINE (scm_dynamic_link, "dynamic-link", 1, 0, 0,
1e6808ea 159 (SCM filename),
ee95d597
GH
160 "Find the shared object (shared library) denoted by\n"
161 "@var{filename} and link it into the running Guile\n"
162 "application. The returned\n"
163 "scheme object is a ``handle'' for the library which can\n"
164 "be passed to @code{dynamic-func}, @code{dynamic-call} etc.\n\n"
165 "Searching for object files is system dependent. Normally,\n"
166 "if @var{filename} does have an explicit directory it will\n"
167 "be searched for in locations\n"
168 "such as @file{/usr/lib} and @file{/usr/local/lib}.")
1bbd0b84 169#define FUNC_NAME s_scm_dynamic_link
80bc7890 170{
7cf1a27e 171 void *handle;
7f9994d9 172 char *file;
80bc7890 173
661ae7ab 174 scm_dynwind_begin (0);
7f9994d9 175 file = scm_to_locale_string (filename);
661ae7ab 176 scm_dynwind_free (file);
7f9994d9 177 handle = sysdep_dynl_link (file, FUNC_NAME);
661ae7ab 178 scm_dynwind_end ();
1e6808ea 179 SCM_RETURN_NEWSMOB2 (scm_tc16_dynamic_obj, SCM_UNPACK (filename), handle);
80bc7890 180}
1bbd0b84 181#undef FUNC_NAME
80bc7890 182
80bc7890 183
a1ec6916 184SCM_DEFINE (scm_dynamic_object_p, "dynamic-object?", 1, 0, 0,
1bbd0b84 185 (SCM obj),
ee95d597
GH
186 "Return @code{#t} if @var{obj} is a dynamic object handle,\n"
187 "or @code{#f} otherwise.")
1bbd0b84 188#define FUNC_NAME s_scm_dynamic_object_p
80bc7890 189{
7888309b 190 return scm_from_bool (SCM_TYP16_PREDICATE (scm_tc16_dynamic_obj, obj));
80bc7890 191}
1bbd0b84 192#undef FUNC_NAME
80bc7890 193
b82c6ce0 194
a1ec6916 195SCM_DEFINE (scm_dynamic_unlink, "dynamic-unlink", 1, 0, 0,
1bbd0b84 196 (SCM dobj),
ee95d597
GH
197 "Unlink a dynamic object from the application, if possible. The\n"
198 "object must have been linked by @code{dynamic-link}, with \n"
199 "@var{dobj} the corresponding handle. After this procedure\n"
200 "is called, the handle can no longer be used to access the\n"
201 "object.")
1bbd0b84 202#define FUNC_NAME s_scm_dynamic_unlink
80bc7890 203{
7cf1a27e 204 /*fixme* GC-problem */
b82c6ce0
DH
205 SCM_VALIDATE_SMOB (SCM_ARG1, dobj, dynamic_obj);
206 if (DYNL_HANDLE (dobj) == NULL) {
9e375910 207 SCM_MISC_ERROR ("Already unlinked: ~S", scm_list_1 (dobj));
b82c6ce0 208 } else {
b82c6ce0
DH
209 sysdep_dynl_unlink (DYNL_HANDLE (dobj), FUNC_NAME);
210 SET_DYNL_HANDLE (dobj, NULL);
b82c6ce0
DH
211 return SCM_UNSPECIFIED;
212 }
80bc7890 213}
1bbd0b84 214#undef FUNC_NAME
80bc7890 215
b82c6ce0 216
52fd9639
AW
217SCM_DEFINE (scm_dynamic_pointer, "dynamic-pointer", 3, 1, 0,
218 (SCM name, SCM type, SCM dobj, SCM len),
219 "Return a ``handle'' for the pointer @var{name} in the\n"
ee95d597 220 "shared object referred to by @var{dobj}. The handle\n"
52fd9639
AW
221 "aliases a C value, and is declared to be of type\n"
222 "@var{type}. Valid types are defined in the\n"
3023e7b0
LC
223 "@code{(system foreign)} module.\n\n"
224 "This facility works by asking the dynamic linker for\n"
52fd9639
AW
225 "the address of a symbol, then assuming that it aliases a\n"
226 "value of a given type. Obviously, the user must be very\n"
227 "careful to ensure that the value actually is of the\n"
228 "declared type, or bad things will happen.\n\n"
ee95d597
GH
229 "Regardless whether your C compiler prepends an underscore\n"
230 "@samp{_} to the global names in a program, you should\n"
231 "@strong{not} include this underscore in @var{name}\n"
232 "since it will be added automatically when necessary.")
52fd9639 233#define FUNC_NAME s_scm_dynamic_pointer
80bc7890 234{
52fd9639
AW
235 void *val;
236 scm_t_foreign_type t;
80bc7890 237
a6d9e5ab 238 SCM_VALIDATE_STRING (1, name);
52fd9639 239 t = scm_to_unsigned_integer (type, 0, SCM_FOREIGN_TYPE_LAST);
52fd9639 240 SCM_VALIDATE_SMOB (SCM_ARG3, dobj, dynamic_obj);
3023e7b0
LC
241
242 if (DYNL_HANDLE (dobj) == NULL)
b82c6ce0 243 SCM_MISC_ERROR ("Already unlinked: ~S", dobj);
3023e7b0
LC
244 else
245 {
246 char *chars;
247
248 scm_dynwind_begin (0);
249 chars = scm_to_locale_string (name);
250 scm_dynwind_free (chars);
251 val = sysdep_dynl_value (chars, DYNL_HANDLE (dobj), FUNC_NAME);
252 scm_dynwind_end ();
253
254 return scm_take_foreign_pointer (t, val,
255 SCM_UNBNDP (len) ? 0 : scm_to_size_t (len),
256 NULL);
257 }
80bc7890 258}
1bbd0b84 259#undef FUNC_NAME
80bc7890 260
b82c6ce0 261
52fd9639
AW
262SCM_DEFINE (scm_dynamic_func, "dynamic-func", 2, 0, 0,
263 (SCM name, SCM dobj),
264 "Return a ``handle'' for the function @var{name} in the\n"
265 "shared object referred to by @var{dobj}. The handle\n"
266 "can be passed to @code{dynamic-call} to actually\n"
267 "call the function.\n\n"
268 "Regardless whether your C compiler prepends an underscore\n"
269 "@samp{_} to the global names in a program, you should\n"
270 "@strong{not} include this underscore in @var{name}\n"
271 "since it will be added automatically when necessary.")
272#define FUNC_NAME s_scm_dynamic_func
273{
274 return scm_dynamic_pointer (name,
275 scm_from_uint (SCM_FOREIGN_TYPE_VOID),
276 dobj,
277 SCM_UNDEFINED);
278}
279#undef FUNC_NAME
280
281
a1ec6916 282SCM_DEFINE (scm_dynamic_call, "dynamic-call", 2, 0, 0,
1bbd0b84 283 (SCM func, SCM dobj),
46732b54
GH
284 "Call a C function in a dynamic object. Two styles of\n"
285 "invocation are supported:\n\n"
286 "@itemize @bullet\n"
287 "@item @var{func} can be a function handle returned by\n"
288 "@code{dynamic-func}. In this case @var{dobj} is\n"
289 "ignored\n"
290 "@item @var{func} can be a string with the name of the\n"
291 "function to call, with @var{dobj} the handle of the\n"
292 "dynamic object in which to find the function.\n"
293 "This is equivalent to\n"
294 "@smallexample\n\n"
295 "(dynamic-call (dynamic-func @var{func} @var{dobj}) #f)\n"
296 "@end smallexample\n"
297 "@end itemize\n\n"
298 "In either case, the function is passed no arguments\n"
299 "and its return value is ignored.")
1bbd0b84 300#define FUNC_NAME s_scm_dynamic_call
80bc7890 301{
7cf1a27e
MD
302 void (*fptr) ();
303
7f9994d9 304 if (scm_is_string (func))
7cf1a27e 305 func = scm_dynamic_func (func, dobj);
52fd9639 306 SCM_VALIDATE_FOREIGN_TYPED (SCM_ARG1, func, VOID);
e773b1e6 307
52fd9639 308 fptr = SCM_FOREIGN_POINTER (func, void);
7cf1a27e 309 fptr ();
7cf1a27e 310 return SCM_UNSPECIFIED;
80bc7890 311}
1bbd0b84 312#undef FUNC_NAME
80bc7890 313
a1ec6916 314SCM_DEFINE (scm_dynamic_args_call, "dynamic-args-call", 3, 0, 0,
1bbd0b84 315 (SCM func, SCM dobj, SCM args),
1e6808ea
MG
316 "Call the C function indicated by @var{func} and @var{dobj},\n"
317 "just like @code{dynamic-call}, but pass it some arguments and\n"
318 "return its return value. The C function is expected to take\n"
319 "two arguments and return an @code{int}, just like @code{main}:\n"
b380b885
MD
320 "@smallexample\n"
321 "int c_func (int argc, char **argv);\n"
322 "@end smallexample\n\n"
1e6808ea
MG
323 "The parameter @var{args} must be a list of strings and is\n"
324 "converted into an array of @code{char *}. The array is passed\n"
325 "in @var{argv} and its size in @var{argc}. The return value is\n"
326 "converted to a Scheme number and returned from the call to\n"
327 "@code{dynamic-args-call}.")
1bbd0b84 328#define FUNC_NAME s_scm_dynamic_args_call
80bc7890 329{
7cf1a27e
MD
330 int (*fptr) (int argc, char **argv);
331 int result, argc;
332 char **argv;
333
7f9994d9 334 if (scm_is_string (func))
7cf1a27e 335 func = scm_dynamic_func (func, dobj);
52fd9639 336 SCM_VALIDATE_FOREIGN_TYPED (SCM_ARG1, func, VOID);
7cf1a27e 337
52fd9639 338 fptr = SCM_FOREIGN_POINTER (func, void);
7f9994d9
MV
339
340 argv = scm_i_allocate_string_pointers (args);
7f9994d9
MV
341 for (argc = 0; argv[argc]; argc++)
342 ;
7cf1a27e 343 result = (*fptr) (argc, argv);
7cf1a27e 344
e11e83f3 345 return scm_from_int (result);
80bc7890 346}
1bbd0b84 347#undef FUNC_NAME
80bc7890 348
1edae076
MV
349void
350scm_init_dynamic_linking ()
351{
7cf1a27e 352 scm_tc16_dynamic_obj = scm_make_smob_type ("dynamic-object", 0);
e841c3e0 353 scm_set_smob_print (scm_tc16_dynamic_obj, dynl_obj_print);
7cf1a27e 354 sysdep_dynl_init ();
a0599745 355#include "libguile/dynl.x"
1edae076 356}
89e00824
ML
357
358/*
359 Local Variables:
360 c-file-style: "gnu"
361 End:
362*/