All Scheme functions and source files are invisibly compiled into internal Java byte-codes. (A traditional interpreter is used for macro-expansion. Kawa used to also interpret “simple” expressions in interactive mode, but always compiling makes things more consistent, and allows for better stack traces on errors.)
To save speed when loading large Scheme source files, you probably want to pre-compile them and save them on your local disk. There are two ways to do this.
You can compile a Scheme source file to a single archive file.
You do this using the compile-file function.
The result is a single file that you can move around and load
just like the .scm source file. You just specify the name
of the archive file to the load procedure.
Currently, the archive is a "zip" archive and has extension ".zip";
a future release will probably use "Java Archive" (jar) files.
The advantage of compiling to an archive is that it is simple
and transparent. A minor disadvantage is that it causes the
Java "verifier" to be run when functions are loaded from it,
which takes a little extra time.
Alternatively, you can compile a Scheme source file to a
collection of ‘.class’ files.
You then use the standard Java class loading mechanism to load the code.
The Java "verifier" does not need to get run, which makes
loading a little faster.
The compiled class files do have to be installed somewhere
in the CLASSPATH.
You can also compile your Scheme program to native code using GCJ.
Function: compile-file source-file compiled-archive
Compile the
source-file, producing a.ziparchivecompiled-file.For example, to byte-compile a file ‘
foo.scm’ do:(compile-file "foo.scm" "foo")This will create ‘
foo.zip’, which contains byte-compiled "j-code". You can move this file around, without worrying about class paths. To load the compiled file, you can laterloadthe named file, as in either(load "foo")or(load "foo.zip"). This should have the same effect as loading ‘foo.scm’, except you will get the faster byte-compiled versions.
Invoking ‘kawa’ (or ‘java kawa.repl’) with
the ‘-C’ flag will compile
a ‘.scm’ source file into one or more ‘.class’ files:
kawa --main -C myprog.scm
You run it as follows:
kawa [-doutdirectory] [-Pprefix] [-Ttopname] [--main | --applet | --servlet] -Cinfile...
Note the ‘-C’ must come last, because ‘Kawa’ processes the
arguments and options in order,
Here:
-C infile ...The Scheme source files we want to compile.
-d outdirectoryThe directory under which the resulting ‘.class’ files will be.
The default is the current directory.
-P prefixA string to prepend to the generated class names. The default is the empty string.
-T topnameThe name of the "top" class - i.e. the one that contains the code
for the top-level expressions and definitions.
The default is generated from the infile and prefix.
--mainGenerate a main method so that the resulting "top" class can
be used as a stand-alone application. See Compiling to a standalone application.
--appletThe resulting class inherits from java.applet.Applet,
and can be used as an applet. See Compiling to an applet.
--servletThe resulting class implements javax.servlet.http.HttpServlet,
and can be used as an servlet in a servlet container like Tomcat.
When you actually want to load the classes, the outdirectory
must be in your ‘CLASSPATH’.
You can use the standard load function to load the code,
by specifying the top-level class, either as a file name
(relative to outdirectory) or a class name.
E.g. if you did:
kawa -d /usr/local/share/java -P my.lib. -T foo -C foosrc.scm
you can use either:
(load "my.lib.foo")
or:
(load "my/lib/foo.class")
If you are compiling a Scheme source file (say ‘foosrc.scm’)
that uses macros defined in some other file (say ‘macs.scm’),
you need to make sure the definitions are visible to the compiler.
One way to do that is with the ‘-f’:
kawa -f macs.scm -C foosrc.scm
Various named option control how Kawa compiles certain forms.
--module-staticIf no module-static is specified, generate a static module
(as if (module-static #t) were specified). See Modules and how they are compiled to classes.
--module-static-runIf no module-static is specified, generate a static module
(as if (module-static 'init-run) were specified). See Modules and how they are compiled to classes.
--warn-invoke-unknown-methodEmit a warning if the invoke function calls a named method
for which there is no matching method in the compile-time type of the receiver.
This (currently) defaults to on;
to turn it off use the --no-warn-invoke-unknown-method flag.
--warn-undefined-variableEmit a warning if the code references a variable which is neither in
lexical scope nor in the compile-time dynamic (global) environment.
This is useful for catching typos.
(A define-variable form can be used to silence warnings.
It declares to the compiler that a variable is to be resolved dynamically.)
--warn-as-errorTreat a compilation warning as if it were an error and halt compilation.
An option can be followed by a value, as
in --warn-invoke-unknown-method=no.
For boolean options, the values yes, true, on, or 1
enable the option, while no, false, off,
or 0 disable it.
You can also negate an option by prefixing it with no-:
The option --no-warn-invoke-unknown-method
is the same as --warn-invoke-unknown-method=no.
You can set the same options (except, for now, module-static)
within your Scheme source file. (In that case they override the
options on the command line.)
Syntax: module-compile-options [key: value] ...
This sets the value of the
keyoption tovaluefor the current module (source file). It takes effect as soon it is seen during the first macro-expansion pass, and is active thereafter (unless overridden bywith-compile-options).The
keyis one of the above option names. (The following colon make it a Kawa keyword.) Thevaluemust be a literal value: either a boolean (#tor#f), a number, or a string, depending on thekey. (All the options so far are boolean options.)(module-compile-options warn-undefined-variable: #t) ;; This causes a warning message that y is unknown. (define (func x) (list x y))
A Java application is a Java class with a special method
(whose name is main). The application can be invoked directly
by naming it in the Java command.
If you want to generate an application from a Scheme program,
create a Scheme source file with the definitions you need, plus
the top-level actions that you want the application to execute.
You can compile in the regular way decribed in the previous section, but add
the --main option. For example,
assuming your Scheme file is MyProgram.scm:
kawa --main -C MyProgram.scm
This will create a MyProgram.class which you can either load
(as decribed in the previous section), or invoke as an application:
java MyProgram [args]
Your Scheme program can access the command-line arguments args
by using the global variable ‘command-line-arguments’.
An applet is a Java class that inherits from java.applet.Applet.
The applet can be downloaded and run in a Java-capable web-browser.
To generate an applet from a Scheme program, write the Scheme
program with appropriate definitions of the functions ‘init’,
‘start’, ‘stop’ and ‘destroy’. You must declare these
as zero-argument functions with a <void> return-type.
Here is an example, based on the scribble applet in Flanagan's "Java Examples in a Nutshell" (O'Reilly, 1997):
(define-private last-x 0)
(define-private last-y 0)
(define (init) :: void
(let ((applet (this)))
(applet:addMouseListener
(object (java.awt.event.MouseAdapter)
((mousePressed e)
(set! last-x (e:getX))
(set! last-y (e:getY)))))
(applet:addMouseMotionListener
(object (java.awt.event.MouseMotionAdapter)
((mouseDragged e)
(let ((g (applet:getGraphics))
(x (e:getX))
(y (e:getY)))
(g:drawLine last-x last-y x y)
(set! last-x x)
(set! last-y y)))))))
(define (start) :: void (format #t "called start.~%~!"))
(define (stop) :: void (format #t "called stop.~%~!"))
(define (destroy) :: void (format #t "called destroy.~%~!"))
You compile the program with the ‘--applet’ flag in addition to the
normal ‘-C’ flag:
java kawa.repl --applet -C scribble.scm
You can then create a ‘.jar’ archive containing your applet:
jar cf scribble.jar scribble*.class
Finally, you create an ‘.html’ page referencing your applet
and its support jars:
<html><head><title>Scribble testapp</title></head> <body><h1>Scribble testapp</h1> You can scribble here: <br> <applet code="scribble.class" archive="scribble.jar, kawa-1.9.90.jar" width=200 height=200> Sorry, Java is needed.</applet> </body></html>
The problem with using Kawa to write applets is that the Kawa .jar
file is quite big, and may take a while to download over a network connection.
Some possible solutions:
Try to strip out of the Kawa .jar any classes your
applet doesn't need.
Java 2 provides a mechanism to install a download extension.
Consider some alternative to applets, such as Java Web Start.
You can compile your Scheme program to native code using GCJ, as long as you have built Kawa using GCJ.
First, you need to compile the Scheme code to a set of .class files;
see Compiling to a set of .class files.
kawa --main -C myprog.scm
Then to create an executable myprog do:
gckawa --main=myprog myprog*.class -o myprog
The gckawa is a simple shell script that calls gcj.
The reason for the wildcard in myprog*.class is that sometimes
Kawa will generate some helper classes in addition to myprog.class.
The --main option tell gcj which class contains
the main method it should use. The -o option names
the resulting executable program. The -lkawa option tells
the linker it should link with the kawa shared library, and
the -L$PREFIX/bin option tells the linker where it can
find that library.