[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