#+AUTHOR: Mark Wooding
#+LaTeX_CLASS: strayman
#+LaTeX_HEADER: \usepackage{tikz, gnuplot-lua-tikz}
+#+LaTeX_HEADER: \DeclareUnicodeCharacter{200B}{}
+#+EXPORT_FILE_NAME: doc/README.pdf
~runlisp~ is a small C program intended to be run from a script ~#!~
line. It selects and invokes a Common Lisp implementation, so as to run
+ Armed Bear Common Lisp (~abcl~),
+ Clozure Common Lisp (~ccl~),
+ GNU CLisp (~clisp~),
- + Carnegie--Mellon Univerity Common Lisp (~cmucl~), and
+ + Carnegie--Mellon Univerity Common Lisp (~cmucl~),
+ Embeddable Common Lisp (~ecl~), and
+ Steel Bank Common Lisp (~sbcl~).
of high-quality configuration runes curated centrally, so I'm happy to
accept submissions in support of any free[fn:free] Lisp implementations.
-[fn:free] Here I mean free as in freedom.
+[fn:free] Here I mean `free' as in freedom: see
+https://www.fsf.org/about/what-is-free-software.
* Writing scripts in Common Lisp
: #-(or sbcl ccl) "an unexpected"
: " Common Lisp!~%"))
+It is not an error to include the name of an unrecognized Lisp system in
+the ~-L~ option: such names are simply ignored. This allows a script to
+declare support for unusual or locally installed Lisp systems without
+compromising its portability to sites where such systems are unknown, or
+which are still running older versions of ~runlisp~ which haven't been
+updated with the necessary configuration for those systems.
+
** Embedded options
If your script requires features of particular Lisp implementations
+ The prevailing Unix standard input, output, and error files are
available through the Lisp ~*standard-input*~, ~*standard-output*~,
- and ~*error-ouptut*~ streams, respectively. (This is, alas, not a
+ and ~*error-output*~ streams, respectively. (This is, alas, not a
foregone conclusion.)
+ The keyword ~:runlisp-script~ is added to the ~*features*~ list.
: 3
If your build script needs to get information out of Lisp, then wrapping
-~format~, or even ~prin1~, around forms is annoying; so ~runlisp~ has a
+~format~, or even ~princ~, around forms is annoying; so ~runlisp~ has a
~-p~ option which prints the values of the forms it evaluates.
: $ runlisp -e '(+ 1 2)'
: 3
-If a form produces multiple values, then ~-p~ will print all of them
-separated by spaces, on a single line:
+If a form produces multiple values, then ~-p~ will print all of them, as
+if by ~princ~, separated by spaces, on a single line:
: $ runlisp -p '(floor 5 2)'
: 2 1
+There's also a ~-d~ option, which does the same thing as ~-p~, only it
+prints values as if by ~prin1~. For example,
+
+: $ runlisp -p '"Hello, world!"'
+: Hello, world!
+: $ runlisp -d '"Hello, world!"'
+: "Hello, world!"
+
In addition to evaluating forms with ~-e~, and printing their values
-with ~-p~, you can also load a file of Lisp code using ~-l~.
+with ~-d~ and ~-p~, you can also load a file of Lisp code using ~-l~.
When ~runlisp~ is acting on ~-e~, ~-p~, and/or ~-l~ options, it's said
to be running in /eval/ mode, rather than its usual /script/ mode. In
-script mode, it /doesn't/ set ~:runlisp-script~ in ~*features*~.
+eval mode, it /doesn't/ set ~:runlisp-script~ in ~*features*~.
You can still insist that ~runlisp~ use a particular Lisp
implementation, or one of a subset of implementations, using the ~-L~
All of the files in this directory named ~SOMETHING.conf~ are read,
in increasing lexicographical order by name. The package comes with
a file ~0base.conf~ intended to be read first, so that it can be
- overridden if necessar. This sets up basic definitions, and defines
+ overridden if necessary. This sets up basic definitions, and defines
the necessary runes for those Lisp implementations which are
supported `out of the box'. New Lisp packages might come with
additional files to drop into this directory.
directories to add support for privately installed Lisp systems, or
to override settings made by earlier configuration files.
-The configuration syntax is complicated, and explained in detail in the
-*runlisp.conf* manpage.
+Configuration files generally look like =.ini=-style files. A line
+beginning with a semicolon ~;~ is a comment and is ignored. Most lines
+are assignments, which look like
+#+BEGIN_QUOTE
+/name/ ~=~ /value/
+#+END_QUOTE
+and assignments are split into sections by section headers in square
+brackets:
+#+BEGIN_QUOTE
+~[~\relax{}/section/\relax{}~]~
+#+END_QUOTE
+The details of the configuration syntax are complicated, and explained
+in the *runlisp.conf* manpage.
Configuration options can also be set on the command line, though the
effects are subtly different. Again, see the manual pages for details.
[fn:xdg-config] More properly, in ~$XDG_CONFIG_HOME/runlisp.conf~, if
-you set that.
+you set that variable.
** Deciding which Lisp implementation to use
implementations. The value is a list of Lisp implementation names, as
you'd give to ~-L~, separated by commas and/or spaces. If the
environment variable ~RUNLISP_PREFER~ is set, then this overrides any
-value found in the configuration files.
+value found in the configuration files. So your ~$HOME/.runlisp.conf~
+file might look like this:
+
+: ;;; -*-conf-*-
+:
+: prefer = sbcl, clisp
When deciding which Lisp implementation to use, ~runlisp~ works as
follows. It builds a list of /acceptable/ Lisp implementations from the
~runlisp~ itself is easy.
As a simple example, let's add support for the 32-bit version of
-Clozure~CL. The source code for Clozure~CL easily builds both 32- and
-64-bit binaries in either 32- or 64-bit userlands, and one might
-reasonably want to use the 32-bit CCL for some reason. The following
-configuration stanza is sufficient
+Clozure\nbsp{}CL. The source code for Clozure\nbsp{}CL easily builds
+both 32- and 64-bit binaries in either 32- or 64-bit userlands, and one
+might reasonably want to use the 32-bit CCL for some reason. The
+following configuration stanza is sufficient
: [ccl32]
: @PARENTS = ccl
: command = ${@ENV:CCL32?ccl32}
-: image-file = ccl32+asdf.image
+ The first line heads a configuration section, providing the name
which will be used for this Lisp implementation, e.g., in ~-L~
ideal opportunity to explain how ~runlisp~ configuration works, without
getting bogged down in the details of fighting less amenable Lisps.)
-The provided ~0base.conf~ file defines SBCL as follows.
+The provided ~0base.conf~ file used to define SBCL as follows. (The
+real version now contains a kludge for old versions, which needn't
+concern us here.)
: [sbcl]
:
we add the tokens ~--core "${image-path}" --eval "${image-restore}"~
to the SBCL command line; otherwise, we add ~--eval
"${run-script-prelude}"~. The ~@IMAGE~ setting is defined by
- ~runlisp~ only if (a)~a custom image was found in the correct placem
- and (b)~use of custom images isn't disabled on its command line.
+ ~runlisp~ only if (a)\nbsp{}a custom image was found in the correct
+ place, and (b)\nbsp{}use of custom images isn't disabled on its
+ command line.
The ~${image-path}~ token expands to the full pathname to the custom
image file; ~image-restore~ is a predefined Lisp expression to be
it's very similar to ~run-script-prelude~, and is built out of many
of the same pieces.
- The thing we haven't seen before is ~${@IMAENEW|q}~. The
+ The thing we haven't seen before is ~${@IMAGENEW|q}~. The
~@IMAGENEW~ setting is defined by the ~dump-runlisp-image~ program
- the name the file in which the new image should be
+ to name the file in which the new image should be
saved.[fn:image-rename] The ~|q~ `filter' is new: it means that the
filename should be escaped suitable for inclusion in a Lisp quoted
string, by prefixing each ~\~ or ~"~ with a ~\~.
implementations, and compared them to how long ~cl-launch~ took: the
results are shown in table [[tab:runlisp-vanilla]]. ~runlisp~ is /at least/
two and half times faster at running this script than ~cl-launch~ on all
-implementations except Clozure CL[fn:slow-ccl], and approaching four and
-a half times faster on SBCL.
+implementations except Clozure\nbsp{}CL[fn:slow-ccl], and approaching
+four and a half times faster on SBCL.
#+CAPTION: ~cl-launch~ vs ~runlisp~ (with vanilla images)
#+NAME: tab:runlisp-vanilla
measurements are included in the source distribution, in the ~bench/~
subdirectory.)
-[fn:slow-ccl] I don't know why Clozure CL shows such a small difference
-here.
+[fn:slow-ccl] I don't know why Clozure\nbsp{}CL shows such a small
+difference here.
** It's inconvenient
: NIL
As another example, Armed Bear Common Lisp doesn't seem to believe in
-the stderr stream: when it starts up, ~*error-ouptut*~ is bound to the
+the stderr stream: when it starts up, ~*error-output*~ is bound to the
standard output, just like ~*standard-output*~. Also, ~cl-launch~
loading ASDF causes a huge number of ~style-warning~ messages to be
written to stdout, making ABCL pretty much useless for writing filter
level of shell integration for all its supported Lisp implementations.
In particular:
- + It ensures that the standard Unix `stdin', `stdout', and `stdarr'
+ + It ensures that the standard Unix `stdin', `stdout', and `stderr'
file descriptors are hooked up to the Lisp ~*standard-input*~,
~*standard-output*~, and ~*error-output*~ streams.
then ~cl-launch~ is the way to do that. Of course, I welcome patches to
help ~runlisp~ support other free Lisp implementations. ~cl-launch~
also supports proprietary Lisps: I have very little interest in these,
-so if you want to run scripts using Allegro or LispWorks then
-~cl-launch~ is your only choice.
+so if you want to run scripts using Allegro or LispWorks then your only
+options are to maintain your own ~runlisp~ configuration for these
+systems or to use ~cl-launch~.
+
+* COMMENT Emacs cruft
+
+# LocalWords: abcl Almquist argv ATTR Attr BST clisp CLisp's Clozure CMU ecl
+# LocalWords: env fn ini interp launchrc lua nbsp noinform precompiled prin
+# LocalWords: princ sb SBCL's sed SYSCONFDIR sysinit TBLFM tbp tikz xdg XPS