[gambit-list] dlopen -- is there a simpler way?
Marc Feeley
feeley at iro.umontreal.ca
Wed Apr 6 07:57:48 EDT 2011
On 2011-04-06, at 3:31 AM, Jason E. Aten wrote:
> Dear Gambit enthusiasts,
>
> I think I figured out how to use dlopen to run functions from Gambit that live in dynamically loaded libraries (plugins); my best to date is below.
>
> But I'm not quite happy with it--because it's kind of elaborate. That is, I couldn't figure out how to avoid some of the boiler plate below. Perhaps there is a shorter way?
>
> So my question for Gambit enthusiasts is: Is there a cleaner way to do this--to run functions from plugin libraries? i.e. without having to pre-declare call_plugin_print8 and call_print8. What if you wanted to make such a call after inspecting a new library at runtime?
>
> Many thanks! Gambit rocks! Thanks again for such a great system.
>
> - Jason
Here's my shot at improving your code. Basically you want to convert the void* pointer returned by dlsym into an actual Scheme function that you can call without going through a proxy. In dlopen.scm I would use this code to implement the conversion:
(c-define-type void* (pointer void))
;;-----------------------------------------------------------------------------
;; Attempt #1, does not work (but should!).
(define convert.->int
(c-lambda (void*) (function () int) "___result = ___arg1;"))
(define convert.int->int
(c-lambda (void*) (function (int) int) "___result = ___arg1;"))
;;-----------------------------------------------------------------------------
;; Attempt #2, does work but a bit clunky.
(define (convert.->int ptr)
(lambda ()
((c-lambda (void*) int
"___result = ___CAST(int (*)(),___arg1)();")
ptr)))
(define (convert.int->int ptr)
(lambda (x)
((c-lambda (void* int) int
"___result = ___CAST(int (*)(int),___arg1)(___arg2);")
ptr
x)))
;;-----------------------------------------------------------------------------
;; Test code. Note the conversion to get a function from the void*
;; pointer returned by dlsym.
(define (test)
(let* ((h (dlopen "libex.so" (RTLD_LAZY)))
(print8 (convert.->int (dlsym h "print8")))
(square (convert.int->int (dlsym h "square"))))
(if (not print8)
(error "could not locate symbol 'print8' in the plugin library!")
(pretty-print (print8)))
(if (not square)
(error "could not locate symbol 'square' in the plugin library!")
(pretty-print (square 10)))))
(test)
;;-----------------------------------------------------------------------------
Note that I have added an int->int function in libex.c:
int print8() {
printf("\n In print8() : returning 8\n");
return 8;
}
int square(int x) {
printf("\n In square(int x) : returning x*x\n");
return x*x;
}
The first attempt, which has nicer code, does not work because I never got around to implementing that conversion in Gambit's FFI.
A more dynamic alternative, which would avoid having to decide on the function types at compile time, is to use libffi. I haven't tried it myself.
Marc
More information about the Gambit-list
mailing list