Actions

Difference between revisions of "Using Gambit with External Libraries"

From Gambit wiki

m
Line 1: Line 1:
 +
== Ensuring singlethreaded behaviour ==
 +
In certain situations, it's vital to ensure a single thread of execution.
 +
 +
One way may be to create one thread to which you send closures containing code to be executed, and which returns the responses through a mailbox mechanism.
 +
 +
Ways to get Gambit execute completely single-threaded is:
 +
 +
* Use (thread-quantum-set! (current-thread) +inf.0)
 +
 +
* Use (##disable-interrupts) and (##enable-interrupts) in Scheme or ___EXT(___disable_interrupts)() and ___EXT(___enable_interrupts)() from C.
 +
 +
== Export and import C symbols ==
 +
Gambit provides helper macros for exporting functions and variables. They are  ___EXPORT_FUNC(type,name) and and ___EXPORT_DATA(type,name), and are used like ___EXPORT_FUNC(int,five) () { return 5; } . Grep lib/*.c of the Gambit sources for EXP_FUNC and EXP_DATA to see examples.
 +
 +
On Windows, exporting and importing functions and variables from C code may be particularly tricky. Check  __declspec(dllexport) and __declspec(dllimport) out.
 +
 
== Using gsc to compile and link a dynamically loadable object file that uses external libraries ==
 
== Using gsc to compile and link a dynamically loadable object file that uses external libraries ==
  

Revision as of 01:22, 13 November 2008

Ensuring singlethreaded behaviour

In certain situations, it's vital to ensure a single thread of execution.

One way may be to create one thread to which you send closures containing code to be executed, and which returns the responses through a mailbox mechanism.

Ways to get Gambit execute completely single-threaded is:

  • Use (thread-quantum-set! (current-thread) +inf.0)
  • Use (##disable-interrupts) and (##enable-interrupts) in Scheme or ___EXT(___disable_interrupts)() and ___EXT(___enable_interrupts)() from C.

Export and import C symbols

Gambit provides helper macros for exporting functions and variables. They are ___EXPORT_FUNC(type,name) and and ___EXPORT_DATA(type,name), and are used like ___EXPORT_FUNC(int,five) () { return 5; } . Grep lib/*.c of the Gambit sources for EXP_FUNC and EXP_DATA to see examples.

On Windows, exporting and importing functions and variables from C code may be particularly tricky. Check __declspec(dllexport) and __declspec(dllimport) out.

Using gsc to compile and link a dynamically loadable object file that uses external libraries

Here is an example of building a dynamically loadable Gambit object file that uses FFTW. This example is on Red Hat Enterprise Linux 4.2 on x86-64.

The program uses the FFTW version 2 API, so we downloaded fftw-2.1.5.tar.gz, untarred it and configured it with

./configure --enable-shared --prefix=/export/users/lucier/local/fftw-2.1.5

You need the --enable-shared option because shared Gambit modules must be linked to shared external libraries. I set the --prefix to install the final FFTW libraries and header files in my home directory.

The file fftbasics.scm provides the basic interface between the Scheme code and FFTW; it is as follows:

(c-declare
"
#include \"fftw.h\"

fftwnd_plan p;

")

(define fftw2d_create_plan_backward
  (c-lambda ()
            void
            "p = fftw2d_create_plan(64,
                                    64,
                                    FFTW_BACKWARD,
                                    FFTW_ESTIMATE | FFTW_IN_PLACE);
            "))

(define fftw2d_create_plan_forward
  (c-lambda ()
            void
            "p = fftw2d_create_plan(64,
                                    64,
                                    FFTW_FORWARD,
                                    FFTW_ESTIMATE | FFTW_IN_PLACE);
            "))

;;; Both forward and backward ffts, depends on which way the plan was created.

(define fftwc
  (c-lambda (scheme-object)
            void
            "
int j; double *fp = (double *)((___WORD)___BODY_AS(___arg1,___tSUBTYPED));
  fftwnd_one(p,
             (fftw_complex *)(fp),
             NULL);
  for (j = 0; j < 64 * 64 * 2; j++)
    fp[j] *= .015625;
"))

We need to pass special options to gsc to compile this file, namely

gsc -cc-options "-I/export/users/lucier/local/fftw-2.1.5/include" -ld-options "-L/export/users/lucier/local/fftw-2.1.5/lib/ -Wl,-rpath,/export/users/lucier/local/fftw-2.1.5/lib/ -lfftw" fftbasic.scm

The first option (-I/export/users/lucier/local/fftw-2.1.5/include) tells gcc where to find the header file fftw.h at compile time. The second option (-L/export/users/lucier/local/fftw-2.1.5/lib/) tells the linker where to find the FFTW library (-lfftw) at link time (i.e., when building the file fftwbasic.o1 from fftwbasic.o), and the third option (-Wl,-rpath,/export/users/lucier/local/fftw-2.1.5/lib/) tells the dynamic loader ldd where to find the FFTW library when fftwbasic.o1 is loaded into gsc.

Aside: Note that if the headers and libraries are in a standard place known to gcc, and the location of the shared library is already in the path of the dynamic loader, then these options may not be necessary. In many GNU/Linux systems, for examples, nearly all packages are installed in /usr/{bin,include,lib}, and you may not need to pass these special options to gsc.

Then we can do

euler-316% gsc
Gambit v4.2.8

> (load "fftbasic")
"/export/users/lucier/programs/gambc-v4_2_8/test-load-options/fftbasic.o1"
> fftwc
#<procedure #2 fftwc>
>
*** EOF again to exit

We can check that fftbasic.o1 links to the right libraries:

euler-317% ldd fftbasic.o1
        libfftw.so.2 => /export/users/lucier/local/fftw-2.1.5/lib/libfftw.so.2 (0x0000002a9565a000)
        libc.so.6 => /lib64/tls/libc.so.6 (0x0000002a957aa000)
        libm.so.6 => /lib64/tls/libm.so.6 (0x0000002a959df000)
        /lib64/ld-linux-x86-64.so.2 (0x000000552aaaa000)

Finally, recall from the the Gambit manual that anything you can do with gsc on the command line you can do with one of the gsc-specific scheme procedures compile-file, compile-file-to-c, link-incremental, or link-flat. Thus, one could build fftbasic.o1 by

euler-352% gsc
Gambit v4.2.8

> (compile-file "fftbasic.scm" cc-options: "-I/export/users/lucier/local/fftw-2.1.5/include"
 ld-options: "-L/export/users/lucier/local/fftw-2.1.5/lib/ -Wl,-rpath,/export/users/lucier/local/fftw-2.1.5/lib/ -lfftw")
#t
> (load "fftbasic")
"/export/users/lucier/programs/gambc-v4_2_8/test-load-options/fftbasic.o1"
> fftwc
#<procedure #2 fftwc>


Practices in FFI development

(There are a couple of posts from September 2008 in the mailing list archive on this subject. Someone please cut and paste them over here.)