2 Copyright (C) 2001-2008, Parrot Foundation.
7 src/dynext.c - Dynamic extensions to Parrot
11 Functions for loading and initializing dynamic link libraries.
21 #include "parrot/parrot.h"
22 #include "parrot/dynext.h"
24 #include "pmc/pmc_parrotlibrary.h"
25 #include "pmc/pmc_context.h"
27 /* HEADERIZER HFILE: include/parrot/dynext.h */
29 /* HEADERIZER BEGIN: static */
30 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
32 PARROT_WARN_UNUSED_RESULT
33 PARROT_CANNOT_RETURN_NULL
34 static STRING
* clone_string_into(
38 __attribute__nonnull__(1)
39 __attribute__nonnull__(2)
40 __attribute__nonnull__(3)
43 PARROT_WARN_UNUSED_RESULT
44 PARROT_CAN_RETURN_NULL
45 static void * dlopen_string(PARROT_INTERP
, ARGIN(STRING
*path
))
46 __attribute__nonnull__(1)
47 __attribute__nonnull__(2);
49 PARROT_WARN_UNUSED_RESULT
50 PARROT_CAN_RETURN_NULL
51 static STRING
* get_path(PARROT_INTERP
,
52 ARGMOD_NULLOK(STRING
*lib
),
53 ARGOUT(void **handle
),
54 ARGIN(STRING
*wo_ext
),
55 ARGIN_NULLOK(STRING
*ext
))
56 __attribute__nonnull__(1)
57 __attribute__nonnull__(3)
58 __attribute__nonnull__(4)
60 FUNC_MODIFIES(*handle
);
62 PARROT_WARN_UNUSED_RESULT
63 PARROT_CAN_RETURN_NULL
64 static PMC
* is_loaded(PARROT_INTERP
, ARGIN(STRING
*path
))
65 __attribute__nonnull__(1)
66 __attribute__nonnull__(2);
68 PARROT_WARN_UNUSED_RESULT
69 PARROT_CANNOT_RETURN_NULL
70 static PMC
* make_string_pmc(PARROT_INTERP
, ARGIN(STRING
*string
))
71 __attribute__nonnull__(1)
72 __attribute__nonnull__(2);
74 PARROT_CANNOT_RETURN_NULL
75 static PMC
* run_init_lib(PARROT_INTERP
,
77 ARGIN_NULLOK(STRING
*lib_name
),
78 ARGIN(STRING
*wo_ext
))
79 __attribute__nonnull__(1)
80 __attribute__nonnull__(2)
81 __attribute__nonnull__(4);
83 static void set_cstring_prop(PARROT_INTERP
,
85 ARGIN(const char *what
),
87 __attribute__nonnull__(1)
88 __attribute__nonnull__(2)
89 __attribute__nonnull__(3)
90 __attribute__nonnull__(4)
91 FUNC_MODIFIES(*lib_pmc
);
93 static void store_lib_pmc(PARROT_INTERP
,
97 ARGIN_NULLOK(STRING
*lib_name
))
98 __attribute__nonnull__(1)
99 __attribute__nonnull__(2)
100 __attribute__nonnull__(3)
101 __attribute__nonnull__(4);
103 #define ASSERT_ARGS_clone_string_into __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
104 PARROT_ASSERT_ARG(d) \
105 , PARROT_ASSERT_ARG(s) \
106 , PARROT_ASSERT_ARG(value))
107 #define ASSERT_ARGS_dlopen_string __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
108 PARROT_ASSERT_ARG(interp) \
109 , PARROT_ASSERT_ARG(path))
110 #define ASSERT_ARGS_get_path __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
111 PARROT_ASSERT_ARG(interp) \
112 , PARROT_ASSERT_ARG(handle) \
113 , PARROT_ASSERT_ARG(wo_ext))
114 #define ASSERT_ARGS_is_loaded __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
115 PARROT_ASSERT_ARG(interp) \
116 , PARROT_ASSERT_ARG(path))
117 #define ASSERT_ARGS_make_string_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
118 PARROT_ASSERT_ARG(interp) \
119 , PARROT_ASSERT_ARG(string))
120 #define ASSERT_ARGS_run_init_lib __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
121 PARROT_ASSERT_ARG(interp) \
122 , PARROT_ASSERT_ARG(handle) \
123 , PARROT_ASSERT_ARG(wo_ext))
124 #define ASSERT_ARGS_set_cstring_prop __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
125 PARROT_ASSERT_ARG(interp) \
126 , PARROT_ASSERT_ARG(lib_pmc) \
127 , PARROT_ASSERT_ARG(what) \
128 , PARROT_ASSERT_ARG(name))
129 #define ASSERT_ARGS_store_lib_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
130 PARROT_ASSERT_ARG(interp) \
131 , PARROT_ASSERT_ARG(lib_pmc) \
132 , PARROT_ASSERT_ARG(path) \
133 , PARROT_ASSERT_ARG(type))
134 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
135 /* HEADERIZER END: static */
137 /* _PARROTLIB is now the default */
138 /*#define _PARROTLIB not working: "make testr" */
142 =item C<static void set_cstring_prop(PARROT_INTERP, PMC *lib_pmc, const char
143 *what, STRING *name)>
145 Set a property C<name> with value C<what> on the C<ParrotLibrary>
153 set_cstring_prop(PARROT_INTERP
, ARGMOD(PMC
*lib_pmc
), ARGIN(const char *what
),
156 ASSERT_ARGS(set_cstring_prop
)
157 STRING
* const key
= Parrot_str_new_constant(interp
, what
);
158 PMC
* const prop
= constant_pmc_new(interp
, enum_class_String
);
160 VTABLE_set_string_native(interp
, prop
, name
);
161 VTABLE_setprop(interp
, lib_pmc
, key
, prop
);
166 =item C<static void store_lib_pmc(PARROT_INTERP, PMC *lib_pmc, STRING *path,
167 STRING *type, STRING *lib_name)>
169 Store a C<ParrotLibrary> PMC in the interpreter's C<iglobals>.
176 store_lib_pmc(PARROT_INTERP
, ARGIN(PMC
*lib_pmc
), ARGIN(STRING
*path
),
177 ARGIN(STRING
*type
), ARGIN_NULLOK(STRING
*lib_name
))
179 ASSERT_ARGS(store_lib_pmc
)
180 PMC
* const iglobals
= interp
->iglobals
;
181 PMC
* const dyn_libs
= VTABLE_get_pmc_keyed_int(interp
, iglobals
,
184 /* remember path/file in props */
185 set_cstring_prop(interp
, lib_pmc
, "_filename", path
);
186 set_cstring_prop(interp
, lib_pmc
, "_type", type
);
189 set_cstring_prop(interp
, lib_pmc
, "_lib_name", lib_name
);
191 VTABLE_set_pmc_keyed_str(interp
, dyn_libs
, path
, lib_pmc
);
196 =item C<static PMC* is_loaded(PARROT_INTERP, STRING *path)>
198 Check if a C<ParrotLibrary> PMC with the filename path exists.
199 If it does, return it. Otherwise, return NULL.
205 PARROT_WARN_UNUSED_RESULT
206 PARROT_CAN_RETURN_NULL
208 is_loaded(PARROT_INTERP
, ARGIN(STRING
*path
))
210 ASSERT_ARGS(is_loaded
)
211 PMC
* const iglobals
= interp
->iglobals
;
212 PMC
* const dyn_libs
= VTABLE_get_pmc_keyed_int(interp
, iglobals
,
214 if (!VTABLE_exists_keyed_str(interp
, dyn_libs
, path
))
216 return VTABLE_get_pmc_keyed_str(interp
, dyn_libs
, path
);
221 =item C<static void * dlopen_string(PARROT_INTERP, STRING *path)>
223 Call Parrot_dlopen with the Parrot String argument converted to C string.
229 PARROT_WARN_UNUSED_RESULT
230 PARROT_CAN_RETURN_NULL
232 dlopen_string(PARROT_INTERP
, ARGIN(STRING
*path
))
234 ASSERT_ARGS(dlopen_string
)
236 char *pathstr
= Parrot_str_to_cstring(interp
, path
);
237 void *handle
= Parrot_dlopen(pathstr
);
238 Parrot_str_free_cstring(pathstr
);
244 =item C<static STRING * get_path(PARROT_INTERP, STRING *lib, void **handle,
245 STRING *wo_ext, STRING *ext)>
247 Return path and handle of a dynamic lib, setting lib_name to just the filestem
248 (i.e. without path or extension) as a freshly-allocated C string.
254 PARROT_WARN_UNUSED_RESULT
255 PARROT_CAN_RETURN_NULL
257 get_path(PARROT_INTERP
, ARGMOD_NULLOK(STRING
*lib
), ARGOUT(void **handle
),
258 ARGIN(STRING
*wo_ext
), ARGIN_NULLOK(STRING
*ext
))
260 ASSERT_ARGS(get_path
)
261 STRING
*path
, *full_name
;
262 const char *err
= NULL
; /* buffer returned from Parrot_dlerror */
264 PMC
* const iglobals
= interp
->iglobals
;
265 PMC
* const lib_paths
= VTABLE_get_pmc_keyed_int(interp
, iglobals
,
267 PMC
* const share_ext
= VTABLE_get_pmc_keyed_int(interp
, lib_paths
,
268 PARROT_LIB_DYN_EXTS
);
271 *handle
= Parrot_dlopen((char *)NULL
);
273 return string_from_literal(interp
, "");
275 err
= Parrot_dlerror();
276 Parrot_warn(interp
, PARROT_WARNINGS_DYNEXT_FLAG
,
277 "Couldn't dlopen(NULL): %s\n",
278 err
? err
: "unknown reason");
283 * first, try to add an extension to the file if it has none.
286 const INTVAL n
= VTABLE_elements(interp
, share_ext
);
289 for (i
= 0; i
< n
; ++i
) {
290 ext
= VTABLE_get_string_keyed_int(interp
, share_ext
, i
);
291 full_name
= Parrot_str_concat(interp
, wo_ext
, ext
, 0);
292 path
= Parrot_locate_runtime_file_str(interp
, full_name
,
293 PARROT_RUNTIME_FT_DYNEXT
);
295 *handle
= dlopen_string(interp
, path
);
299 err
= Parrot_dlerror();
300 Parrot_warn(interp
, PARROT_WARNINGS_DYNEXT_FLAG
,
301 "Couldn't load '%Ss': %s\n",
302 full_name
, err
? err
: "unknown reason");
307 * File with extension and prefix was not found,
308 * so try file.extension w/o prefix
310 *handle
= dlopen_string(interp
, full_name
);
317 * finally, try the given file name as is. We still use
318 * Parrot_locate_runtime_file so that (a) relative pathnames are searched in
319 * the standard locations, and (b) the angle of the slashes are adjusted as
320 * required for non-Unix systems.
322 full_name
= Parrot_locate_runtime_file_str(interp
, lib
,
323 PARROT_RUNTIME_FT_DYNEXT
);
325 *handle
= dlopen_string(interp
, full_name
);
331 * and on windows strip a leading "lib"
332 * [shouldn't this happen in Parrot_locate_runtime_file instead?]
335 if (!STRING_IS_EMPTY(lib
) && memcmp(lib
->strstart
, "lib", 3) == 0) {
336 *handle
= Parrot_dlopen((char *)lib
->strstart
+ 3);
338 path
= Parrot_str_substr(interp
, lib
, 3, lib
->strlen
- 3, NULL
, 0);
344 /* And on cygwin replace a leading "lib" by "cyg". */
346 if (!STRING_IS_EMPTY(lib
) && memcmp(lib
->strstart
, "lib", 3) == 0) {
347 path
= Parrot_str_append(interp
, CONST_STRING(interp
, "cyg"),
348 Parrot_str_substr(interp
, lib
, 3, lib
->strlen
- 3, NULL
, 0));
350 *handle
= dlopen_string(interp
, path
);
357 /* And after-finally, let the OS use his own search */
358 if (!STRING_IS_EMPTY(lib
)) {
359 *handle
= dlopen_string(interp
, lib
);
364 err
= Parrot_dlerror();
365 Parrot_warn(interp
, PARROT_WARNINGS_DYNEXT_FLAG
,
366 "Couldn't load '%Ss': %s\n",
367 lib
, err
? err
: "unknown reason");
373 =item C<PMC * Parrot_init_lib(PARROT_INTERP, PMC *(*load_func(PARROT_INTERP)),
374 void (*init_func(PARROT_INTERP, PMC *)))>
376 Initializes a new library. First, calls C<load_func> to load the library
377 (if C<load_func> is provided) and then calls C<init_func>. Returns a
378 ParrotLibrary PMC object that represents the initialized library.
385 PARROT_CANNOT_RETURN_NULL
387 Parrot_init_lib(PARROT_INTERP
,
388 ARGIN_NULLOK(PMC
*(*load_func
)(PARROT_INTERP
)),
389 ARGIN_NULLOK(void (*init_func
)(PARROT_INTERP
, ARGIN_NULLOK(PMC
*))))
391 ASSERT_ARGS(Parrot_init_lib
)
395 lib_pmc
= (*load_func
)(interp
);
397 /* seems to be a native/NCI lib */
398 if (!load_func
|| !lib_pmc
)
399 lib_pmc
= constant_pmc_new(interp
, enum_class_ParrotLibrary
);
401 /* Call init, if it exists */
403 (init_func
)(interp
, lib_pmc
);
410 =item C<static PMC * run_init_lib(PARROT_INTERP, void *handle, STRING *lib_name,
413 Loads and Initializes a new library and returns a ParrotLibrary PMC.
414 Takes the name of a library C<libname>, that is loaded with handle C<handle>.
415 Calls the necessary initialization routines, if any.
421 PARROT_CANNOT_RETURN_NULL
423 run_init_lib(PARROT_INTERP
, ARGIN(void *handle
),
424 ARGIN_NULLOK(STRING
*lib_name
), ARGIN(STRING
*wo_ext
))
426 ASSERT_ARGS(run_init_lib
)
428 PMC
*(*load_func
)(PARROT_INTERP
);
429 void (*init_func
)(PARROT_INTERP
, PMC
*);
432 INTVAL regs_used
[] = { 2, 2, 2, 2 }; /* Arbitrary values */
433 const int parrot_hll_id
= 0;
434 PMC
* context
= Parrot_push_context(interp
, regs_used
);
435 Parrot_pcc_set_HLL(interp
, context
, parrot_hll_id
);
436 Parrot_pcc_set_namespace(interp
, context
,
437 Parrot_get_HLL_namespace(interp
, parrot_hll_id
));
440 * work around gcc 3.3.3 and other problem with dynpmcs
441 * something during library loading doesn't stand a GC run
443 Parrot_block_GC_mark(interp
);
446 STRING
* const load_name
= Parrot_sprintf_c(interp
,
447 "Parrot_lib_%Ss_load", lib_name
);
448 STRING
* const init_func_name
= Parrot_sprintf_c(interp
,
449 "Parrot_lib_%Ss_init", lib_name
);
450 char * const cload_func_name
= Parrot_str_to_cstring(interp
, load_name
);
451 char * const cinit_func_name
= Parrot_str_to_cstring(interp
, init_func_name
);
454 void * dlsymfunc
= Parrot_dlsym(handle
, cload_func_name
);
455 load_func
= (PMC
* (*)(PARROT_INTERP
)) D2FPTR(dlsymfunc
);
456 Parrot_str_free_cstring(cload_func_name
);
459 dlsymfunc
= Parrot_dlsym(handle
, cinit_func_name
);
460 init_func
= (void (*)(PARROT_INTERP
, PMC
*)) D2FPTR(dlsymfunc
);
461 Parrot_str_free_cstring(cinit_func_name
);
468 lib_pmc
= Parrot_init_lib(interp
, load_func
, init_func
);
469 VTABLE_set_pointer(interp
, lib_pmc
, handle
);
472 type
= CONST_STRING(interp
, "NCI");
474 if (((Parrot_ParrotLibrary_attributes
*)PMC_data(lib_pmc
))->oplib_init
)
475 type
= CONST_STRING(interp
, "Ops");
477 type
= CONST_STRING(interp
, "PMC");
480 /* remember lib_pmc in iglobals */
481 store_lib_pmc(interp
, lib_pmc
, wo_ext
, type
, lib_name
);
484 Parrot_unblock_GC_mark(interp
);
486 Parrot_pop_context(interp
);
493 =item C<static STRING * clone_string_into(Interp *d, Interp *s, PMC *value)>
495 Extracts a STRING value from PMC C<value> in interpreter C<s>. Copies that
496 string into the pool of interpreter C<d> using the default encoding
503 PARROT_WARN_UNUSED_RESULT
504 PARROT_CANNOT_RETURN_NULL
506 clone_string_into(ARGMOD(Interp
*d
), ARGIN(Interp
*s
), ARGIN(PMC
*value
))
508 ASSERT_ARGS(clone_string_into
)
509 STRING
* const orig
= VTABLE_get_string(s
, value
);
510 char * const raw_str
= Parrot_str_to_cstring(s
, orig
);
512 Parrot_str_new_init(d
, raw_str
, strlen(raw_str
),
513 PARROT_DEFAULT_ENCODING
, PARROT_DEFAULT_CHARSET
,
515 Parrot_str_free_cstring(raw_str
);
521 =item C<static PMC * make_string_pmc(PARROT_INTERP, STRING *string)>
523 Converts a STRING C<string> into a String PMC.
529 PARROT_WARN_UNUSED_RESULT
530 PARROT_CANNOT_RETURN_NULL
532 make_string_pmc(PARROT_INTERP
, ARGIN(STRING
*string
))
534 ASSERT_ARGS(make_string_pmc
)
535 PMC
* const ret
= constant_pmc_new(interp
, enum_class_String
);
536 VTABLE_set_string_native(interp
, ret
, string
);
543 =item C<PMC * Parrot_clone_lib_into(Interp *d, Interp *s, PMC *lib_pmc)>
545 Clones a ParrotLibrary PMC C<lib_pmc> from interpreter C<s> into interpreter
553 PARROT_WARN_UNUSED_RESULT
554 PARROT_CANNOT_RETURN_NULL
556 Parrot_clone_lib_into(ARGMOD(Interp
*d
), ARGMOD(Interp
*s
), ARGIN(PMC
*lib_pmc
))
558 ASSERT_ARGS(Parrot_clone_lib_into
)
559 STRING
* const filename
= CONST_STRING(s
, "_filename");
560 STRING
* const libname
= CONST_STRING(s
, "_lib_name");
561 STRING
* const type_str
= CONST_STRING(s
, "_type");
562 STRING
* const ops
= CONST_STRING(s
, "Ops");
564 STRING
* const wo_ext
= clone_string_into(d
, s
,
565 VTABLE_getprop(s
, lib_pmc
, filename
));
566 STRING
* const lib_name
= clone_string_into(d
, s
,
567 VTABLE_getprop(s
, lib_pmc
, libname
));
568 void * const handle
= VTABLE_get_pointer(s
, lib_pmc
);
569 STRING
* const type
=
570 VTABLE_get_string(s
, VTABLE_getprop(s
, lib_pmc
, type_str
));
572 if (Parrot_str_equal(s
, type
, ops
)) {
573 /* we can't clone oplibs in the normal way, since they're actually
574 * shared between interpreters dynop_register modifies the (statically
575 * allocated) op_lib_t structure from core_ops.c, for example.
576 * Anyways, if we hope to share bytecode at runtime, we need to have
577 * them have identical opcodes anyways.
579 PMC
* const new_lib_pmc
= constant_pmc_new(d
, enum_class_ParrotLibrary
);
581 PMC_data(new_lib_pmc
) = handle
;
582 VTABLE_setprop(d
, new_lib_pmc
, CONST_STRING(s
, "_filename"), make_string_pmc(d
, wo_ext
));
583 VTABLE_setprop(d
, new_lib_pmc
, CONST_STRING(s
, "_lib_name"), make_string_pmc(d
, lib_name
));
584 VTABLE_setprop(d
, new_lib_pmc
, CONST_STRING(s
, "_type"), make_string_pmc(d
, ops
));
586 /* fixup d->all_op_libs, if necessary */
587 if (d
->n_libs
!= s
->n_libs
) {
590 d
->all_op_libs
= (op_lib_t
**)mem_sys_realloc(d
->all_op_libs
,
591 sizeof (op_lib_t
*) * s
->n_libs
);
593 d
->all_op_libs
= (op_lib_t
**)mem_sys_allocate(sizeof (op_lib_t
*) *
595 for (i
= d
->n_libs
; i
< s
->n_libs
; ++i
)
596 d
->all_op_libs
[i
] = s
->all_op_libs
[i
];
597 d
->n_libs
= s
->n_libs
;
603 return run_init_lib(d
, handle
, lib_name
, wo_ext
);
609 =item C<PMC * Parrot_load_lib(PARROT_INTERP, STRING *lib, PMC *initializer)>
611 Dynamic library loader.
613 C<initializer> is currently unused.
615 Calls C<Parrot_lib_%s_load()> which performs the registration of the lib
616 once C<Parrot_lib_%s_init()> gets called (if exists) to perform thread
617 specific setup. In both functions C<%s> is the name of the library.
619 If Parrot_lib_%s_load() succeeds, it should either return a
620 ParrotLibrary PMC, which is then used as the handle for this library
621 or NULL, in which case parrot creates a handle for the library.
623 If either Parrot_lib_%s_load() or Parrot_lib_%s_init() detects an error
624 condition, an exception should be thrown.
626 TODO: fetch Parrot_lib load/init handler exceptions
633 PARROT_WARN_UNUSED_RESULT
634 PARROT_CANNOT_RETURN_NULL
636 Parrot_load_lib(PARROT_INTERP
, ARGIN_NULLOK(STRING
*lib
), SHIM(PMC
*initializer
))
638 ASSERT_ARGS(Parrot_load_lib
)
642 STRING
*lib_name
, *wo_ext
, *ext
; /* library stem without path
644 /* Find the pure library name, without path or extension. */
646 * TODO move the class_count_mutex here
651 lib_name
= parrot_split_path_ext(interp
, lib
, &wo_ext
, &ext
);
654 wo_ext
= string_from_literal(interp
, "");
659 lib_pmc
= is_loaded(interp
, wo_ext
);
660 if (!PMC_IS_NULL(lib_pmc
)) {
665 path
= get_path(interp
, lib
, &handle
, wo_ext
, ext
);
666 if (!path
|| !handle
) {
668 * XXX Parrot_ex_throw_from_c_args? return PMCNULL?
669 * PMC Undef seems convenient, because it can be queried with get_bool()
671 return pmc_new(interp
, enum_class_Undef
);
674 return run_init_lib(interp
, handle
, lib_name
, wo_ext
);
683 F<include/parrot/dynext.h> and F<src/pmc/parrotlibrary.pmc>.
687 Initial rev by leo 2003.08.06.
696 * c-file-style: "parrot"
698 * vim: expandtab shiftwidth=4: