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