[[LarcenyCompilerSection]]

Compiler
~~~~~~~~

The `(larceny compiler)` library exports the
`load` and `r5rs:require` procedures of `(larceny load)`,
the
<<current-require-path,`current-require-path`>> and
<<current-directory,`current-directory`>>
parameters, the
<<compile-file,`compile-file`>>,
<<compile-library,`compile-library`>>,
<<compile-stale-libraries,`compile-stale-libraries`>>,
<<compile-stale-cautiously,`compile-stale-cautiously`>>,
<<compile-stale-regardless,`compile-stale-regardless`>>, and
<<compile-stale-recklessly,`compile-stale-recklessly`>>
procedures described below,
and the
<<compiler-switches,`compiler-switches`>> procedure.

These procedures can be used to compile R7RS/R6RS
libraries and top-level programs before they are imported
or executed.
This is especially important for Petit Larceny, which
would otherwise use an interpreter.  For native Larceny,
whose just-in-time compiler generates native machine code
as source libraries and programs are loaded, imported, or
executed, the main advantage of separate compilation is
that compiled libraries and programs will load much
faster than source libraries and programs.

The main disadvantage of separate compilation is that
compiled libraries and programs go _stale_ when their
source code is changed or when a library on which they
depend is changed or recompiled.  Stale libraries and
programs can be dangerously inconsistent with libraries
on which they depend, so Larceny checks for staleness
and refuses to execute a stale library or program.
The
<<compile-stale-libraries,`compile-stale-libraries`>>,
<<compile-stale-cautiously,`compile-stale-cautiously`>>,
<<compile-stale-regardless,`compile-stale-regardless`>>, and
<<compile-stale-recklessly,`compile-stale-recklessly`>>,
procedures make it easier to recompile stale
libraries and programs.

proc:compile-file[args="sourcefile",optarg="slfaslfile"]

Compiles _sourcefile_, which must be a string naming
a file that contains source code for one or more
R7RS/R6RS libraries or a top-level program.
If _slfaslfile_ 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 "`.sld`" or "`.sls`" suffix with "`.slfasl`".

proc:compile-library[args="sourcefile",optarg="slfaslfile"]

Compiles _sourcefile_, which must be a string naming
a file that contains source code for one or more
R7RS/R6RS libraries.
Apart from its unwillingness to compile top-level
programs, `compile-library` behaves the same as
`compile-file` above.

proc:compile-stale-libraries[args=""]
proctempl:compile-stale-libraries[args="changedfile"]

If no argument is supplied, then all "`.sld`" and "`.sls`" files that
lie within the current directory or a subdirectory are
recompiled.

If _changedfile_ is supplied, then it must be a string
giving the absolute pathname of a file.
(In typical usage, _changedfile_ is a source file that
has been modified, making it necessary to recompile all
files that depend upon it.)
Compiles all R7RS/R6RS library files that lie within
the same directory as _changedfile_ or a subdirectory,
and have not yet been compiled or whose compiled files
are older than _changedfile_.

[NOTE]
================================================================
In future versions of Larceny, `compile-stale-libraries`
might compile only the source files that depend upon
_changedfile_.
================================================================


proc:compile-stale-recklessly[args="sourcefile ..."]
proc:compile-stale-regardless[args="sourcefile ..."]
proc:compile-stale-cautiously[args="sourcefile ..."]

All three of these procedures attempt to compile the given
source files together with all of the files they depend upon
that have not yet been compiled or have been compiled but
gone stale.  They differ in how they behave when one of the
files to be compiled lies outside the current directory or
when one of the files to be compiled is imported, directly
or indirectly, by a file that is neither passed as an argument
nor relied upon by one of the files passed as an argument.

The `compile-recklessly` procedure compiles the given files
along with all of the files on which they depend that have
not yet been compiled or have gone stale or import a library
from one of the files that will be compiled.
If there are available libraries that depend upon one of the
files to be compiled but are not imported (directly or
indirectly) by one of the given files, then they too will
need to be re-compiled; the `compile-recklessly` procedure
does not re-compile those libraries, but it does print a
message listing them.

The `compile-regardless` procedure behaves the same as the
`compile-recklessly` procedure when all of the files to be
compiled and all of the other files that would need to be
re-compiled are located within the current directory.  If
not, `compile-regardless` does not compile any files but
does print a message telling how to compile all of the
files using `compile-file`.

The `compile-cautiously` procedure behaves the same as the
`compile-regardless` procedure when all of the files can be
compiled without affecting any available libraries that will
not be compiled.  If compiling the files would make it
necessary to re-compile some other library, `compile-cautiously`
does not compile any files but does print a message telling
how to compile all of the files using `compile-file`.

Suppose, for example, that `/tmp/Foo` and `/tmp/Bar` contain
these four files:

