1#lang scribble/doc
2@(require "utils.rkt")
3
4@bc-title[#:tag "Writing Racket Extensions"]{Writing Racket Extensions}
5
6@section-index["extending Racket"]
7
8As noted in @secref["embedding-and-extending"], writing Racket code
9and using the @seclink["top" #:doc '(lib
10"scribblings/foreign/foreign.scrbl")]{foreign-function interface} is
11usually a better option than writing an extension to Racket, but
12Racket also supports C-implemented extensions that plug more directly
13into the run-time system.
14(Racket CS does not have a similar extension interface.)
15
16The process of creating an extension for Racket 3m or Racket CGC (see
17@secref["CGC versus 3m"]) is essentially the same, but the process for
183m is most easily understood as a variant of the process for CGC.
19
20@section{CGC Extensions}
21
22
23To write a C/C++-based extension for Racket CGC, follow these
24steps:
25
26@itemize[
27
28 @item{@index['("header files")]{For} each C/C++ file that uses
29 Racket library functions, @cpp{#include} the file
30 @as-index{@filepath{escheme.h}}.
31
32 This file is distributed with the Racket software in an
33 @filepath{include} directory, but if @|mzc| is used to
34 compile, this path is found automatically.}
35
36
37 @item{Define the C function @cppi{scheme_initialize}, which takes a
38 @cpp{Scheme_Env*} namespace (see @secref["im:env"]) and returns a
39 @cpp{Scheme_Object*} Racket value.
40
41 This initialization function can install new global primitive
42 procedures or other values into the namespace, or it can simply
43 return a Racket value. The initialization function is called when the
44 extension is loaded with @racket[load-extension] the first time in a
45 given @|tech-place|; the return value from @cpp{scheme_initialize} is used
46 as the return value for @racket[load-extension]. The namespace
47 provided to @cpp{scheme_initialize} is the current namespace when
48 @racket[load-extension] is called.}
49
50
51 @item{Define the C function @cppi{scheme_reload}, which has the same
52 arguments and return type as @cpp{scheme_initialize}.
53
54 This function is called if @racket[load-extension] is called a second
55 time (or more times) for an extension in a given @|tech-place|. Like
56 @cpp{scheme_initialize}, the return value from this function is the
57 return value for @racket[load-extension].}
58
59
60 @item{Define the C function @cppi{scheme_module_name}, which takes
61 no arguments and returns a @cpp{Scheme_Object*} value, either a
62 symbol or @cpp{scheme_false}.
63
64 The function should return a symbol when the effect of calling
65 @cpp{scheme_initialize} and @cpp{scheme_reload} is only to declare
66 a module with the returned name. This function is called when the
67 extension is loaded to satisfy a @racket[require] declaration.
68
69 The @cpp{scheme_module_name} function may be called before
70 @cpp{scheme_initialize} and @cpp{scheme_reload}, after those
71 functions, or both before and after, depending on how the extension
72 is loaded and re-loaded.}
73
74
75 @item{Compile the extension C/C++ files to create platform-specific
76 object files.
77
78 The @as-index{@|mzc|} compiler, which is distributed with Racket,
79 compiles plain C files when the @as-index{@DFlag{cc}} flag is
80 specified. More precisely, @|mzc| does not compile the files itself,
81 but it locates a C compiler on the system and launches it with the
82 appropriate compilation flags.  If the platform is a relatively
83 standard Unix system, a Windows system with either Microsoft's C
84 compiler or @exec{gcc} in the path, or a Mac OS system with Apple's
85 developer tools installed, then using @|mzc| is typically easier than
86 working with the C compiler directly. Use the @as-index{@DFlag{cgc}}
87 flag to indicate that the build is for use with Racket CGC.}
88
89
90 @item{Link the extension C/C++ files with
91 @as-index{@filepath{mzdyn.o}} (Unix, Mac OS) or
92 @as-index{@filepath{mzdyn.obj}} (Windows) to create a shared object. The
93 resulting shared object should use the extension @filepath{.so} (Unix),
94 @filepath{.dll} (Windows), or @filepath{.dylib} (Mac OS).
95
96 The @filepath{mzdyn} object file is distributed in the installation's
97 @filepath{lib} directory. For Windows, the object file is in a
98 compiler-specific sub-directory of @filepath{racket\lib}.
99
100 The @|mzc| compiler links object files into an extension when the
101 @as-index{@DFlag{ld}} flag is specified, automatically locating
102 @filepath{mzdyn}. Again, use the @DFlag{cgc} flag with @|mzc|.}
103
104 @item{Load the shared object within Racket using
105 @racket[(load-extension _path)], where @racket[_path] is the name of
106 the extension file generated in the previous step.
107
108 Alternately, if the extension defines a module (i.e.,
109 @cpp{scheme_module_name} returns a symbol), then place the shared
110 object in a special directory with a special name, so that it is
111 detected by the module loader when @racket[require] is used. The
112 special directory is a platform-specific path that can be obtained by
113 evaluating @racket[(build-path "compiled" "native"
114 (system-library-subpath))]; see @racket[load/use-compiled] for more
115 information.  For example, if the shared object's name is
116 @filepath{example_rkt.dll}, then @racket[(require "example.rkt")] will
117 be redirected to @filepath{example_rkt.dll} if the latter is placed in
118 the sub-directory @racket[(build-path "compiled" "native"
119 (system-library-subpath))] and if @filepath{example.rkt} does not
120 exist or has an earlier timestamp.
121
122 Note that @racket[(load-extension _path)] within a @racket[module]
123 does @italic{not} introduce the extension's definitions into the
124 module, because @racket[load-extension] is a run-time operation. To
125 introduce an extension's bindings into a module, make sure that the
126 extension defines a module, put the extension in the
127 platform-specific location as described above, and use
128 @racket[require].}
129
130]
131
132@index['("allocation")]{@bold{IMPORTANT:}} With Racket CGC, Racket
133values are garbage collected using a conservative garbage collector,
134so pointers to Racket objects can be kept in registers, stack
135variables, or structures allocated with @cppi{scheme_malloc}. However,
136static variables that contain pointers to collectable memory must be
137registered using @cppi{scheme_register_extension_global} (see
138@secref["im:memoryalloc"]); even then, such static variables must be
139thread-local (in the OS-thread sense) to work with multiple
140@|tech-place|s (see @secref["places"]).
141
142As an example, the following C code defines an extension that returns
143@racket["hello world"] when it is loaded:
144
145@verbatim[#:indent 2]{
146 #include "escheme.h"
147 Scheme_Object *scheme_initialize(Scheme_Env *env) {
148   return scheme_make_utf8_string("hello world");
149 }
150 Scheme_Object *scheme_reload(Scheme_Env *env) {
151   return scheme_initialize(env); /* Nothing special for reload */
152 }
153 Scheme_Object *scheme_module_name() {
154   return scheme_false;
155 }
156}
157
158Assuming that this code is in the file @filepath{hw.c}, the extension
159is compiled on Unix with the following two commands:
160
161@commandline{raco ctool --cgc --cc hw.c}
162@commandline{raco ctool --cgc --ld hw.so hw.o}
163
164(Note that the @DFlag{cgc}, @DFlag{cc}, and @DFlag{ld} flags are each
165prefixed by two dashes, not one.)
166
167The @filepath{collects/mzscheme/examples} directory in the Racket
168distribution contains additional examples.
169
170@section{3m Extensions}
171
172To build an extension to work with Racket 3m, the CGC instructions
173must be extended as follows:
174
175@itemize[
176
177 @item{Adjust code to cooperate with the garbage collector as
178 described in @secref["im:3m"]. Using @|mzc| with the
179 @as-index{@DFlag{xform}} might convert your code to implement part of
180 the conversion, as described in @secref["im:3m:mzc"].}
181
182 @item{In either your source in the in compiler command line,
183 @cpp{#define} @cpp{MZ_PRECISE_GC} before including
184 @filepath{escheme.h}. When using @|mzc| with the @DFlag{cc} and
185 @as-index{@DFlag{3m}} flags, @cpp{MZ_PRECISE_GC} is automatically
186 defined.}
187
188 @item{Link with @as-index{@filepath{mzdyn3m.o}} (Unix, Mac OS) or
189 @as-index{@filepath{mzdyn3m.obj}} (Windows) to create a shared
190 object.  When using @|mzc|, use the @DFlag{ld} and @DFlag{3m} flags
191 to link to these libraries.}
192
193]
194
195For a relatively simple extension @filepath{hw.c}, the extension is
196compiled on Unix for 3m with the following three commands:
197
198@commandline{raco ctool --xform hw.c}
199@commandline{raco ctool --3m --cc hw.3m.c}
200@commandline{raco ctool --3m --ld hw.so hw_3m.o}
201
202Some examples in @filepath{collects/mzscheme/examples} work with
203Racket 3m in this way. A few examples are manually instrumented, in
204which case the @DFlag{xform} step should be skipped.
205
206@section{Declaring a Module in an Extension}
207
208To create an extension that behaves as a module, return a symbol from
209@cpp{scheme_module_name}, and have @cpp{scheme_initialize} and
210@cpp{scheme_reload} declare a module using @cpp{scheme_primitive_module}.
211
212For example, the following extension implements a module named
213@racket[hi] that exports a binding @racket[greeting]:
214
215@verbatim[#:indent 2]{
216  #include "escheme.h"
217
218  Scheme_Object *scheme_initialize(Scheme_Env *env) {
219    Scheme_Env *mod_env;
220    mod_env = scheme_primitive_module(scheme_intern_symbol("hi"),
221                                      env);
222    scheme_add_global("greeting",
223                      scheme_make_utf8_string("hello"),
224                      mod_env);
225    scheme_finish_primitive_module(mod_env);
226    return scheme_void;
227  }
228
229  Scheme_Object *scheme_reload(Scheme_Env *env) {
230    return scheme_initialize(env); /* Nothing special for reload */
231  }
232
233  Scheme_Object *scheme_module_name() {
234    return scheme_intern_symbol("hi");
235  }
236}
237
238This extension could be compiled for 3m on i386 Linux, for
239example, using the following sequence of @exec{mzc} commands:
240
241@commandline{raco ctool --xform hi.c}
242@commandline{raco ctool --3m --cc hi.3m.c}
243@commandline{mkdir -p compiled/native/i386-linux/3m}
244@commandline{raco ctool --3m --ld compiled/native/i386-linux/3m/hi_rkt.so hi_3m.o}
245
246The resulting module can be loaded with
247
248@racketblock[(require "hi.rkt")]
249
250@; ----------------------------------------------------------------------
251
252