Next: , Previous: Calling C functions from Scheme, Up: C interface


7.4 Dynamic loading of C modules

External code can be loaded into a running Scheme48 on most Unices and on Windows. Such external code must be stored in shared objects; see below on details of the C side. The relevant Scheme procedures are available in the load-dynamic-external structure:

— procedure: load-dynamic-externals filename add-file-type? reload-on-repeat? reload-on-resume? –> dynamic-externals
— procedure: import-dynamic-externals filename –> dynamic-externals
— procedure: unload-dynamic-externals dynamic-externals –> unspecified

Load-dynamic-external loads a shared object from filename, with an appropriate file type appended if add-file-type? is true (.so on Unix and .dll on Windows), and returns a dynamic externals object representing the loaded shared object. If the shared object was already loaded, then if reload-on-repeat? is true, it is reloaded; otherwise, the load-dynamic-externals call has no effect. If the dynamic externals descriptor is stored in a dumped heap image, when that heap image is resumed, if reload-on-resume? is true, the shared object corresponding with that dynamic external descriptor is reloaded. Unload-dynamic-externals unloads the given dynamic externals object.

Import-dynamic-externals is a convenient wrapper for the common case of load-dynamic-externals; it is equivalent to (load-dynamic-externals #t #f #t), i.e. it will append a file type, it will not reload the shared object if it was already loaded, and the shared object will be loaded if part of a resumed heap image.

— procedure: reload-dynamic-externals filename –> unspecified

Reloads the shared object named by filename. This is intended as an interactive utility, which is why it accepts the filename of the shared object and not a dynamic externals descriptor.

Shared objects intended to be loaded into Scheme48 must define two functions:

— C function: void s48_on_load (void)
— C function: void s48_on_reload (void)

s48_on_load is called when the shared object is initially loaded by Scheme48. It typically consists of a number of invocations of S48_EXPORT_FUNCTION to make C functions available to Scheme48 code. s48_on_reload is called when the shared object is reloaded after it has been initially loaded once; it typically just calls s48_on_load, but it may perform other reinitializations.

On Linux, the following commands compile the C source file foo.c into a shared object foo.so that can be loaded dynamically by Scheme48:

     % gcc -c -o foo.o foo.c
     % ld -shared -o foo.so foo.o

7.4.1 Old dynamic loading interface

The old dynamic-externals structures, which exported dynamic-load, get-external, lookup-external, lookup-all-externals, external?, external-name, external-value, and call-external, is still supported, but it will not work on Windows, its use is deprecated, and it is likely to vanish in a future release. The old documentation is preserved to aid updating of old code:

On architectures that support it, external code can be loaded into a running Scheme48 process, and C object file bindings can be accessed at runtime & their values called. These Scheme procedures are exported by the structure dynamic-externals.

In some Unices, retrieving a value from the current process may require a non-trivial amount of computation. We recommend that a dynamically loaded file contain a single initialization function that creates shared bindings for the values exported by the file.

— Scheme procedure: dynamic-load string –> unspecified

Loads the filename named by string into the current process. An exception is raised if the file cannot be found or if dynamic loading is not supported by the host operating system. The file must have been compiled & linked appropriately. For Linux, for example, the following commands compile foo.c into a file foo.so that can be loaded dynamically:

          % gcc -c -o foo.o foo.c
          % ld -shared -o foo.so foo.o
— Scheme procedure: get-external string –> external
— Scheme procedure: external? object –> boolean
— Scheme procedure: external-name external –> string
— Scheme procedure: external-value external –> byte-vector

These procedures access external values bound in the current process. Get-external returns a external object that contains the value of the C binding with the name string. It signals a warning if there is no such binding in the current process. External? is the disjoint type predicate for externals, and external-name & external-value return the name & value of an external. The value is represented as a byte vector of length four on 32-bit architectures. The value is that of the C binding from when get-external (or lookup-external, as described below) was called.

— Scheme procedure: lookup-external external –> boolean
— Scheme procedure: lookup-all-externals –> boolean

Lookup-external updates the value of external by looking up its binding in the current process. It returns #t if the external is bound and #f if not. Lookup-all-externals calls lookup-external on all externals in the current Scheme48 image. It returns #t if all were bound and #f if there was at least one unbound external.

— Scheme procedure: call-external external argument ... –> value

Calls the C function pointed to by external with the given arguments, and returns the value that the C function returned. This is like call-imported-binding and call-external-value except that the function argument is represented as an external, not as an imported binding or byte vector containing a pointer. For more details, see Calling C functions from Scheme.