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 that are referenced dynamically -- through
, eval, or load -- are not
automatically embedded into the created executable, but they can be
explicitly included using mzc's --lib flag.dynamic-require
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. 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. 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 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. 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, 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 exectuables 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-printloop. 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.