* *.c: Pervasive software-engineering-motivated rewrite of
[bpt/guile.git] / libguile / dynl.c
CommitLineData
1edae076
MV
1/* dynl.c - dynamic linking
2 *
a80a90e9 3 * Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
1edae076
MV
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this software; see the file COPYING. If not, write to
82892bed
JB
17 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307 USA
1edae076
MV
19 *
20 * As a special exception, the Free Software Foundation gives permission
21 * for additional uses of the text contained in its release of GUILE.
22 *
23 * The exception is that, if you link the GUILE library with other files
24 * to produce an executable, this does not by itself cause the
25 * resulting executable to be covered by the GNU General Public License.
26 * Your use of that executable is in no way restricted on account of
27 * linking the GUILE library code into it.
28 *
29 * This exception does not however invalidate any other reasons why
30 * the executable file might be covered by the GNU General Public License.
31 *
32 * This exception applies only to the code released by the
33 * Free Software Foundation under the name GUILE. If you copy
34 * code from other Free Software Foundation releases into a copy of
35 * GUILE, as the General Public License permits, the exception does
36 * not apply to the code that you add in this way. To avoid misleading
37 * anyone as to the status of such modified files, you must delete
38 * this exception notice from them.
39 *
40 * If you write modifications of your own for GUILE, it is your choice
41 * whether to permit this exception to apply to your modifications.
82892bed 42 * If you do not wish that, delete this exception notice. */
1edae076 43
1bbd0b84
GB
44/* Software engineering face-lift by Greg J. Badros, 11-Dec-1999,
45 gjb@cs.washington.edu, http://www.cs.washington.edu/homes/gjb */
46
47
1edae076
MV
48/* "dynl.c" dynamically link&load object files.
49 Author: Aubrey Jaffer
50 Modified for libguile by Marius Vollmer */
51
104d4533 52#if 0 /* Disabled until we know for sure that it isn't needed */
80bc7890
MV
53/* XXX - This is only here to drag in a definition of __eprintf. This
54 is needed for proper operation of dynamic linking. The real
55 solution would probably be a shared libgcc. */
56
57#undef NDEBUG
58#include <assert.h>
59
60static void
61maybe_drag_in_eprintf ()
62{
63 assert (!maybe_drag_in_eprintf);
64}
104d4533 65#endif
80bc7890 66
96599e6a 67#include <stdio.h>
1edae076 68#include "_scm.h"
80bc7890
MV
69#include "dynl.h"
70#include "genio.h"
71#include "smob.h"
8e3ab003 72#include "keywords.h"
80bc7890 73
1edae076
MV
74/* Converting a list of SCM strings into a argv-style array. You must
75 have ints disabled for the whole lifetime of the created argv (from
76 before MAKE_ARGV_FROM_STRINGLIST until after
77 MUST_FREE_ARGV). Atleast this is was the documentation for
78 MAKARGVFROMSTRS says, it isn't really used that way.
79
80 This code probably belongs into strings.c */
81
1edae076 82static char **
1bbd0b84 83scm_make_argv_from_stringlist (SCM args,int *argcp,const char *subr,int argn)
1edae076
MV
84{
85 char **argv;
86 int argc, i;
87
88 argc = scm_ilength(args);
89 argv = (char **) scm_must_malloc ((1L+argc)*sizeof(char *), subr);
90 for(i = 0; SCM_NNULLP (args); args = SCM_CDR (args), i++) {
91 size_t len;
92 char *dst, *src;
93 SCM str = SCM_CAR (args);
94
95 SCM_ASSERT (SCM_NIMP (str) && SCM_ROSTRINGP (str), str, argn, subr);
96 len = 1 + SCM_ROLENGTH (str);
97 dst = (char *) scm_must_malloc ((long)len, subr);
98 src = SCM_ROCHARS (str);
99 while (len--)
100 dst[len] = src[len];
101 argv[i] = dst;
102 }
103
104 if (argcp)
105 *argcp = argc;
106 argv[argc] = 0;
107 return argv;
108}
109
1edae076 110static void
1bbd0b84 111scm_must_free_argv(char **argv)
1edae076
MV
112{
113 char **av = argv;
c3e09ef9
MD
114 while (*av)
115 free(*(av++));
1edae076
MV
116 free(argv);
117}
118
119/* Coerce an arbitrary readonly-string into a zero-terminated string.
120 */
121
1edae076 122static SCM
1bbd0b84 123scm_coerce_rostring (SCM rostr,const char *subr,int argn)
1edae076
MV
124{
125 SCM_ASSERT (SCM_NIMP (rostr) && SCM_ROSTRINGP (rostr), rostr, argn, subr);
126 if (SCM_SUBSTRP (rostr))
127 rostr = scm_makfromstr (SCM_ROCHARS (rostr), SCM_ROLENGTH (rostr), 0);
128 return rostr;
129}
130
80bc7890
MV
131/* Module registry
132 */
133
134/* We can't use SCM objects here. One should be able to call
135 SCM_REGISTER_MODULE from a C++ constructor for a static
136 object. This happens before main and thus before libguile is
137 initialized. */
138
139struct moddata {
140 struct moddata *link;
141 char *module_name;
142 void *init_func;
143};
144
145static struct moddata *registered_mods = NULL;
146
147void
148scm_register_module_xxx (module_name, init_func)
149 char *module_name;
150 void *init_func;
151{
152 struct moddata *md;
153
154 /* XXX - should we (and can we) DEFER_INTS here? */
155
156 for (md = registered_mods; md; md = md->link)
157 if (!strcmp (md->module_name, module_name)) {
158 md->init_func = init_func;
159 return;
160 }
161
162 md = (struct moddata *)malloc (sizeof (struct moddata));
96599e6a
MV
163 if (md == NULL) {
164 fprintf (stderr,
165 "guile: can't register module (%s): not enough memory",
166 module_name);
80bc7890 167 return;
96599e6a 168 }
80bc7890
MV
169
170 md->module_name = module_name;
171 md->init_func = init_func;
172 md->link = registered_mods;
173 registered_mods = md;
174}
175
1bbd0b84
GB
176GUILE_PROC (scm_registered_modules, "c-registered-modules", 0, 0, 0,
177 (),
178"")
179#define FUNC_NAME s_scm_registered_modules
80bc7890
MV
180{
181 SCM res;
182 struct moddata *md;
183
184 res = SCM_EOL;
185 for (md = registered_mods; md; md = md->link)
186 res = scm_cons (scm_cons (scm_makfrom0str (md->module_name),
187 scm_ulong2num ((unsigned long) md->init_func)),
188 res);
189 return res;
190}
1bbd0b84 191#undef FUNC_NAME
80bc7890 192
1bbd0b84
GB
193GUILE_PROC (scm_clear_registered_modules, "c-clear-registered-modules", 0, 0, 0,
194 (),
195"")
196#define FUNC_NAME s_scm_clear_registered_modules
80bc7890
MV
197{
198 struct moddata *md1, *md2;
199
200 SCM_DEFER_INTS;
201
202 for (md1 = registered_mods; md1; md1 = md2) {
203 md2 = md1->link;
204 free (md1);
205 }
206 registered_mods = NULL;
207
208 SCM_ALLOW_INTS;
209 return SCM_UNSPECIFIED;
210}
1bbd0b84 211#undef FUNC_NAME
80bc7890 212
1edae076 213/* Dispatch to the system dependent files
80bc7890 214 *
419e9e11
MV
215 * They define some static functions. These functions are called with
216 * deferred interrupts. When they want to throw errors, they are
217 * expected to insert a SCM_ALLOW_INTS before doing the throw. It
218 * might work to throw an error while interrupts are deferred (because
219 * they will be unconditionally allowed the next time a SCM_ALLOW_INTS
220 * is executed, SCM_DEFER_INTS and SCM_ALLOW_INTS do not nest).
1edae076
MV
221 */
222
8e3ab003
MV
223#define DYNL_GLOBAL 0x0001
224
26c41b99 225#ifdef HAVE_DLOPEN
1edae076
MV
226#include "dynl-dl.c"
227#else
228#ifdef HAVE_SHL_LOAD
229#include "dynl-shl.c"
230#else
26c41b99 231#ifdef HAVE_LIBDLD
1edae076 232#include "dynl-dld.c"
96599e6a
MV
233#else
234
235/* no dynamic linking available, throw errors. */
236
237static void
1bbd0b84 238sysdep_dynl_init (void)
96599e6a
MV
239{
240}
241
242static void
a80a90e9 243no_dynl_error (const char *subr)
96599e6a 244{
419e9e11
MV
245 SCM_ALLOW_INTS;
246 scm_misc_error (subr, "dynamic linking not available", SCM_EOL);
96599e6a
MV
247}
248
249static void *
8e3ab003
MV
250sysdep_dynl_link (const char *filename,
251 int flags,
a80a90e9 252 const char *subr)
96599e6a
MV
253{
254 no_dynl_error (subr);
255 return NULL;
256}
257
258static void
a80a90e9
JB
259sysdep_dynl_unlink (void *handle,
260 const char *subr)
96599e6a
MV
261{
262 no_dynl_error (subr);
263}
264
265static void *
a80a90e9
JB
266sysdep_dynl_func (const char *symbol,
267 void *handle,
268 const char *subr)
96599e6a
MV
269{
270 no_dynl_error (subr);
271 return NULL;
272}
273
80bc7890
MV
274#endif
275#endif
276#endif
277
278int scm_tc16_dynamic_obj;
279
280struct dynl_obj {
281 SCM filename;
282 void *handle;
283};
284
80bc7890 285static SCM
1bbd0b84 286mark_dynl_obj (SCM ptr)
80bc7890
MV
287{
288 struct dynl_obj *d = (struct dynl_obj *)SCM_CDR (ptr);
80bc7890
MV
289 return d->filename;
290}
291
c487ad44 292static scm_sizet
1bbd0b84 293free_dynl_obj (SCM ptr)
c487ad44
MV
294{
295 scm_must_free ((char *)SCM_CDR (ptr));
296 return sizeof (struct dynl_obj);
297}
298
80bc7890 299static int
1bbd0b84 300print_dynl_obj (SCM exp,SCM port,scm_print_state *pstate)
80bc7890
MV
301{
302 struct dynl_obj *d = (struct dynl_obj *)SCM_CDR (exp);
b7f3516f 303 scm_puts ("#<dynamic-object ", port);
80bc7890 304 scm_iprin1 (d->filename, port, pstate);
1fe1799f 305 if (d->handle == NULL)
b7f3516f
TT
306 scm_puts (" (unlinked)", port);
307 scm_putc ('>', port);
80bc7890
MV
308 return 1;
309}
310
8e3ab003
MV
311static SCM kw_global;
312SCM_SYMBOL (sym_global, "-global");
313
1bbd0b84
GB
314GUILE_PROC (scm_dynamic_link, "dynamic-link", 1, 0, 1,
315 (SCM fname, SCM rest),
316"")
317#define FUNC_NAME s_scm_dynamic_link
80bc7890
MV
318{
319 SCM z;
c487ad44 320 void *handle;
80bc7890 321 struct dynl_obj *d;
8e3ab003 322 int flags = DYNL_GLOBAL;
80bc7890 323
1bbd0b84 324 fname = scm_coerce_rostring (fname, FUNC_NAME, SCM_ARG1);
c487ad44 325
8e3ab003
MV
326 /* collect flags */
327 while (SCM_NIMP (rest) && SCM_CONSP (rest))
328 {
329 SCM kw, val;
330
331 kw = SCM_CAR (rest);
332 rest = SCM_CDR (rest);
333
334 if (!(SCM_NIMP (rest) && SCM_CONSP (rest)))
1bbd0b84 335 scm_misc_error (FUNC_NAME, "keyword without value", SCM_EOL);
8e3ab003
MV
336
337 val = SCM_CAR (rest);
338 rest = SCM_CDR (rest);
339
340 if (kw == kw_global)
341 {
342 if (SCM_FALSEP (val))
343 flags &= ~DYNL_GLOBAL;
344 }
345 else
1bbd0b84 346 scm_misc_error (FUNC_NAME, "unknown keyword argument: %s",
8e3ab003
MV
347 scm_cons (kw, SCM_EOL));
348 }
349
c487ad44 350 SCM_DEFER_INTS;
1bbd0b84 351 handle = sysdep_dynl_link (SCM_CHARS (fname), flags, FUNC_NAME);
c487ad44 352
80bc7890 353 d = (struct dynl_obj *)scm_must_malloc (sizeof (struct dynl_obj),
1bbd0b84 354 FUNC_NAME);
80bc7890 355 d->filename = fname;
c487ad44 356 d->handle = handle;
80bc7890 357
80bc7890
MV
358 SCM_NEWCELL (z);
359 SCM_SETCHARS (z, d);
360 SCM_SETCAR (z, scm_tc16_dynamic_obj);
361 SCM_ALLOW_INTS;
362
363 return z;
364}
1bbd0b84 365#undef FUNC_NAME
80bc7890 366
80bc7890 367static struct dynl_obj *
1bbd0b84 368get_dynl_obj (SCM dobj,const char *subr,int argn)
80bc7890
MV
369{
370 struct dynl_obj *d;
371 SCM_ASSERT (SCM_NIMP (dobj) && SCM_CAR (dobj) == scm_tc16_dynamic_obj,
372 dobj, argn, subr);
373 d = (struct dynl_obj *)SCM_CDR (dobj);
374 SCM_ASSERT (d->handle != NULL, dobj, argn, subr);
375 return d;
376}
377
1bbd0b84
GB
378GUILE_PROC (scm_dynamic_object_p, "dynamic-object?", 1, 0, 0,
379 (SCM obj),
380"")
381#define FUNC_NAME s_scm_dynamic_object_p
80bc7890
MV
382{
383 return (SCM_NIMP (obj) && SCM_CAR (obj) == scm_tc16_dynamic_obj)?
384 SCM_BOOL_T : SCM_BOOL_F;
385}
1bbd0b84 386#undef FUNC_NAME
80bc7890 387
1bbd0b84
GB
388GUILE_PROC (scm_dynamic_unlink, "dynamic-unlink", 1, 0, 0,
389 (SCM dobj),
390"")
391#define FUNC_NAME s_scm_dynamic_unlink
80bc7890 392{
1bbd0b84 393 struct dynl_obj *d = get_dynl_obj (dobj, FUNC_NAME, SCM_ARG1);
419e9e11 394 SCM_DEFER_INTS;
1bbd0b84 395 sysdep_dynl_unlink (d->handle, FUNC_NAME);
80bc7890 396 d->handle = NULL;
419e9e11
MV
397 SCM_ALLOW_INTS;
398 return SCM_UNSPECIFIED;
80bc7890 399}
1bbd0b84 400#undef FUNC_NAME
80bc7890 401
1bbd0b84
GB
402GUILE_PROC (scm_dynamic_func, "dynamic-func", 2, 0, 0,
403 (SCM symb, SCM dobj),
404"")
405#define FUNC_NAME s_scm_dynamic_func
80bc7890
MV
406{
407 struct dynl_obj *d;
408 void (*func) ();
409
1bbd0b84
GB
410 symb = scm_coerce_rostring (symb, FUNC_NAME, SCM_ARG1);
411 d = get_dynl_obj (dobj, FUNC_NAME, SCM_ARG2);
80bc7890 412
419e9e11 413 SCM_DEFER_INTS;
cdbadcac 414 func = (void (*) ()) sysdep_dynl_func (SCM_CHARS (symb), d->handle,
1bbd0b84 415 FUNC_NAME);
419e9e11
MV
416 SCM_ALLOW_INTS;
417
80bc7890
MV
418 return scm_ulong2num ((unsigned long)func);
419}
1bbd0b84 420#undef FUNC_NAME
80bc7890 421
1bbd0b84
GB
422GUILE_PROC (scm_dynamic_call, "dynamic-call", 2, 0, 0,
423 (SCM func, SCM dobj),
424"")
425#define FUNC_NAME s_scm_dynamic_call
80bc7890
MV
426{
427 void (*fptr)();
428
429 if (SCM_NIMP (func) && SCM_ROSTRINGP (func))
430 func = scm_dynamic_func (func, dobj);
1bbd0b84 431 fptr = (void (*)()) scm_num2ulong (func, (char *)SCM_ARG1, FUNC_NAME);
419e9e11 432 SCM_DEFER_INTS;
80bc7890 433 fptr ();
419e9e11
MV
434 SCM_ALLOW_INTS;
435 return SCM_UNSPECIFIED;
80bc7890 436}
1bbd0b84 437#undef FUNC_NAME
80bc7890 438
1bbd0b84
GB
439GUILE_PROC (scm_dynamic_args_call, "dynamic-args-call", 3, 0, 0,
440 (SCM func, SCM dobj, SCM args),
441"")
442#define FUNC_NAME s_scm_dynamic_args_call
80bc7890
MV
443{
444 int (*fptr) (int argc, char **argv);
445 int result, argc;
446 char **argv;
447
448 if (SCM_NIMP (func) && SCM_ROSTRINGP (func))
449 func = scm_dynamic_func (func, dobj);
450
451 fptr = (int (*)(int, char **)) scm_num2ulong (func, (char *)SCM_ARG1,
1bbd0b84 452 FUNC_NAME);
419e9e11 453 SCM_DEFER_INTS;
1bbd0b84 454 argv = scm_make_argv_from_stringlist (args, &argc, FUNC_NAME,
80bc7890 455 SCM_ARG3);
80bc7890 456 result = (*fptr) (argc, argv);
80bc7890 457 scm_must_free_argv (argv);
419e9e11
MV
458 SCM_ALLOW_INTS;
459
80bc7890
MV
460 return SCM_MAKINUM(0L+result);
461}
1bbd0b84 462#undef FUNC_NAME
80bc7890 463
1edae076
MV
464void
465scm_init_dynamic_linking ()
466{
23a62151
MD
467 scm_tc16_dynamic_obj = scm_make_smob_type_mfpe ("dynamic-object", sizeof (struct dynl_obj),
468 mark_dynl_obj, free_dynl_obj,
469 print_dynl_obj, NULL);
80bc7890
MV
470 sysdep_dynl_init ();
471#include "dynl.x"
8e3ab003 472 kw_global = scm_make_keyword_from_dash_symbol (sym_global);
1edae076 473}