#
Chapter 3
Compiling Individual Files with `mzc`

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.

## 3.1 Compiling with Modules

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).

## 3.2 Compilation without Modules

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.

## 3.3 Autodetecting Compiled Files for Loading

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 `(`build-path` dir "compiled" "native" (`system-library-subpath`))` where `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 `(`load/use-compiled` "file.ss")` 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` loads `file.ss`, because `file.so` is out-of-date.

## 3.4 Compiling Multiple Files to a Single Native-Code Library

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 `(`load-extension` "_loader.so")` is a procedure that takes a symbol or `#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 `(`load-extension` "_loader.so")` multiple times returns an equivalent loader procedure each time.

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.