6.19.2 Foreign Extensions

One way to use shared libraries is to extend Guile. Such loadable modules generally define one distinguished initialization function that, when called, will use the libguile API to define procedures in the current module.

Concretely, you might extend Guile with an implementation of the Bessel function, j0:

#include <math.h>
#include <libguile.h>

SCM
j0_wrapper (SCM x)
{
  return scm_from_double (j0 (scm_to_double (x, "j0")));
}

void
init_math_bessel (void)
{
  scm_c_define_gsubr ("j0", 1, 0, 0, j0_wrapper);
}

The C source file would then need to be compiled into a shared library. On GNU/Linux, the compiler invocation might look like this:

gcc -shared -o bessel.so -fPIC bessel.c

A good default place to put shared libraries that extend Guile is into the extensions dir. From the command line or a build script, invoke pkg-config --variable=extensionsdir guile-3.0 to print the extensions dir. See Parallel Installations, for more details.

Guile can load up bessel.so via load-extension.

Scheme Procedure: load-extension lib init
C Function: scm_load_extension (lib, init)

Load and initialize the extension designated by LIB and INIT.

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 (math bessel)
  #:export (j0))

(load-extension "bessel" "init_math_bessel")

This load-extension invocation loads the bessel library via (load-foreign-library "bessel"), then looks up the init_math_bessel symbol in the library, treating it as a function of no arguments, and calls that function.

If you decide to put your extension outside the default search path for load-foreign-library, probably you should adapt the Scheme module to specify its absolute path. For example, if you use automake to build your extension and place it in $(pkglibdir), you might define a build-parameters module that gets created by the build system:

(define-module (math config)
  #:export (extensiondir))
(define extensiondir "PKGLIBDIR")

This file would be config.scm.in. You would define a make rule to substitute in the absolute installed file name:

config.scm: config.scm.in
        sed 's|PKGLIBDIR|$(pkglibdir)|' <$< >$ 

Then your (math bessel) would import (math config), then (load-extension (in-vicinity extensiondir "bessel") "init_math_bessel").

An alternate approach would be to rebind the guile-extensions-path parameter, or its corresponding environment variable, but note that changing those parameters applies to other users of load-foreign-library as well.

Note that the new primitives that the extension adds to Guile with scm_c_define_gsubr (see Primitive Procedures) or with any of the other mechanisms are placed into the module that is current when the scm_c_define_gsubr is executed, so to be clear about what goes vwhere it’s best to include the load-extension in a module, as above. Alternately, the C code can use scm_c_define_module to specify which module is being created:

static void
do_init (void *unused)
{
  scm_c_define_gsubr ("j0", 1, 0, 0, j0_wrapper);
  scm_c_export ("j0", NULL);
}

void
init_math_bessel ()
{
  scm_c_define_module ("math bessel", do_init, NULL);
}

And yet... if what we want is just the j0 function, it seems like a lot of ceremony to have to compile a Guile-specific wrapper library complete with an initialization function and wraper module to allow Guile users to call it. There is another way, but to get there, we have to talk about function pointers and function types first. See Foreign Functions, to skip to the good parts.