Writing MzScheme Extensions
To write a C/C++-based extension to MzScheme, follow these steps:
This file is distributed with the PLT software in plt/collects/mzscheme/include, but if mzc is used to compile the C files, this path is found automatically.
This initialization function can install new global primitive procedures or other values into the namespace, or it can simply return a Scheme value. The initialization function is called when the extension is loaded with load-extension (the first time); the return value from scheme_initialize is used as the return value for load-extension. The namespace provided to scheme_initialize is the current namespace when load-extension is called.
This function is called if load-extension is called a second time (or more times) for an extension. Like scheme_initialize, the return value from this function is the return value for load-extension.
The mzc compiler, distributed with MzScheme, compiles plain C files when the --cc flag is specified. Actually, mzc does not compile the files itself, but it locates a C compiler on the system and launches it with the appropriate compilation flags. If the platform is a relatively standard Unix system, a Windows system with either Microsoft's C compiler or gcc in the path, or a MacOS system with Metrowerks CodeWarrior installed, then using mzc is typically easier than working with the compiler directly.
The mzdyn object file is distributed in a platform-specific directory in plt/collects/mzscheme/lib for Unix or Windows, but it is not distributed for MacOS.
The mzc compiler links object files into an extension when the --ld flag is specified, automatically locating mzdyn. Under MacOS, mzc generates the mzdyn object file as necessary.
See also the general integration notes at the end of this section.
As an example, the following C code defines an extension that returns "hello world" when it is loaded:
#include "escheme.h" Scheme_Object *scheme_initialize(Scheme_Env *env) { return scheme_make_string("hello world"); } Scheme_Object *scheme_reload(Scheme_Env *env) { return scheme_initialize(env); /* Nothing special for reload */ }
Assuming that this code is in the file hw.c, the extension is compiled under Unix with the following two commands:
mzc --cc hw.c mzc --ld hw.so hw.o
Embedding MzScheme into a Program
To embed MzScheme in a program, first download the MzScheme source code. Then, follow these steps:
Under Unix, the libraries are libmzscheme.a and libgc.a. After compiling MzScheme and running mzmake install, the libraries are in a platform-specific directory under plt/collects/mzscheme/lib/. Under Windows and MacOS, consult the compilation instructions for information on compiling the libraries.
This file is distributed with the PLT software in plt/collects/mzscheme/include.
For example, the following is a simple embedding program which evaluates all expressions provided on the command line and displays the results:
#include "scheme.h" int main(int argc, char *argv[]) { Scheme_Env *e = scheme_basic_env(); Scheme_Object *curout = scheme_get_param(scheme_config, MZCONFIG_OUTPUT_PORT); int i; for (i = 1; i < argc; i++) { if (scheme_setjmp(scheme_error_buf)) { return -1; /* There was an error */ } else { Scheme_Object *v = scheme_eval_string(argv[i], e); scheme_display(v, curout); scheme_display(scheme_make_character('\n'), curout); } } return 0; }
General Integration Notes
Scheme values are garbage collected using a conservative garbage collector, so pointers to MzScheme objects can be kept in registers, stack variables, or structures allocated with scheme_malloc. In an extension, static variables that contain pointers to collectable memory must be registered using scheme_register_global (but registered variables need not necessarily contain a collectable pointer at all times). When MzScheme is embedded in an application, all globals are automaticaly registered.