To compile an individual file with mzc, provide the file name as the command line argument to mzc. To compile to byte code, use the -z or --zo flag; to compile to native code, use the -e or --extension flag. If no compilation mode flag is specified, --extension is assumed.
The input file must have a file extension that designates it as a Scheme file, either .ss or .scm. The output file will have the same base name and same directory (by default) as the input file, but with an extension appropriate to the type of the output file (either .zo, .dll, or .so).
Example:
mzc --extension file.ss
Under Windows, the above command reads file.ss from the current directory and produces file.dll in the current directory.
Multiple Scheme files can be specified for compilation at once. A separate compiled file is produced for each Scheme file. By default, each compiled file is placed in the directory containing the corresponding input file. When multiple files are compiled at once, macros defined in a file are visible in the files that are compiled afterwards.
In terms of both optimization and proper loading of syntax
definitions, mzc works best with programs that are encapulated
within per-file module
expressions. Using a single
module
expression in a file eliminates the code's dependence
on the top-level environment. Consequently, all dependencies of the
code on loadable syntax extensions are evident to the compiler.
When compiling a module that require
s another module (that is
not built into MzScheme), mzc loads the required module, but does
not invoke it. Instead, mzc uses the loaded module only for its
syntax exports, if any (which means that mzc executes the
transformer code in the module, but not any of its normal code).
Top-level define-syntax
(es
), module
,
require
, require-for-syntax
, and begin
expressions are handled specially by mzc: the compile-time portion
of the expression is evaluated, because it might affects later
expressions.2 For example, when compiling the file
containing
(require (lib "etc.ss")) (define f (opt-lambda (a [b 7]) (+ a b)))
the opt-lambda
syntax from the "etc.ss"
library must be
bound in the compilation namespace at compile time. Thus, the
require
expression is both compiled (to appear in the output
code) and evaluated (for further computation).
Many definition forms expand to define-syntax
. For example,
define-signature
expands to a define-syntax
definition. mzc detects define-syntax
and other expressions
after expansion, so top-level define-signature
expressions
affect the compilation of later expressions, as a programmer would
expect.
In contrast, a load
or eval
expression in a source
file is compiled -- but not evaluated! -- as the source file is
compiled. Even if the load
expression loads syntax or
signature definitions, these will not be loaded as the file is
compiled. The same is true of application expressions that affect the
reader, such as (
.read-case-sensitive
#t)
mzc's -p or --prefix flag takes a file and
loads it before compiling the source files specified on the command
line. In general, a better solution is to put all compiled code into
module
expressions, as explained in section 3.1.
Note that MzScheme provides no eval-when
form for
controlling the evaluation of compiled code, because module
provides a simpler and more consistent interface for separating
compile-time and run-time code.
When MzScheme's load/use-compiled
, load-relative
, or
require
is used to load a file, MzScheme automatically detects
an alternate byte-code and/or native-code file that resides near the
requested file. Byte-code files are found in a compiled
subdirectory in the directory of the requested file. Native-code
files are found in (
where build-path
dir "compiled" "native"
(system-library-subpath
))dir
is the directory of the
requested file. A byte-code or native-code file is used in place of
the requested file only if its modification date is later than the
requested file, or if the requested file does not exist. If both
byte-code and native-code files can be loaded, the native-code file
is loaded.
Example:
mzc --extension --destination compiled/native/i386-linux file.ss
Under Linux, the above command compiles file.ss in the current
directory and produces compiled/native/i386-linux/file.so.
Evaluating (
in MzScheme will then
load compiled/native/i386-linux/file.so instead of
file.ss. If file.ss is changed without recreating
file.so, then load/use-compiled
"file.ss")load/use-compiled
loads file.ss,
because file.so is out-of-date.
When the -o or --object flag is provided to mzc, .kp and .o/.obj files are produced instead of a loadable library. The .o/.obj files contain the native code for a single source file. The .kp files contain information used for global optimizations.
Multiple .kp and .o/.obj files are linked into a single library using mzc with the -l or --link-extension flag. All of the .kp and .o/.obj files to be linked together are provided on the command line to mzc. The output library is always named _loader.so or _loader.dll.
Example:
mzc --object file1.ss
mzc --object file2.ss
mzc --link-extension file1.kp file1.o file2.kp file2.o
Under Unix, the above commands produce a _loader.so library that encapsulates both file1.ss and file2.ss.
Loading _loader into MzScheme is not quite the same as loading
all of the Source files that are encapsulated by _loader. The
return value from (
is a
procedure that takes a symbol or load-extension
"_loader.so")#t
. If a symbol is provided
and it is the same as the base name of a source file (i.e., the name
without a path or file extension) encapsulated by _loader,
then a thunk is returned, along with a symbol (or #f
)
indicating a module name declared by the file. Applying the thunk has
the same effect as loading the corresponding source file. If a symbol
is not recognized by the _loader procedure, #f
is
returned instead of a thunk. If #t
is provided, a thunk is
returned that ``loads'' all of the files (using the order of the
.o/.obj files provided to mzc) and returns the
result from loading the last one.
The _loader procedure can be called any number of times to
obtain thunks, and each thunk can be applied any number of times
(where each application has the same effect as loading the source
file again). Evaluating (
multiple times returns an equivalent loader procedure each time.load-extension
"_loader.so")
Given the _loader.so constructed by the example commands above, the following Scheme expressions have the same effect as loading file1.ss and file2.ss:
(let-values ([(go modname) ((load-extension
"_loader.so") 'file1)]) (go)) (let-values ([(go modname) ((load-extension
"_loader.so") 'file2)]) (go))
or, equivalently:
(let-values ([(go modname) ((load-extension
"_loader.so") #t)]) (go))
The special _loader convention is recognized by MzScheme's
load/use-compiled
, load-relative
, and
require
. MzScheme automatically detects _loader.so or
_loader.dll in the same directory as individual native-code
files (see section 3.3). If both an individual native-code
file and a _loader are available, the _loader file is
used.
2 The -m or --module flag turns off this special handling.