Dear Gambit enthusiasts,<br><br>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.<br><br>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?<br>
<br>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?<br>
<br>Many thanks! Gambit rocks! Thanks again for such a great system.<br><br>- Jason<br><br><span style="font-family: courier new,monospace;">;;;;;;;;;;;;;;; file: libex.cpp ;;;;;;;;;;;;</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">;</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">; a simple library of one function for </span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">; testing/development of plugin loading </span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">;</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">#include <stdio.h></span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">extern "C" int print8() {</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> printf("\n In print8() : returning 8\n"); </span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> return 8; </span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">}</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">;;;;;;;;;;;;;;; file: libex.h ;;;;;;;;;;;;</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">#ifndef LIBEX_H</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">#define LIBEX_H</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">int print8();</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">#endif</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">;;;;;;;;;;;;;;; file: dlopen.scm ;;;;;;;;;;;;</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">;; dlopen.scm : plugins in Gambit</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">; compile and link with:</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">;</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">; gsc -link dlopen.scm</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">; gcc -I/usr/local/Gambit-C/include -L/usr/local/Gambit-C/lib dlopen.c dlopen_.c -lgambc -lm -lutil -ldl -o dlopen</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">(c-declare #<<c-declare-end</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> #include <stdio.h></span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> #include <stdlib.h></span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> #include <dlfcn.h></span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> #include "libex.h"</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> /* simple wrapper to do runtime plugin function calls (call into .so library) */</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> int call_plugin_print8(void* handle) {</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> char *error;</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> int (*my_func)();</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> // my_func = (int (*)()) dlsym(handle,"print8");</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> *(void **) (&my_func) = dlsym(handle, "print8");</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> if ((error = dlerror()) != NULL) </span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> {</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> fprintf(stderr, "%s\n", error);</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> exit(EXIT_FAILURE);</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> }</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> </span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> return (*my_func)();</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> }</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">c-declare-end</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">)</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">; from dlfcn.h ; see man dlopen</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">;</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">; void * dlopen(const char *filename, int flag);</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">; char * dlerror(void);</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">; void * dlsym(void *handle, const char *symbol);</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">; int dlclose(void *handle);</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">;</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">; translated into Gambit-C FFI:</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">;</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">(define dlopen (c-lambda (nonnull-char-string int32) (pointer void) "dlopen"))</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">(define dlerror (c-lambda () char-string "dlerror"))</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">(define dlsym (c-lambda ((pointer void) nonnull-char-string) (pointer void) "dlsym"))</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">(define dlclose (c-lambda ((pointer void)) int32 "dlclose"))</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">;; hmm is there a defconstant in scheme that we could use for these C header constants?</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">;; for now generate a function of the same name to get us the constant int value we need.</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">(define RTLD_LAZY (c-lambda () int32 "___result = RTLD_LAZY;"))</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">; declare the type of the foreign function</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">(define call_print8 (c-lambda ((pointer void)) int32 "call_plugin_print8"))</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">(let* ((h (dlopen "/home/jaten/dj/gamb/libex.so" (RTLD_LAZY)))</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> (res (dlsym h "print8")))</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> (if (null? res)</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> (error "could not locate symbol 'print8' in the plugin library!"))</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> </span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> (pretty-print (list "calling print8() gives: " (call_print8 h)))</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> (pretty-print res) </span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> (pretty-print h)</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> (pretty-print (list "The value of the constant RTLD_LAZY is: " (RTLD_LAZY))))</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">;; output:</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">;;; $ ./dlopen</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">;</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">; In print8() : returning 8</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">;8</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">;#<void* #2 0x7fdd20c1868c></span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">;#<void* #3 0x22cd7b0></span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">;("The value of the constant RTLD_LAZY is: " 1)</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">;;;;;;;;;;;;;;; file: Makefile ;;;;;;;;;;;;</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">all:</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> gsc -link dlopen.scm</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> gcc -I/usr/local/Gambit-C/include -L/usr/local/Gambit-C/lib dlopen.c dlopen_.c -lgambc -lm -lutil -ldl -o dlopen</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> g++ -c libex.cpp -fpic -o libex.o</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> g++ -shared libex.o -o libex.so</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"> @echo "testing ./dlopen"</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> ./dlopen</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">clean:</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;"> rm -f dlopen dlopen_.c dlopen.c dlopen.o1 dlopen.o2 *~ *.o *.so</span><br style="font-family: courier new,monospace;">
<br>