2 Copyright (C) 2001-2008, The Perl Foundation.
7 src/dynext.c - Dynamic extensions to Parrot
19 #include "parrot/parrot.h"
20 #include "parrot/dynext.h"
23 /* HEADERIZER HFILE: include/parrot/dynext.h */
25 /* HEADERIZER BEGIN: static */
26 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
28 PARROT_WARN_UNUSED_RESULT
29 PARROT_CANNOT_RETURN_NULL
30 static STRING
* clone_string_into(
34 __attribute__nonnull__(1)
35 __attribute__nonnull__(2)
36 __attribute__nonnull__(3)
39 PARROT_WARN_UNUSED_RESULT
40 PARROT_CAN_RETURN_NULL
41 static STRING
* get_path(PARROT_INTERP
,
43 ARGOUT(void **handle
),
44 ARGIN(STRING
*wo_ext
),
45 ARGIN_NULLOK(STRING
*ext
))
46 __attribute__nonnull__(1)
47 __attribute__nonnull__(2)
48 __attribute__nonnull__(3)
49 __attribute__nonnull__(4)
51 FUNC_MODIFIES(*handle
);
53 PARROT_WARN_UNUSED_RESULT
54 PARROT_CAN_RETURN_NULL
55 static PMC
* is_loaded(PARROT_INTERP
, ARGIN(STRING
*path
))
56 __attribute__nonnull__(1)
57 __attribute__nonnull__(2);
59 PARROT_WARN_UNUSED_RESULT
60 PARROT_CANNOT_RETURN_NULL
61 static PMC
* make_string_pmc(PARROT_INTERP
, ARGIN(STRING
*string
))
62 __attribute__nonnull__(1)
63 __attribute__nonnull__(2);
65 PARROT_CANNOT_RETURN_NULL
66 static PMC
* run_init_lib(PARROT_INTERP
,
68 ARGIN(STRING
*lib_name
),
69 ARGIN(STRING
*wo_ext
))
70 __attribute__nonnull__(1)
71 __attribute__nonnull__(2)
72 __attribute__nonnull__(3)
73 __attribute__nonnull__(4);
75 static void set_cstring_prop(PARROT_INTERP
,
77 ARGIN(const char *what
),
79 __attribute__nonnull__(1)
80 __attribute__nonnull__(2)
81 __attribute__nonnull__(3)
82 __attribute__nonnull__(4)
83 FUNC_MODIFIES(*lib_pmc
);
85 static void store_lib_pmc(PARROT_INTERP
,
89 ARGIN(STRING
*lib_name
))
90 __attribute__nonnull__(1)
91 __attribute__nonnull__(2)
92 __attribute__nonnull__(3)
93 __attribute__nonnull__(4)
94 __attribute__nonnull__(5);
96 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
97 /* HEADERIZER END: static */
99 /* _PARROTLIB is now the default */
100 /*#define _PARROTLIB not working: "make testr" */
104 =item C<static void set_cstring_prop>
106 Set a property C<name> with value C<what> on the C<ParrotLibrary>
114 set_cstring_prop(PARROT_INTERP
, ARGMOD(PMC
*lib_pmc
), ARGIN(const char *what
),
117 STRING
* const key
= const_string(interp
, what
);
118 PMC
* const prop
= constant_pmc_new(interp
, enum_class_String
);
120 VTABLE_set_string_native(interp
, prop
, name
);
121 VTABLE_setprop(interp
, lib_pmc
, key
, prop
);
126 =item C<static void store_lib_pmc>
128 Store a C<ParrotLibrary> PMC in the interpreter's C<iglobals>.
135 store_lib_pmc(PARROT_INTERP
, ARGIN(PMC
*lib_pmc
), ARGIN(STRING
*path
),
136 ARGIN(STRING
*type
), ARGIN(STRING
*lib_name
))
138 PMC
* const iglobals
= interp
->iglobals
;
139 PMC
* const dyn_libs
= VTABLE_get_pmc_keyed_int(interp
, iglobals
,
142 /* remember path/file in props */
143 set_cstring_prop(interp
, lib_pmc
, "_filename", path
); /* XXX */
144 set_cstring_prop(interp
, lib_pmc
, "_type", type
);
147 set_cstring_prop(interp
, lib_pmc
, "_lib_name", lib_name
);
149 VTABLE_set_pmc_keyed_str(interp
, dyn_libs
, path
, lib_pmc
);
154 =item C<static PMC* is_loaded>
156 Check if a C<ParrotLibrary> PMC with the filename path exists.
157 If it does, return it. Otherwise, return NULL.
163 PARROT_WARN_UNUSED_RESULT
164 PARROT_CAN_RETURN_NULL
166 is_loaded(PARROT_INTERP
, ARGIN(STRING
*path
))
168 PMC
* const iglobals
= interp
->iglobals
;
169 PMC
* const dyn_libs
= VTABLE_get_pmc_keyed_int(interp
, iglobals
,
171 if (!VTABLE_exists_keyed_str(interp
, dyn_libs
, path
))
173 return VTABLE_get_pmc_keyed_str(interp
, dyn_libs
, path
);
178 =item C<static STRING * get_path>
180 Return path and handle of a dynamic lib, setting lib_name to just the filestem
181 (i.e. without path or extension) as a freshly-allocated C string.
187 PARROT_WARN_UNUSED_RESULT
188 PARROT_CAN_RETURN_NULL
190 get_path(PARROT_INTERP
, ARGMOD(STRING
*lib
), ARGOUT(void **handle
),
191 ARGIN(STRING
*wo_ext
), ARGIN_NULLOK(STRING
*ext
))
193 STRING
*path
, *full_name
;
194 const char *err
= NULL
; /* buffer returned from Parrot_dlerror */
196 PMC
* const iglobals
= interp
->iglobals
;
197 PMC
* const lib_paths
= VTABLE_get_pmc_keyed_int(interp
, iglobals
,
199 PMC
* const share_ext
= VTABLE_get_pmc_keyed_int(interp
, lib_paths
,
200 PARROT_LIB_DYN_EXTS
);
203 *handle
= Parrot_dlopen((char *)NULL
);
205 return string_from_literal(interp
, "");
207 err
= Parrot_dlerror();
208 Parrot_warn(interp
, PARROT_WARNINGS_DYNEXT_FLAG
,
209 "Couldn't dlopen(NULL): %s\n",
210 err
? err
: "unknown reason");
215 * first, try to add an extension to the file if it has none.
218 const INTVAL n
= VTABLE_elements(interp
, share_ext
);
221 for (i
= 0; i
< n
; ++i
) {
222 ext
= VTABLE_get_string_keyed_int(interp
, share_ext
, i
);
223 full_name
= string_concat(interp
, wo_ext
, ext
, 0);
224 path
= Parrot_locate_runtime_file_str(interp
, full_name
,
225 PARROT_RUNTIME_FT_DYNEXT
);
227 *handle
= Parrot_dlopen(path
->strstart
);
231 err
= Parrot_dlerror();
232 Parrot_warn(interp
, PARROT_WARNINGS_DYNEXT_FLAG
,
233 "Couldn't load '%Ss': %s\n",
234 full_name
, err
? err
: "unknown reason");
239 * File with extension and prefix was not found,
240 * so try file.extension w/o prefix
242 *handle
= Parrot_dlopen(full_name
->strstart
);
249 * finally, try the given file name as is. We still use
250 * Parrot_locate_runtime_file so that (a) relative pathnames are searched in
251 * the standard locations, and (b) the angle of the slashes are adjusted as
252 * required for non-Unix systems.
254 full_name
= Parrot_locate_runtime_file_str(interp
, lib
,
255 PARROT_RUNTIME_FT_DYNEXT
);
257 *handle
= Parrot_dlopen((char *)full_name
->strstart
);
263 * and on windows strip a leading "lib"
264 * [shouldn't this happen in Parrot_locate_runtime_file instead?]
267 if (!STRING_IS_EMPTY(lib
) && memcmp(lib
->strstart
, "lib", 3) == 0) {
268 *handle
= Parrot_dlopen((char*)lib
->strstart
+ 3);
270 path
= string_substr(interp
, lib
, 3, lib
->strlen
- 3, NULL
, 0);
276 /* And on cygwin replace a leading "lib" by "cyg". */
278 if (!STRING_IS_EMPTY(lib
) && memcmp(lib
->strstart
, "lib", 3) == 0) {
279 path
= string_append(interp
, CONST_STRING(interp
, "cyg"),
280 string_substr(interp
, lib
, 3, lib
->strlen
- 3, NULL
, 0));
282 *handle
= Parrot_dlopen(path
->strstart
);
288 err
= Parrot_dlerror();
289 Parrot_warn(interp
, PARROT_WARNINGS_DYNEXT_FLAG
,
290 "Couldn't load '%Ss': %s\n",
291 lib
, err
? err
: "unknown reason");
297 =item C<PMC * Parrot_init_lib>
299 RT#48260: Not yet documented!!!
306 PARROT_CANNOT_RETURN_NULL
308 Parrot_init_lib(PARROT_INTERP
,
309 ARGIN_NULLOK(PMC
*(*load_func
)(PARROT_INTERP
)),
310 ARGIN_NULLOK(void (*init_func
)(PARROT_INTERP
, ARGIN_NULLOK(PMC
*))))
315 lib_pmc
= (*load_func
)(interp
);
317 /* seems to be a native/NCI lib */
318 if (!load_func
|| !lib_pmc
)
319 lib_pmc
= constant_pmc_new(interp
, enum_class_ParrotLibrary
);
321 /* Call init, if it exists */
323 (init_func
)(interp
, lib_pmc
);
330 =item C<static PMC * run_init_lib>
332 RT#48260: Not yet documented!!!
338 PARROT_CANNOT_RETURN_NULL
340 run_init_lib(PARROT_INTERP
, ARGIN(void *handle
),
341 ARGIN(STRING
*lib_name
), ARGIN(STRING
*wo_ext
))
344 PMC
*(*load_func
)(PARROT_INTERP
);
345 void (*init_func
)(PARROT_INTERP
, PMC
*);
346 char *cinit_func_name
;
350 * work around gcc 3.3.3 and other problem with dynpmcs
351 * something during library loading doesn't stand a DOD run
353 Parrot_block_GC_mark(interp
);
357 STRING
* const load_func_name
= Parrot_sprintf_c(interp
,
358 "Parrot_lib_%Ss_load", lib_name
);
359 char * const cload_func_name
= string_to_cstring(interp
, load_func_name
);
360 STRING
*init_func_name
;
362 load_func
= (PMC
* (*)(PARROT_INTERP
))
363 (Parrot_dlsym(handle
, cload_func_name
));
365 string_cstring_free(cload_func_name
);
368 init_func_name
= Parrot_sprintf_c(interp
, "Parrot_lib_%Ss_init",
370 cinit_func_name
= string_to_cstring(interp
, init_func_name
);
371 init_func
= (void (*)(PARROT_INTERP
, PMC
*))(Parrot_dlsym(handle
,
373 string_cstring_free(cinit_func_name
);
380 lib_pmc
= Parrot_init_lib(interp
, load_func
, init_func
);
381 VTABLE_set_pointer(interp
, lib_pmc
, handle
);
384 type
= CONST_STRING(interp
, "NCI");
386 /* we could set a private flag in the PMC header too
387 * but currently only ops files have struct_val set */
389 if (PMC_struct_val(lib_pmc
))
390 type
= CONST_STRING(interp
, "Ops");
392 type
= CONST_STRING(interp
, "PMC");
395 /* remember lib_pmc in iglobals */
396 store_lib_pmc(interp
, lib_pmc
, wo_ext
, type
, lib_name
);
399 Parrot_unblock_GC_mark(interp
);
406 =item C<static STRING * clone_string_into>
408 RT#48260: Not yet documented!!!
414 PARROT_WARN_UNUSED_RESULT
415 PARROT_CANNOT_RETURN_NULL
417 clone_string_into(ARGMOD(Interp
*d
), ARGIN(Interp
*s
), ARGIN(PMC
*value
))
419 STRING
* const orig
= VTABLE_get_string(s
, value
);
420 char * const raw_str
= string_to_cstring(s
, orig
);
422 string_make_direct(d
, raw_str
, strlen(raw_str
),
423 PARROT_DEFAULT_ENCODING
, PARROT_DEFAULT_CHARSET
,
425 string_cstring_free(raw_str
);
431 =item C<static PMC * make_string_pmc>
433 RT#48260: Not yet documented!!!
439 PARROT_WARN_UNUSED_RESULT
440 PARROT_CANNOT_RETURN_NULL
442 make_string_pmc(PARROT_INTERP
, ARGIN(STRING
*string
))
444 PMC
* const ret
= VTABLE_new_from_string(interp
,
445 interp
->vtables
[enum_class_String
]->pmc_class
,
446 string
, PObj_constant_FLAG
);
452 =item C<PMC * Parrot_clone_lib_into>
454 RT#48260: Not yet documented!!!
461 PARROT_WARN_UNUSED_RESULT
462 PARROT_CANNOT_RETURN_NULL
464 Parrot_clone_lib_into(ARGMOD(Interp
*d
), ARGMOD(Interp
*s
), ARGIN(PMC
*lib_pmc
))
466 STRING
* const wo_ext
= clone_string_into(d
, s
,
467 VTABLE_getprop(s
, lib_pmc
, CONST_STRING(s
, "_filename")));
468 STRING
* const lib_name
= clone_string_into(d
, s
,
469 VTABLE_getprop(s
, lib_pmc
, CONST_STRING(s
, "_lib_name")));
470 void * const handle
= PMC_data(lib_pmc
);
471 STRING
* const type
=
472 VTABLE_get_string(s
, VTABLE_getprop(s
, lib_pmc
, CONST_STRING(s
, "_type")));
473 STRING
* const ops
= CONST_STRING(s
, "Ops");
475 if (!string_equal(s
, type
, ops
)) {
476 /* we can't clone oplibs in the normal way, since they're actually
477 * shared between interpreters dynop_register modifies the (statically
478 * allocated) op_lib_t structure from core_ops.c, for example.
479 * Anyways, if we hope to share bytecode at runtime, we need to have
480 * them have identical opcodes anyways.
482 PMC
* const new_lib_pmc
= constant_pmc_new(d
, enum_class_ParrotLibrary
);
484 PMC_data(new_lib_pmc
) = handle
;
485 VTABLE_setprop(d
, new_lib_pmc
, CONST_STRING(s
, "_filename"), make_string_pmc(d
, wo_ext
));
486 VTABLE_setprop(d
, new_lib_pmc
, CONST_STRING(s
, "_lib_name"), make_string_pmc(d
, lib_name
));
487 VTABLE_setprop(d
, new_lib_pmc
, CONST_STRING(s
, "_type"), make_string_pmc(d
, ops
));
489 /* fixup d->all_op_libs, if necessary */
490 if (d
->n_libs
!= s
->n_libs
) {
493 d
->all_op_libs
= (op_lib_t
**)mem_sys_realloc(d
->all_op_libs
,
494 sizeof (op_lib_t
*) * s
->n_libs
);
496 d
->all_op_libs
= (op_lib_t
**)mem_sys_allocate(sizeof (op_lib_t
*) *
498 for (i
= d
->n_libs
; i
< s
->n_libs
; ++i
)
499 d
->all_op_libs
[i
] = s
->all_op_libs
[i
];
500 d
->n_libs
= s
->n_libs
;
506 return run_init_lib(d
, handle
, lib_name
, wo_ext
);
512 =item C<PMC * Parrot_load_lib>
514 Dynamic library loader.
516 C<initializer> is currently unused.
518 Calls C<Parrot_lib_%s_load()> which performs the registration of the lib
519 once C<Parrot_lib_%s_init()> gets called (if exists) to perform thread
520 specific setup. In both functions C<%s> is the name of the library.
522 If Parrot_lib_%s_load() succeeds, it should either return a
523 ParrotLibrary PMC, which is then used as the handle for this library
524 or NULL, in which case parrot creates a handle for the library.
526 If either Parrot_lib_%s_load() or Parrot_lib_%s_init() detects an error
527 condition, an exception should be thrown.
529 TODO: fetch Parrot_lib load/init handler exceptions
536 PARROT_WARN_UNUSED_RESULT
537 PARROT_CANNOT_RETURN_NULL
539 Parrot_load_lib(PARROT_INTERP
, ARGIN_NULLOK(STRING
*lib
), SHIM(PMC
*initializer
))
544 STRING
*lib_name
, *wo_ext
, *ext
; /* library stem without path
546 /* Find the pure library name, without path or extension. */
548 * TODO move the class_count_mutex here
553 lib_name
= parrot_split_path_ext(interp
, lib
, &wo_ext
, &ext
);
556 wo_ext
= string_from_literal(interp
, "");
561 lib_pmc
= is_loaded(interp
, wo_ext
);
562 if (!PMC_IS_NULL(lib_pmc
)) {
567 path
= get_path(interp
, lib
, &handle
, wo_ext
, ext
);
568 if (!path
|| !handle
) {
570 * XXX real_exception? return PMCNULL?
571 * PMC Undef seems convenient, because it can be queried with get_bool()
573 return pmc_new(interp
, enum_class_Undef
);
576 return run_init_lib(interp
, handle
, lib_name
, wo_ext
);
585 F<include/parrot/dynext.h> and F<src/pmc/parrotlibrary.pmc>.
589 Initial rev by leo 2003.08.06.
598 * c-file-style: "parrot"
600 * vim: expandtab shiftwidth=4: