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
.
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
where 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 wrapper 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.