Next: Compiled Code Installation, Previous: Compiled Code Modules, Up: Dynamic Libraries
The most interesting application of dynamically linked libraries is probably to use them for providing compiled code modules to Scheme programs. As much fun as programming in Scheme is, every now and then comes the need to write some low-level C stuff to make Scheme even more fun.
Not only can you put these new primitives into their own module (see the previous section), you can even put them into a shared library that is only then linked to your running Guile image when it is actually needed.
An example will hopefully make everything clear. Suppose we want to
make the Bessel functions of the C library available to Scheme in the
module `(math bessel)'. First we need to write the appropriate
glue code to convert the arguments and return values of the functions
from Scheme to C and back. Additionally, we need a function that will
add them to the set of Guile primitives. Because this is just an
example, we will only implement this for the j0
function.
#include <math.h> #include <libguile.h> SCM j0_wrapper (SCM x) { return scm_double2num (j0 (scm_num2dbl (x, "j0"))); } void init_math_bessel () { scm_c_define_gsubr ("j0", 1, 0, 0, j0_wrapper); }
We can already try to bring this into action by manually calling the low
level functions for performing dynamic linking. The C source file needs
to be compiled into a shared library. Here is how to do it on
GNU/Linux, please refer to the libtool
documentation for how to
create dynamically linkable libraries portably.
gcc -shared -o libbessel.so -fPIC bessel.c
Now fire up Guile:
(define bessel-lib (dynamic-link "./libbessel.so")) (dynamic-call "init_math_bessel" bessel-lib) (j0 2) => 0.223890779141236
The filename ./libbessel.so should be pointing to the shared
library produced with the gcc
command above, of course. The
second line of the Guile interaction will call the
init_math_bessel
function which in turn will register the C
function j0_wrapper
with the Guile interpreter under the name
j0
. This function becomes immediately available and we can call
it from Scheme.
Fun, isn't it? But we are only half way there. This is what
apropos
has to say about j0
:
(apropos "j0") -| (guile-user): j0 #<primitive-procedure j0>
As you can see, j0
is contained in the root module, where all
the other Guile primitives like display
, etc live. In general,
a primitive is put into whatever module is the current module at
the time scm_c_define_gsubr
is called.
A compiled module should have a specially named module init
function. Guile knows about this special name and will call that
function automatically after having linked in the shared library. For
our example, we replace init_math_bessel
with the following code in
bessel.c:
void init_math_bessel (void *unused) { scm_c_define_gsubr ("j0", 1, 0, 0, j0_wrapper); scm_c_export ("j0", NULL); } void scm_init_math_bessel_module () { scm_c_define_module ("math bessel", init_math_bessel, NULL); }
The general pattern for the name of a module init function is: `scm_init_', followed by the name of the module where the individual hierarchical components are concatenated with underscores, followed by `_module'.
After libbessel.so has been rebuilt, we need to place the shared library into the right place.
Once the module has been correctly installed, it should be possible to use it like this:
guile> (load-extension "./libbessel.so" "scm_init_math_bessel_module") guile> (use-modules (math bessel)) guile> (j0 2) 0.223890779141236 guile> (apropos "j0") -| (math bessel): j0 #<primitive-procedure j0>
That's it!
Load and initialize the extension designated by LIB and INIT. When there is no pre-registered function for LIB/INIT, this is equivalent to
(dynamic-call INIT (dynamic-link LIB))When there is a pre-registered function, that function is called instead.
Normally, there is no pre-registered function. This option exists only for situations where dynamic linking is unavailable or unwanted. In that case, you would statically link your program with the desired library, and register its init function right after Guile has been initialized.
LIB should be a string denoting a shared library without any file type suffix such as ".so". The suffix is provided automatically. It should also not contain any directory components. Libraries that implement Guile Extensions should be put into the normal locations for shared libraries. We recommend to use the naming convention libguile-bla-blum for a extension related to a module `(bla blum)'.
The normal way for a extension to be used is to write a small Scheme file that defines a module, and to load the extension into this module. When the module is auto-loaded, the extension is loaded as well. For example,
(define-module (bla blum)) (load-extension "libguile-bla-blum" "bla_init_blum")