If you write a Kawa application, it is convenient to be able
to execute it directly (from the command line or clicking an icon, say),
without have to explicitly run kawa
or java
.
On Unix-like systems the easiest way to do this is to
write a small shell script that runs your Kawa application.
For modest-sized applications it is convenient if the shell script
and the Kawa code can be in the same file.
Unix-like systems support a mechanism where a script can
specify a program that should execute it. The convention
is that the first line of the file should start with the two characters
‘#!
’ followed by the absolute path of the program that should
process (interpret) the script.
(Windows has batch files, which are similar.)
This convention works well for script languages that use ‘#
’
to indicate the start of a comment, since the interpreter will
automatically ignore the line specifying the interpreter filename.
Scheme, however, uses ‘#
’ as a multi-purpose prefix,
and Kawa specifically uses ‘#!
’ as a prefix for
various Special named constants such as #!optional
.
Kawa does recognize the three-character sequence ‘#!/
’ at the
beginning of a file as special, and ignores it.
Here is an example:
#!/usr/local/bin/kawa (format #t "The command-line was:~{ ~w~}~%" (command-line))
If you copy this text to a file named /home/me/bin/scm-echo
,
set the execute permission, and make sure it is in your PATH
,
then you can execute it just by naming it on command line:
$ chmod +x /home/me/bin/scm-echo $ PATH=/home/me/bin:$PATH $ scm-env a b The command-line was: "/home/me/bin/scm-echo" "a" "b"
The system kernel will automatically execute kawa
, passing it the
filename as an argument.
Note that the full path-name of the kawa
interpreter
must be hard-wired into the script. This means you may have to edit
the script depending on where Kawa is installed on your system.
Another possible problem is that the interpreter must be an
actual program, not a shell script. Depending on how you configure
and install Kawa, kawa
can be a real program or a script.
You can avoid both problems by the env
program, available on
most modern Unix-like systems:
#!/usr/bin/env kawa (format #t "The command-line was:~{ ~w~}~%" (command-line))
This works the same way, but assumes kawa
is in the
command PATH
.
If you need to specify extra arguments to kawa
,
you can run arbitrary shell command inside Scheme block comments.
Here is an example:
#!/bin/sh #| exec kawa out:base=16 out:radix=yes "$0" "$*" |# (format #t "The command-line is:~{ ~w~}.~%" (command-line)) (display "It has ") (display (apply + (map string-length (command-line)))) (display " characters.") (newline)
The trick is to hide the shell code from Kawa inside
a #|...|#
block-comment. The start of the block comment
is a line starting with a #
, so it is treated as a comment by the shell.
You can then invoke kawa
(or java
directly)
as you prefer, setting up class-path and jars as needed,
and passing whatever arguments you want.
(The shell replaces the "$0"
by the name of the script, and
replaces the "$@"
by the remaining arguments passed to the script.)
You need to make sure the shell finishes before it reaches
the end of the block comment or the Scheme code, which would confuse it.
The example uses exec
, which tells the shell to replace
itself by kawa
;
an alternative is to use the shell exit
command.
If you copy the above file to /tmp/sch-echo
and make
that file executable, you can run it directly:
$ /tmp/scm-echo "a b" "c d" The command-line is: "/tmp/scm-echo" "a b c d". It has #x14 characters.
When the Kawa reader sees the initial #/
it sets
the command name to the file name, so it can be used by a future
call to (command-name)
. If you want to override
this you can use the -Dkawa.command.name=
option.
name
Using comments this way has the advantage that you have the option of running the script “manually” if you prefer:
$ kawa /tmp/scm-echo out:base=8 "x y" The command-line is: "/tmp/scm-echo" "out:base=8" "x y". It has 26 characters.
An argument consisting of just a \
(backslash)
causes Kawa to read the second line looking for
options. (Quotes and backslashes work like in the shell.)
These replace the backslash in the command line.
This is a less verbose mechanism, but it requires an
absolute path to kawa
, due to shell limitations.
#!/usr/bin/kawa \ --scheme --full-tailcalls (format #t "The command-line is:~{ ~w~}.~%" (command-line))
In this case the effective command line received by Kawa will
be --scheme
, --full-tailcalls
, followed by the
script filename, followed by other arguments specified when
running the script.
The backslash used this way originated in
scsh where it is called the meta-arg.
(Unlike scsh, Kawa’s #!
is not a block comment,
but a rest-of-line, though the backslash causes the following line
to also be skipped.)
An alternative method is to use the --script2
option,
which tells Kawa to execute the script after ignoring
the initial two lines. For example:
#!/bin/sh exec kawa --commonlisp out:base=16 --script2 "$0" "$@" (setq xx 20) (display xx) (newline)
This is slightly more compact than using block-comments as shown earlier,
but it has the disadvantage that you can’t explicitly
use kawa
or java
to run the script unless you
make sure to pass it the --script2
option.
If you compile your Kawa application to class files (or better:
a jar
file), you probably still want to write a small
shell script to set things up. Here is one method:
#!/bin/sh export CLASSPATH=/my/path exec kawa -Dkawa.command.name="$0" foo "$@"
Using the kawa
front-end is a convenience, since it automatically
sets up the paths for the Kawa classes, and (if enabled) it
provides readline support for the default input port.
Setting the kawa.command.name
property to "$0"
(the filename used to invoke the script) enables
(command-line
) to use the script name as the command name.
You can invoke java
directly, which is necessary when
running a jar
file:
#!/bin/sh exec java -cp /path/to/kawa -Dkawa.command.name="$0" foo.jar "$@"