Building and Distributing Stand-alone Executables
For all compilation modes, the output of mzc relies on MzScheme (and MrEd) to provide run-time support to the compiled code. However, mzc can also package code together with its run-time support to form an executable that works on the source machine or a package that can be distributed to other machines.
5.1 Stand-Alone Executables from Scheme Code
The command-line flag --exe directs mzc to embed a module (from source or byte code) into a copy of the MzScheme executable. (Under Unix, the embedding executable is actually a copy of a wrapper executable.) The created executable invokes the embedded module on startup. The --gui-exe flag is similar, but it copies the MrEd executable.
If the embedded module refers statically (i.e., through
require
) to modules in MzLib or other collections, then
those modules are also included in the embedding executable.
Library modules or other files that are referenced
dynamically -- through
, eval
, or
load
-- are not automatically embedded into the
created executable. Such modules can be explicitly included using
mzc's --lib flag. Alternately, use the forms of the
runtime-path.ss MzLib library to embed references to the
run-time files in the executable; the files are then copied and
packaged together with the executable when creating a distribution
(as described in the following section).dynamic-require
Modules that are implemented directly by extensions -- i.e.,
extensions that are automatically loaded from (
to satisfy a
build-path
"compiled" "native" (system-library-subpath
))require
-- are treated like other run-time files: a
generated executable uses them from their original location, and they
are copied and packaged together when creating a distribution.
The --exe and --gui-exe flags work only with
module
-based programs. The embed.ss library in the
compiler collection provides a more general interface to the
embedding mechanism.
Example:
mzc --gui-exe hello hello.ss
Under Windows, this command produces hello.exe, which runs the same as invoking the hello.ss module. Under Mac OS X, the resulting executable is an application hello.app.
A stand-alone executable is ``stand-alone'' in the sense that you can run it without starting MzScheme, MrEd, or DrScheme. However, the executable depends on MzScheme and/or MrEd shared libraries, and possibly other run-time files declared via runtime-path.ss. The executable can be packaged with support libraries to create a distribution, as described in the following section.
5.2 Distributing Stand-Alone Executables
The command-line flag --exe-dir directs mzc to combine a stand-alone executable (created via --exe or --gui-exe) with all of the shared libraries that are needed to run it, along with any run-time files declared via the runtime-path.ss MzLib library. The resulting package can be moved to other machines that run the same operating system.
After the --exe-dir flag, supply a directory to contain the combined files for a distribution. Each command-line argument is an executable to include in the distribution, so multiple executables can be packaged together:
Example:
mzc --exe-dir geetings hello.exe goodbye.exe
Under Windows, this example creates a directory greetings (if the directory doesn't exist already), and it copies the executables hello.exe and goodbye.exe into greetings. It also creates a lib sub-directory in greetings to contain DLLs, and it adjusts the copied hello.exe and goodbye.exe to use the DLLs in lib.
The layout of files within a distribution directory is platform-specific:
Under Windows, executables are put directly into the distribution directory, and DLLs and other run-time files go into a lib sub-directory.
Under Mac OS X, --gui-exe executables go into the distribution directory, --exe executables go into a bin subdirectory, and frameworks (i.e., shared libraries) go into a lib sub-directory along with other run-time files. As a special case, if the distribution has a single --gui-exe executable, then the lib directory is hidden inside the application bundle.
Under Unix, executables go into a bin subdirectory, shared libraries (if any) go into a lib subdirectory along with other run-time files, and wrapped executables are placed into a lib/plt subdirectory with version-specific names. This layout is consistent with Unix installation conventions; the version-specific names for shared libraries and wrapped executables means that distributions can be safely unpacked into a standard place on target machines without colliding with an existing PLT Scheme installation or other executables created by mzc.
A distribution also has a collects directory that is used as the main library collection directory for the packaged executables. By default, the directory is empty. Use the ++copy-collects flag to supply a directory whose content is copied into the distribution's collects directory. The ++copy-collects flag can be used multiple times to supply multiple directories.
When multiple executables are disrtibuted together, then separately creating the executables with --exe and --gui-exe can generate multiple copies of collection-based libraries that are used by multiple executables. To share the library code, instead, specify a target directory for library copies using the --collects-dest flag with --exe and --gui-exe, and specify the same directory for each executable (so that the set of libraries used by all executables are pooled together). Finally, when packaging the distribution with --exe-dir, use the ++copy-collects flag to include the copied libraries in the distribution.
5.3 Stand-Alone Executables from Native Code
Creating a stand-alone executable that embeds native code from mzc requires downloading the MzScheme source code and using a C compiler and linker directly.
To build an executable with an embedded MzScheme engine:
Download the source code from http://www.drscheme.org/ and compile MzScheme.
Recompile MzScheme's main.c with the preprocessor symbol STANDALONE_WITH_EMBEDDED_EXTENSION defined. Under Unix, the Makefile distributed with MzScheme provides a target ee-main that performs this step.
The preprocessor symbol causes MzScheme's startup code to skip command line parsing, the user's initialization file, and the
read-eval-print
loop. Instead, the C function scheme_initialize is called, which is the entry point into mzc-compiled Scheme code. After compiling main.c with STANDALONE_WITH_EMBEDDED_EXTENSION defined, MzScheme will not link by itself; it must be linked with objects produced by mzc.Compile each Scheme source file in the program with mzc's -o or --object flag and the --embedded flag, producing a set of .kp files and object (.o or .obj) files.
After each Scheme file is compiled, run mzc with the -g or --link-glue and the --embedded flag, providing all of the .kp files and object files on the command line. (Put the object files in the order that they should be ``loaded.'') The -g or --link-glue step produces a new object file, _loader.o or _loader.obj.
Each of the Scheme source files in the program must have a different base name (i.e., the file name without its directory path or extension), otherwise _loader cannot distinguish them. The files need not reside in the same directory.
Link all of the mzc-created object files with the MzScheme implementation (having compiled main.c with STANDALONE_WITH_EMBEDDED_EXTENSION defined) to produce a stand-alone executable.
Under Unix, the Makefile distributed with MzScheme provides a target ee-app that performs the final linking step. To use the target, call mzmake with a definition for the makefile macro EEAPP to the output file name, and a definition for the makefile macro EEOBJECTS to the list of mzc-created object files. (The example below demonstrates how to define makefile variables on the command line.)
For example, under Unix, to create a standalone executable MyApp that is equivalent to
mzscheme -mv -f file1.ss -f file2.ss
unpack the MzScheme source code and perform the following steps:
cd plt/src/mzscheme
./mzmake
./mzmake ee-main
mzc --object --embedded file1.ss
mzc --object --embedded file2.ss
mzc --link-glue --embedded file1.kp file1.o file2.kp file2.o
./mzmake EEAPP=MyApp EEOBJECTS="file1.o file2.o _loader.o" ee-app
To produce an executable that embeds the MrEd engine, the procedure is essentially the same; MrEd's main file is mrmain.cxx instead of main.c. See the compilation notes in the MrEd source code distribution for more information.