----------------------------------------------------------------
% cat /tmp/Foo/foo.sps
(import (scheme base)
        (scheme write)
        (foo)
        (bar))
(write (list y x)) (newline)
% cat /tmp/Foo/foo.sld
(define-library (foo)
  (export x)
  (import (scheme base)
          (bar))
  (begin (define x 97)))
% cat /tmp/Bar/bar.sps
(import (scheme base)
        (scheme write)
        (foo)
        (bar))
(write (list x y)) (newline)
% cat /tmp/Bar/bar.sld
(define-library (bar)
  (export y)
  (import (scheme base))
  (begin (define y 98)))
----------------------------------------------------------------

The two programs can be run without compiling any of those files:

----------------------------------------------------------------
% larceny -I /tmp/Foo -I /tmp/Bar /tmp/Foo/foo.sps
(98 97)
% larceny -I /tmp/Foo -I /tmp/Bar /tmp/Bar/bar.sps
(97 98)
----------------------------------------------------------------

The `compile-stale-cautiously` and `compile-stale-regardless`
procedures refuse to compile the `bar.sps` program because it
imports a library located in another directory that has not been
compiled.  The `compile-stale-recklessly` procedure goes ahead
and compiles that library even though it is located in a different
directory:

----------------------------------------------------------------
% larceny -I /tmp/Foo -I /tmp/Bar -r7
Larceny v1.3

> (import (larceny compiler))

> (parameterize ((current-directory "/tmp/Bar"))
    (compile-stale-cautiously "bar.sps"))

Libraries and programs to be compiled:

    (bar)
    (foo)
    (#(program) 1)

Minimal files to be compiled:

    "/tmp/Bar/bar.sld"
    "/tmp/Foo/foo.sld"
    "/tmp/Bar/bar.sps"

NO FILES WERE COMPILED

    because some files to be compiled are outside current directory

To force compilation, import (larceny compiler) and evaluate

(for-each
  compile-file
  '("/tmp/Bar/bar.sld"
    "/tmp/Foo/foo.sld"
    "/tmp/Bar/bar.sps"))

NO FILES WERE COMPILED

> (parameterize ((current-directory "/tmp/Bar"))
    (compile-stale-recklessly "bar.sps"))

Libraries and programs to be compiled:

    (bar)
    (foo)
    (#(program) 1)

Minimal files to be compiled:

    "/tmp/Bar/bar.sld"
    "/tmp/Foo/foo.sld"
    "/tmp/Bar/bar.sps"

Compiling /tmp/Bar/bar.sld
Compiling /tmp/Foo/foo.sld
Compiling /tmp/Bar/bar.sps

% larceny -I /tmp/Foo -I /tmp/Bar /tmp/Bar/bar.sps.slfasl
(97 98)
----------------------------------------------------------------


proc:compiler-switches[args=""]
proctempl:compiler-switches[args="mode"]

If no argument is supplied, then the current settings
of all compiler switches are displayed.  Each of those
switches is itself a parameter that is exported by the
`(larceny compiler)` library.  Calling any individual
compiler switch with no arguments will return its current
setting.  Calling any individual compiler switch with an
argument (usually a boolean) will change its setting to
that argument.

The `compiler-switches` procedure may also be called with
one of the following symbols as its argument:

`default`
sets most compiler switches to their default settings.

`fast-safe`
enables all optimizations but continues to generate
code to perform all run-time type and range checks that
are needed for safety
(in the traditional sense, not the R6RS sense).

`fast-unsafe`
enables all optimizations and also disables type and
range checking.  This setting is deprecated because it
compromises safety (in the traditional sense).

`slow`
turns off all optimizations.

`standard`
sets compiler switches for maximal conformance to the
R5RS and R6RS standards.

[WARNING]
================================================================
The `standard` setting is deprecated because it generates
very slow code (because the R5RS makes it difficult to
inline standard procedures), disables most compile-time
checking (because the R6RS forbids rejection of programs
with obvious errors unless the R6RS classifies the errors
as syntactic), and may also compromise the portability or
interoperability of R7RS/R6RS libraries and programs
(because the R6RS outlaws several extensions that Larceny
uses to improve its compatibility with other implementations
of the R5RS, R6RS, and R7RS as well as interoperability between
Larceny's own R5RS and R7RS/R6RS modes).
================================================================

[TIP]
================================================================
Selective toggling of compiler switches is almost always
better than using the `standard` setting.
To improve R5RS conformance without sacrificing too much
performance, set the `benchmark-mode` switch to false and
set the `integrate-procedures` switch to false only when
compiling files that need to be sensitive to redefinitions
of standard procedures.
For R6RS libraries and programs, setting the `benchmark-mode`
and `global-optimization` switches to false will eliminate a
couple of minor conformance issues with only a small loss
of performance and without sacrificing compile-time checking
or portability.
For R7RS libraries and programs, the compiler's default settings
already conform to the R7RS.
================================================================
