This section details guile-specific support in SWIG.
There are three different concepts of "module" involved, defined separately for SWIG, Guile, and Libtool. To avoid horrible confusion, we explicitly prefix the context, e.g., "guile-module".
The guile module can currently export wrapper files that use the guile GH interface or the SCM interface. This is controlled by an argument passed to swig. The "-gh" argument causes swig to output GH code, and the "-scm" argument causes swig to output SCM code. Right now the "-scm" argument is the default. The "-scm" wrapper generation assumes a guile version >= 1.6 and has several advantages over the "-gh" wrapper generation including garbage collection and GOOPS support. The "-gh" wrapper generation can be used for older versions of guile. The guile GH wrapper code generation is depreciated and the SCM interface is the default. The SCM and GH interface differ greatly in how they store pointers and have completely different run-time code. See below for more info.
The GH interface to guile is deprecated. Read more about why in the Guile manual. The idea of the GH interface was to provide a high level API that other languages and projects could adopt. This was a good idea, but didn't pan out well for general development. But for the specific, minimal uses that the SWIG typemaps put the GH interface to use is ideal for using a high level API. So even though the GH interface is depreciated, SWIG will continue to use the GH interface and provide mappings from the GH interface to whatever API we need. We can maintain this mapping where guile failed because SWIG uses a small subset of all the GH functions which map easily. All the guile typemaps like typemaps.i and std_vector.i will continue to use the GH functions to do things like create lists of values, convert strings to integers, etc. Then every language module will define a mapping between the GH interface and whatever custom API the language uses. This is currently implemented by the guile module to use the SCM guile API rather than the GH guile API. For example, here are some of the current mapping file for the SCM API
#define gh_append2(a, b) scm_append(scm_listify(a, b, SCM_UNDEFINED)) #define gh_apply(a, b) scm_apply(a, b, SCM_EOL) #define gh_bool2scm SCM_BOOL #define gh_boolean_p SCM_BOOLP #define gh_car SCM_CAR #define gh_cdr SCM_CDR #define gh_cons scm_cons #define gh_double2scm scm_make_real ...
This file is parsed by SWIG at wrapper generation time, so every reference to a gh_ function is replaced by a scm_ function in the wrapper file. Thus the gh_ function calls will never be seen in the wrapper; the wrapper will look exactly like it was generated for the specific API. Currently only the guile language module has created a mapping policy from gh_ to scm_, but there is no reason other languages (like mzscheme or chicken) couldn't also use this. If that happens, there is A LOT less code duplication in the standard typemaps.
Guile support is complicated by a lack of user community cohesiveness, which manifests in multiple shared-library usage conventions. A set of policies implementing a usage convention is called a linkage.
The default linkage is the simplest; nothing special is done. In this
case the function SWIG_init()
is exported. Simple linkage
can be used in several ways:
SWIG_init()
in the
inner_main()
function. See the "simple" and "matrix" examples under
Examples/guile
.
Dynamic module mix-in. You want to create a Guile module
using define-module
, containing both Scheme code and
bindings made by SWIG; you want to load the SWIG modules as shared
libraries into Guile.
(define-module (my module)) (define my-so (dynamic-link "./example.so")) (dynamic-call "SWIG_init" my-so) ; make SWIG bindings ;; Scheme definitions can go here
Newer Guile versions provide a shorthand for dynamic-link
and dynamic-call
:
(load-extension "./example.so" "SWIG_init")
You need to explicitly export those bindings made by SWIG that you want to import into other modules:
(export foo bar)
In this example, the procedures foo
and bar
would be exported. Alternatively, you can export all bindings with the
following module-system hack:
(module-map (lambda (sym var) (module-export! (current-module) (list sym))) (current-module))
SWIG can also generate this Scheme stub (from
define-module
up to export
)
semi-automagically if you pass it the command-line argument
-scmstub
. The code will be exported in a file called
module.scm
in the directory specified by -outdir
or the current directory if -outdir
is not specified.
Since SWIG doesn't know how
to load your extension module (with dynamic-link
or
load-extension
), you need to supply this
information by including a directive like this in the interface file:
%scheme %{ (load-extension "./example.so" "SWIG_init") %}
(The %scheme
directive allows to insert arbitrary Scheme
code into the generated file module.scm
; it is
placed between the define-module
form and the
export
form.)
If you want to include several SWIG modules, you would need to rename
SWIG_init
via a preprocessor define to avoid symbol
clashes. For this case, however, passive linkage is available.
Passive linkage is just like simple linkage, but it generates an initialization function whose name is derived from the module and package name (see below).
You should use passive linkage rather than simple linkage when you are using multiple modules.
SWIG can also generate wrapper code that does all the Guile module
declarations on its own if you pass it the -Linkage
module
command-line option. This requires Guile 1.5.0 or later.
The module name is set with the -package
and
-module
command-line options. Suppose you want to define
a module with name (my lib foo)
; then you would have to
pass the options -package my/lib -module
foo
. Note that the last part of the name can also be set
via the SWIG directive %module
.
You can use this linkage in several ways:
scm_init_my_modules_foo_module
in the inner_main()
function.
(define my-so (dynamic-link "./foo.so")) ;; create new module and put bindings there: (dynamic-call "scm_init_my_modules_foo_module" my-so)
(load-extension "./foo.so" "scm_init_my_modules_foo_module")
Guile used to support an autoloading facility for object-code
modules. This support has been marked deprecated in version 1.4.1 and
is going to disappear sooner or later. SWIG still supports building
auto-loading modules if you pass it the -Linkage ltdlmod
command-line option.
Auto-loading worked like this: Suppose a module with name (my
lib foo)
is required and not loaded yet. Guile will then search
all directories in its search path
for a Scheme file my/modules/foo.scm
or a shared library
my/modules/libfoo.so
(or
my/modules/libfoo.la
;
see the GNU libtool documentation). If a
shared library is found that contains the symbol
scm_init_my_modules_foo_module
,
the library is loaded, and the function at that symbol is called with
no arguments in order to initialize the module.
When invoked with the -Linkage ltdlmod
command-line
option, SWIG generates an exported module initialization function with
an appropriate name.
The only other linkage supported at this time creates shared object
libraries suitable for use by hobbit's (hobbit4d link)
guile module. This is called the "hobbit" linkage, and requires also
using the "-package" command line option to set the part of the module
name before the last symbol. For example, both command lines:
swig -guile -package my/lib foo.i swig -guile -package my/lib -module foo foo.i
would create module (my lib foo)
(assuming in the first
case foo.i declares the module to be "foo"). The installed files are
my/lib/libfoo.so.X.Y.Z and friends. This scheme is still very
experimental; the (hobbit4d link) conventions are not well understood.
Underscores are converted to dashes in identifiers. Guile support may grow an option to inhibit this folding in the future, but no one has complained so far.
You can use the SWIG directives %name
and
%rename
to specify the Guile name of the wrapped
functions and variables (see CHANGES).
The Guile module handles all types via typemaps. This
information is read from Lib/guile/typemaps.i
.
Some non-standard typemap substitutions are supported:
$descriptor
expands to a type descriptor for use with
the SWIG_NewPointerObj()
and
SWIG_ConvertPtr
functions.
$*descriptor
expands to a
descriptor for the direct base type (i.e., one pointer is stripped),
whereas $basedescriptor
expands to a
descriptor for the base type (i.e., all pointers are stripped).
A function returning void
(more precisely, a function
whose out
typemap returns SCM_UNSPECIFIED
) is
treated as returning no values. In argout
typemaps, one
can use the macro GUILE_APPEND_RESULT
in order to append
a value to the list of function return values.
Multiple values can be passed up to Scheme in one of three ways:
Multiple values as lists. By default, if more than one value is to be returned, a list of the values is created and returned; to switch back to this behavior, use
%values_as_list;
Multiple values as vectors. By issuing
%values_as_vector;
vectors instead of lists will be used.
Multiple values for multiple-value continuations. This is the most elegant way. By issuing
%multiple_values;
multiple values are passed to the multiple-value
continuation, as created by call-with-values
or the
convenience macro receive
. The latter is available if you
issue (use-modules (srfi srfi-8))
. Assuming that your
divide
function
wants to return two values, a quotient and a remainder, you can write:
(receive (quotient remainder) (divide 35 17) body...)
In body
, the first result of
divide
will be bound to the variable
quotient
, and the second result to remainder
.
See also the "multivalue" example.
Constants are exported as a function that returns the value. The %feature("constasvar") can be applied to any constant, immutable variable, or enum. Instead of exporting the constant as a function that must be called, the constant will appear as a scheme variable. See Features and the %feature directive for info on how to apply the %feature.
For pointer types, SWIG uses Guile smobs. SWIG smobs print
like this: #<swig struct xyzzy * 0x1234affe>
Two of
them are equal?
if and only if they have the same type
and value.
To construct a Scheme object from a C pointer, the wrapper code calls
the function SWIG_NewPointerObj()
, passing a pointer to a
struct representing the pointer type. The type index to store in the
upper half of the CAR is read from this struct.
To get the pointer represented by a smob, the wrapper code calls the
function SWIG_ConvertPtr()
, passing a pointer to a struct
representing the expected pointer type. See also
The run-time type checker.
If the Scheme object passed was not a SWIG smob representing a compatible
pointer, a wrong-type-arg
exception is raised.
In earlier versions of SWIG, C pointers were represented as Scheme strings containing a hexadecimal rendering of the pointer value and a mangled type name. As Guile allows registering user types, so-called "smobs" (small objects), a much cleaner representation has been implemented now. The details will be discussed in the following.
A smob is a cons cell where the lower half of the CAR contains the smob type tag, while the upper half of the CAR and the whole CDR are available. Every module creates its own smob type in the clientdata field of the module. So the lower 16 bits of the car of the smob store the tag and the upper 16 bits store the index this type is in the array. We can then, given a smob, find its swig_type_info struct by using the tag (lower 16 bits of car) to find which module this type is in (since each tag is unique for the module). Then we use the upper 16 bits to index into the array of types attached to this module. Looking up the module from the tag is worst case O(# of modules) but average case O(1). This is because the modules are stored in a circularly linked list, and when we start searching the modules for the tag, we start looking with the module that the function doing the lookup is in. SWIG_Guile_ConvertPtr() takes as its first argument the swig_module_info * of the calling function, which is where we start comparing tags. Most types will be looked up in the same module that created them, so the first module we check will most likely be correct. Once we have a swig_type_info structure, we loop through the linked list of casts, using pointer comparisons.
The SCM interface (using the "-scm" argument to swig) uses swigrun.swg. The whole type system, when it is first initialized, creates two smobs named "swig" and "collected_swig". The swig smob is used for non-garbage collected smobs, while the collected_swig smob is used as described below. Each smob has the same format, which is a double cell created by SCM_NEWSMOB2() The first word of data is the pointer to the object and the second word of data is the swig_type_info * structure describing this type. This is a lot easier than the GH interface above because we can store a pointer to the type info structure right in the type. With the GH interface, there was not enough room in the smob to store two whole words of data so we needed to store part of the "swig_type_info address" in the smob tag. If a generated GOOPS module has been loaded, smobs will be wrapped by the corresponding GOOPS class.
Garbage collection is a feature of the new SCM interface, and it is automatically included if you pass the "-scm" flag to swig. Thus the swig garbage collection support requires guile >1.6. Garbage collection works like this. Every swig_type_info structure stores in its clientdata field a pointer to the destructor for this type. The destructor is the generated wrapper around the delete function. So swig still exports a wrapper for the destructor, it just does not call scm_c_define_gsubr() for the wrapped delete function. So the only way to delete an object is from the garbage collector, since the delete function is not available to scripts. How swig determines if a type should be garbage collected is exactly like described in Object ownership and %newobject in the SWIG manual. All typemaps use an $owner var, and the guile module replaces $owner with 0 or 1 depending on feature:new.
SWIG code calls scm_error
on exception, using the following
mapping:
MAP(SWIG_MemoryError, "swig-memory-error"); MAP(SWIG_IOError, "swig-io-error"); MAP(SWIG_RuntimeError, "swig-runtime-error"); MAP(SWIG_IndexError, "swig-index-error"); MAP(SWIG_TypeError, "swig-type-error"); MAP(SWIG_DivisionByZero, "swig-division-by-zero"); MAP(SWIG_OverflowError, "swig-overflow-error"); MAP(SWIG_SyntaxError, "swig-syntax-error"); MAP(SWIG_ValueError, "swig-value-error"); MAP(SWIG_SystemError, "swig-system-error");
The default when not specified here is to use "swig-error". See Lib/exception.i for details.
If invoked with the command-line option -procdoc
file
, SWIG creates documentation strings for the
generated wrapper functions, describing the procedure signature and
return value, and writes them to file. You need Guile 1.4
or later to make use of the documentation files.
SWIG can generate documentation strings in three formats, which are
selected via the command-line option -procdocformat
format
:
guile-1.4
(default): Generates a format suitable for Guile 1.4.
plain
: Generates a format suitable for Guile 1.4.1 and
later.
texinfo
: Generates texinfo source, which must be run
through texinfo in order to get a format suitable for Guile 1.4.1 and
later.
You need to register the generated documentation file with Guile like this:
(use-modules (ice-9 documentation)) (set! documentation-files (cons "file" documentation-files))
Documentation strings can be configured using the Guile-specific
typemap argument doc
. See Lib/guile/typemaps.i
for
details.
For global variables, SWIG creates a single wrapper procedure
(variable :optional value)
, which is used for
both getting and setting the value. For struct members, SWIG creates
two wrapper procedures (struct-member-get
pointer)
and (struct-member-set pointer value)
.
If invoked with the command-line option -emit-setters
(recommended),
SWIG will additionally create procedures with setters. For global
variables, the procedure-with-setter variable
is created, so you can use (variable)
to get
the value and (set! (variable)
value)
to set it. For struct members, the
procedure-with-setter struct-member
is created, so you can use (struct-member
pointer)
to get the value and (set!
(struct-member pointer)
value)
to set it.
If invoked with the command-line option -only-setters
,
SWIG will only create procedures with setters, i.e., for
struct members, the procedures (struct-member-get
pointer)
and (struct-member-set pointer
value)
are not generated.
SWIG can also generate classes and generic functions for use with Guile's Object-Oriented Programming System (GOOPS). GOOPS is a sophisticated object system in the spirit of the Common Lisp Object System (CLOS).
GOOPS support is
only available with the new SCM interface (enabled with the
-scm
command-line option of SWIG). To enable GOOPS
support, pass the -proxy
argument to
swig. This will export the GOOPS wrapper definitions into the
module.scm
file in the directory specified by -outdir or the
current directory. GOOPS support requires either passive or module linkage.
The generated file will contain definitions of GOOPS classes mimicking the C++ class hierarchy.
Enabling GOOPS support implies -emit-setters
.
If -emit-slot-accessors
is also passed as an argument,
then the generated file will contain accessor methods for all the
slots in the classes and for global variables. The input class
class Foo { public: Foo(int i) : a(i) {} int a; int getMultBy(int i) { return a * i; } Foo getFooMultBy(int i) { return Foo(a * i); } }; Foo getFooPlus(int i) { return Foo(a + i); }
will produce (if -emit-slot-accessors
is not passed as a parameter)
(define-class <Foo> (<swig>) (a #:allocation #:swig-virtual #:slot-ref primitive:Foo-a-get #:slot-set! primitive:Foo-a-set) #:metaclass <swig-metaclass> #:new-function primitive:new-Foo ) (define-method (getMultBy (swig_smob <Foo>) i) (primitive:Foo-getMultBy (slot-ref swig_smob 'smob) i)) (define-method (getFooMultBy (swig_smob <Foo>) i) (make <Foo> #:init-smob (primitive:Foo-getFooMultBy (slot-ref swig_smob 'smob) i))) (define-method (getFooPlus i) (make <Foo> #:init-smob (primitive:getFooPlus i))) (export <Foo> getMultBy getFooMultBy getFooPlus )
and will produce (if -emit-slot-accessors
is passed as a parameter)
(define-class <Foo> (<swig>) (a #:allocation #:swig-virtual #:slot-ref primitive:Foo-a-get #:slot-set! primitive:Foo-a-set #:accessor a) #:metaclass <swig-metaclass> #:new-function primitive:new-Foo ) (define-method (getMultBy (swig_smob <Foo>) i) (primitive:Foo-getMultBy (slot-ref swig_smob 'smob) i)) (define-method (getFooMultBy (swig_smob <Foo>) i) (make <Foo> #:init-smob (primitive:Foo-getFooMultBy (slot-ref swig_smob 'smob) i))) (define-method (getFooPlus i) (make <Foo> #:init-smob (primitive:getFooPlus i))) (export <Foo> a getMultBy getFooMultBy getFooPlus )
which can then be used by this code
;; not using getters and setters (define foo (make <Foo> #:args '(45))) (slot-ref foo 'a) (slot-set! foo 'a 3) (getMultBy foo 4) (define foo2 (getFooMultBy foo 7)) (slot-ref foo 'a) (slot-ref (getFooPlus foo 4) 'a) ;; using getters and setters (define foo (make <Foo> #:args '(45))) (a foo) (set! (a foo) 5) (getMultBy foo 4) (a (getFooMultBy foo 7))
Notice that constructor arguments are passed as a list after the #:args
keyword. Hopefully in
the future the following will be valid (make <Foo> #:a 5 #:b 4)
Also note that the order the declarations occur in the .i file make a difference. For example,
%module test %{ #include "foo.h" %} %inline %{ int someFunc(Foo &a) { ... } %} %include "foo.h"
This is a valid SWIG file it will work as you think it will for primitive support, but the generated
GOOPS file will be broken. Since the someFunc
definition is parsed by SWIG before all the
declarations in foo.h, the generated GOOPS file will contain the definition of someFunc()
before the definition of <Foo>. The generated GOOPS file would look like
;;... (define-method (someFunc (swig_smob <Foo>)) (primitive:someFunc (slot-ref swig_smob 'smob))) ;;... (define-class <Foo> (<swig>) ;;... ) ;;...
Notice that <Foo> is used before it is defined. The fix is to just put the
%import "foo.h"
before the %inline
block.
As you can see in the example above, there are potential naming conflicts. The default exported
accessor for the Foo::a
variable is named a
. The name of the wrapper global
function is getFooPlus
.
If the -useclassprefix
option is passed to swig, the name of all accessors and member
functions will be prepended with the class name. So the accessor will be called Foo-a
and
the member functions will be called Foo-getMultBy
. Also, if the
-goopsprefix goops:
argument is passed to swig, every identifier will be prefixed by
goops:
Two guile-modules are created by SWIG. The first module contains the primitive definitions
of all the wrapped functions and variables, and is located either in the _wrap.cxx file (with -Linkage
module
) or in the scmstub file (if -Linkage passive -scmstub
). The name of this
guile-module is the swig-module name (given on the command line with the -module argument or with the
%module directive) concatenated with the string "-primitive". For
example, if %module Test
is set in the swig interface file, the name of the guile-module in
the scmstub or -Linkage module
will be Test-primitive
. Also, the scmstub
file will be named Test-primitive.scm
.
The string "primitive" can be changed by the -primsuffix
swig
argument. So the same interface, with the -primsuffix base
will produce a module called
Test-base
.
The second generated guile-module contains all the GOOPS class definitions and is located in
a file named module.scm in the directory specified with -outdir or the current directory.
The name of this guile-module is the name of the
swig-module (given on the command line or with the %module
directive).
In the previous example, the GOOPS definitions will be in a file named Test.scm.
Because of the naming conflicts, you can't in general use both the -primitive
and the GOOPS
guile-modules at the same time. To do this, you need to rename the exported symbols from one or both
guile-modules. For example,
(use-modules ((Test-primitive) #:renamer (symbol-prefix-proc 'primitive:))) (use-modules ((Test) #:renamer (symbol-prefix-proc 'goops:)))
The guile-modules generated above all need to be linked together. GOOPS support requires
either passive or module linkage. The exported GOOPS guile-module will be the name of the swig-module
and should be located in a file called Module.scm. This should be installed on the autoload
path for guile, so that (use-modules (Package Module))
will load everything needed.
Thus, the top of the GOOPS guile-module will contain code to load everything needed by the interface
(the shared library, the scmstub module, etc.).
The %goops
directive inserts arbitrary code into the generated GOOPS guile-module, and
should be used to load the dependent libraries.
This breaks up into three cases
-exportprimitive
option is passed to SWIG the
(export ...)
code that would be exported into the scmstub file is exported at the bottom
of the generated GOOPS guile-module.
The %goops
directive should contain code to load the .so library.
%goops %{ (load-extension "./foo.so" "scm_init_my_modules_foo_module") %}
Produces the following code at the top of the generated GOOPS guile-module
(with the -package my/modules -module foo
command line arguments)
(define-module (my modules foo)) ;; %goops directive goes here (load-extension "./foo.so" "scm_init_my_modules_foo_module") (use-modules (oop goops) (Swig common))
Passive Linkage with -scmstub: Here, the name of the scmstub file should be
Module-primitive.scm
(with primitive replaced with whatever is given with the -primsuffix
argument. The code to load the .so
library should be located in the %scheme
directive,
which will then be added to the scmstub file.
SWIG will automatically generate the line (use-modules (Package Module-primitive))
into the GOOPS guile-module. So if Module-primitive.scm is on the autoload path for guile, the
%goops
directive can be empty. Otherwise, the %goops
directive should contain
whatever code is needed to load the Module-primitive.scm file into guile.
%scheme %{ (load-extension "./foo.so" "scm_init_my_modules_foo_module") %} // only include the following definition if (my modules foo) cannot // be loaded automatically %goops %{ (primitive-load "/path/to/foo-primitive.scm") (primitive-load "/path/to/Swig/common.scm") %}
Produces the following code at the top of the generated GOOPS guile-module
(define-module (my modules foo)) ;; %goops directive goes here (if any) (primitive-load "/path/to/foo-primitive.scm") (primitive-load "/path/to/Swig/common.scm") (use-modules (oop goops) (Swig common)) (use-modules ((my modules foo-primitive) :renamer (symbol-prefix-proc 'primitive:)))
Module Linkage: This is very similar to passive linkage with a scmstub file.
SWIG will also automatically generate the line (use-modules
(Package Module-primitive))
into the GOOPS guile-module. Again the %goops
directive should contain whatever code is needed to get that module loaded into guile.
%goops %{ (load-extension "./foo.so" "scm_init_my_modules_foo_module") %}
Produces the following code at the top of the generated GOOPS guile-module
(define-module (my modules foo)) ;; %goops directive goes here (if any) (load-extension "./foo.so" "scm_init_my_modules_foo_module") (use-modules (oop goops) (Swig common)) (use-modules ((my modules foo-primitive) :renamer (symbol-prefix-proc 'primitive:)))
(Swig common): The generated GOOPS guile-module also imports definitions from the
(Swig common) guile-module.
This module is included with SWIG and should be installed by SWIG into the autoload path for
guile (based on the configure script and whatever arguments are passed). If it is not, then the
%goops
directive also needs to contain code to load the common.scm
file
into guile. Also note that if you are trying to install the generated wrappers on a computer without
SWIG installed, you will need to include the common.swg file along with the install.
Multiple Modules: Type dependencies between modules is supported. For example, if
mod1
includes definitions of some classes, and mod2
includes some classes
derived from classes in mod1
, the generated GOOPS file for mod2
will declare
the correct superclasses. The only problem is that since mod2
uses symbols from
mod1
, the mod2
GOOPS file must include a (use-modules (mod2))
.
Currently, SWIG does not automatically export this line; it must be included in the %goops
directive of mod2
. Maybe in the future SWIG can detect dependencies and export this line.
(how do other language modules handle this problem?)