[[CompilingChapter]]

Compiling Files and Libraries
-----------------------------

This chapter explains how you can use Larceny to compile
Scheme source code to native machine code.

The native varieties of Larceny have a just-in-time
compiler that compiles to native code automatically
whenever you evaluate an expression, load a source
file, or import a source library.  Even so, files
will load faster if they are compiled ahead of time.

Petit Larceny does not have a just-in-time compiler,
so compiling ahead of time is the only way to enjoy
the speed of native machine code in Petit Larceny.

////////////////////////////////////////////////////////////////
Common Larceny uses an interpreter for expressions
that are typed at the interactive read/eval/print
loop, but files will be compiled as they are loaded
if you specify +Larceny.fasl+ on the command line.
For more information on compiling files in Common
Larceny, please consult the
http://larceny.ccs.neu.edu[Common Larceny User Manual].
////////////////////////////////////////////////////////////////

The main disadvantage of compiling files and libraries
is that compiled code goes _stale_ when its original
source code is changed or when a library on which
the compiled code depends is changed or recompiled.
Stale compiled code can be dangerously inconsistent
with libraries on which it depends, so Larceny checks
for staleness and refuses to execute a stale library
or program.


[[CompilingToExecutable]]

Compiling an R7RS/R6RS program into directly executable form
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

On Unix machines, the `compile-larceny` script can be used to
compile an R7RS/R6RS program named `pgm.sps` or `pgm.scm` into
an executable file named `pgm`:
----------------------------------------------------------------
    % compile-larceny pgm.sps
----------------------------------------------------------------
The `compile-larceny` script satisfies the
http://srfi.schemers.org/srfi-138[SRFI 138] specification
of `compile-r7rs` scripts, so it accepts Larceny's `-I`, `-A`,
and `-D` options, and also recognizes an option of the form
`-o pgm`, which can be used to specify a name other than `pgm`
for the executable file.

The executable `pgm` file will be a shell script that calls `larceny`
on a `pgm.slfasl` file produced by `compile-larceny`, passing the
same `-I`, `-A`, and `-D` options that had been passed to
`compile-larceny`.

[WARNING]
================================================================
If any libraries used by the program are changed, touched, or
moved, the program will need to be re-compiled.  That means you
should compile all of the libraries the program uses before you
compile the program.
================================================================


[[CompilingR7rsSection]]

Compiling R7RS/R6RS libraries
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

To compile individual files, use the `compile-file` or
`compile-library` procedures that are exported by
<<LarcenyCompilerSection,`(larceny compiler)`>>.

To compile specific files while also compiling any stale
or as-yet-un-compiled libraries on which they may depend,
use the
`compile-stale-cautiously`,
`compile-stale-regardless`, or
`compile-stale-recklessly` procedures exported by
<<LarcenyCompilerSection,`(larceny compiler)`>>.

On Unix machines, the `compile-larceny` script can sometimes
be used to compile all of the R7RS/R6RS libraries within
one or more directories.  The following example compiles
all libraries found within `mydir1` and its subdirectories,
and then compiles all libraries found within `/tmp/mydir2`
and its subdirectories:
----------------------------------------------------------------
    % compile-larceny -I mydir1 -I /tmp/mydir2
----------------------------------------------------------------

[WARNING]
================================================================
When `compile-larceny` is used to compile all libraries within
one or more directories as in the above example, it respects
import dependencies within each directory given on its command
line, but it does not respect import dependences between libraries
located in two different directories on its command line.
For the general case, in which some of the libraries in each
directory import libraries located in one of the other
directories, use procedures exported by
<<LarcenyCompilerSection,`(larceny compiler)`>>.
================================================================

On Unix machines, a convenient way to compile
a group of R7RS/R6RS libraries and top-level programs
that are all located within a single directory
is to use the +compile-stale+ script in Larceny's root
directory.
If Larceny's root directory is in your execution path,
then there are just two steps:

1.  Use +cd+ to change to the directory that contains
the R7RS/R6RS files you want to compile.  (Files
that lie within subdirectories of that directory will
be compiled also.)

2.  Run the +compile-stale+ script.

The `compile-stale` script accepts Larceny's `-I`, `-A`,
and `-D` options, which will be necessary if any of the
files to be compiled import from libraries located outside
of Larceny's usual library search path.  For example:
----------------------------------------------------------------
    % cd /tmp/mydir2
    % compile-stale -I mydir1 -I /tmp/mydir2
----------------------------------------------------------------

On non-Unix machines, you can accomplish the same thing
using Larceny's R7RS mode and the +(larceny compiler)+
library:
----------------------------------------------------------------
    % pushd /tmp/mydir2
    % larceny -r7 -I mydir1 -I /tmp/mydir2
    Larceny v1.3

    > (import (larceny compiler))

    > (compile-stale-libraries)
----------------------------------------------------------------

The `compile-stale` script also accepts file names,
in which case it behaves like the
<<compile-stale-cautiously,`compile-stale-cautiously`>> procedure
exported by
<<LarcenyCompilerSection,`(larceny compiler)`>>.


[[CompilingR5rsSection]]

Compiling R5RS source files
~~~~~~~~~~~~~~~~~~~~~~~~~~~

proc:compile-file[args="sourcefile",optargs="faslfile"]

Compiles _sourcefile_, which must be a string naming
a file that contains R5RS source code.
If _faslfile_ is supplied as a second argument,
then it must be a string naming the file that will
contain the compiled code; otherwise the name of
the compiled file is obtained from _sourcefile_
by replacing the "`.sch`" or "`.scm`" suffix with
"`.fasl`".

For R7RS/R6RS libraries and top-level programs,
<<CompilingR7rsSection,see above>>.


[[LoadingR5intoR7Section]]

Loading compiled R5RS files into an R7RS session
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

When a file is compiled, the compiler must make assumptions
about the meanings of its free identifiers.

When R5RS code is compiled, Larceny's compiler assumes all
free identifiers refer to the flat global naming environment
prescribed by the R5RS standard.

When an R7RS/R6RS library or top-level program is compiled,
Larceny's compiler assumes all free identifiers refer to
identifiers imported from other libraries.  That assumption
is checked at both compile time and at run time.  At compile
time, the compiler refuses to compile a library if one or
more of its free identifiers is not imported.  The compiler
also records the current versions of all imported libraries,
so Larceny's import mechanism can check at run time to make
sure all of the imported libraries are still consistent with
the libraries imported at compile time.

The facts stated above imply compiled R5RS code can only be
loaded into the flat global environment provided by Larceny's
underlying R5RS layer, and compiled R7RS/R6RS code can only
be imported by or loaded into an R7RS/R6RS program or
interactive session.

R5RS source code can be loaded into an interactive R7RS
session, but it will be loaded as though it were R7RS code
rather than R5RS code.  That means loading R5RS source code
into an interactive R7RS session behaves differently from
loading compiled R5RS code into an interactive R7RS session.

When compiled R5RS code is loaded into an interactive R7RS
session, it is loaded into Larceny's underlying R5RS layer.
The procedures it defines can then be imported into
the R7RS session using Larceny's
<<R7rsPrimitivesSection,primitives>>
extension to `import` syntax.

When R5RS source code is loaded into an interactive R7RS
session, however, it will behave as though the source code
had been typed interactively.
