On this page:
10.1 CGC Extensions
10.2 3m Extensions
10.3 Declaring a Module in an Extension

10 Writing Racket Extensions

As noted in Embedding and Extending Racket, writing Racket code and using the foreign-function interface is usually a better option than writing an extension to Racket, but Racket also supports C-implemented extensions that plug more directly into the run-time system. (Racket CS does not have a similar extension interface.)

The process of creating an extension for Racket 3m or Racket CGC (see CGC versus 3m) is essentially the same, but the process for 3m is most easily understood as a variant of the process for CGC.

10.1 CGC Extensions

To write a C/C++-based extension for Racket CGC, follow these steps:

IMPORTANT: With Racket CGC, Racket values are garbage collected using a conservative garbage collector, so pointers to Racket objects can be kept in registers, stack variables, or structures allocated with scheme_malloc. However, static variables that contain pointers to collectable memory must be registered using scheme_register_extension_global (see Memory Allocation); even then, such static variables must be thread-local (in the OS-thread sense) to work with multiple places (see Racket BC and Places).

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_utf8_string("hello world");

  }

  Scheme_Object *scheme_reload(Scheme_Env *env) {

    return scheme_initialize(env); /* Nothing special for reload */

  }

  Scheme_Object *scheme_module_name() {

    return scheme_false;

  }

Assuming that this code is in the file "hw.c", the extension is compiled on Unix with the following two commands:

  raco ctool --cgc --cc hw.c
  raco ctool --cgc --ld hw.so hw.o

(Note that the --cgc, --cc, and --ld flags are each prefixed by two dashes, not one.)

The "collects/mzscheme/examples" directory in the Racket distribution contains additional examples.

10.2 3m Extensions

To build an extension to work with Racket 3m, the CGC instructions must be extended as follows:

For a relatively simple extension "hw.c", the extension is compiled on Unix for 3m with the following three commands:

  raco ctool --xform hw.c
  raco ctool --3m --cc hw.3m.c
  raco ctool --3m --ld hw.so hw_3m.o

Some examples in "collects/mzscheme/examples" work with Racket 3m in this way. A few examples are manually instrumented, in which case the --xform step should be skipped.

10.3 Declaring a Module in an Extension

To create an extension that behaves as a module, return a symbol from scheme_module_name, and have scheme_initialize and scheme_reload declare a module using scheme_primitive_module.

For example, the following extension implements a module named hi that exports a binding greeting:

  #include "escheme.h"

  

  Scheme_Object *scheme_initialize(Scheme_Env *env) {

    Scheme_Env *mod_env;

    mod_env = scheme_primitive_module(scheme_intern_symbol("hi"),

                                      env);

    scheme_add_global("greeting",

                      scheme_make_utf8_string("hello"),

                      mod_env);

    scheme_finish_primitive_module(mod_env);

    return scheme_void;

  }

  

  Scheme_Object *scheme_reload(Scheme_Env *env) {

    return scheme_initialize(env); /* Nothing special for reload */

  }

  

  Scheme_Object *scheme_module_name() {

    return scheme_intern_symbol("hi");

  }

This extension could be compiled for 3m on i386 Linux, for example, using the following sequence of mzc commands:

  raco ctool --xform hi.c
  raco ctool --3m --cc hi.3m.c
  mkdir -p compiled/native/i386-linux/3m
  raco ctool --3m --ld compiled/native/i386-linux/3m/hi_rkt.so hi_3m.o

The resulting module can be loaded with

(require "hi.rkt")