.\" -*-nroff-*- .\" .\" Manual for `runlisp' .\" .\" (c) 2020 Mark Wooding .\" . .\"----- Licensing notice --------------------------------------------------- .\" .\" This file is part of Runlisp, a tool for invoking Common Lisp scripts. .\" .\" Runlisp is free software: you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 3 of the License, or (at your .\" option) any later version. .\" .\" Runlisp is distributed in the hope that it will be useful, but WITHOUT .\" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or .\" FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" You should have received a copy of the GNU General Public License .\" along with Runlisp. If not, see . . .ie t \{\ . ds o \(bu . if \n(.g \{\ . fam P . ev an-1 . fam P . ev . \} .\} .el \{\ . ds o o .\} . .de hP .IP \h'-\w'\fB\\$1\ \fP'u'\fB\\$1\ \fP\c .. . .\"-------------------------------------------------------------------------- .TH runlisp 1 "2 August 2020" "Mark Wooding" .SH NAME runlisp \- run Common Lisp programs as scripts . .\"-------------------------------------------------------------------------- .SH SYNOPSIS . .B runlisp .RB [ \-CDEnqv ] .RB [ \-I .IR imagedir ] .RB [ \-L .IB sys , sys , \fR...] .RB [ \-P .IB sys , sys , \fR...] .br \h'8n' .RB [ \-e .IR form ] .RB [ \-l .IR file ] .RB [ \-p .IR form ] .RB [ \-\- ] .RI [ script ] .RI [ arguments \&...] . .\"-------------------------------------------------------------------------- .SH DESCRIPTION . The .B runlisp program has two main functions. .hP 1. It can be used in a script's .RB ` #! ' line to run a Common Lisp script. .hP 2. It can be used in build scripts to invoke a Common Lisp system, e.g., to build a standalone program. . .SS "Supported Common Lisp implementations" The following Lisp implementations are currently supported. .TP .B "abcl" Armed Bear Common Lisp. .TP .B "ccl" Clozure Common Lisp. .TP .B "clisp" GNU CLisp. .TP .B "cmucl" Carnegie\(enMellon University Common Lisp. .TP .B "ecl" Embeddable Common Lisp. .TP .B "sbcl" Steel Bank Common Lisp. .PP The .B runlisp program expects, by default, to be able to run a Lisp system as a program with the same name, found by searching as directed by the .B PATH environment variable. This can be overridden by setting an environment variable, with the same name but in .IR "upper case" , to the actual name \(en either a bare filename to be searched for on the .BR PATH , or a pathname containing a .RB ` / ', relative to the working directory or absolute, to the program. Note that the entire variable value is used as the program name: it's not possible to provide custom arguments to a Lisp system using this mechanism. If you want to do that, you must write a shell script to do the necessary work, and point the environment variable (or the .BR PATH ) at your script. . .SS "Options" Options are read from the command line, as usual, but also from a number of other sources; these are, in order: .hP \*o If a .I script is named, and the script's second line contains a .RB ` @RUNLISP: ' marker, then text following the marker is parsed as options. .hP \*o If files named .B ~/.runlisprc and/or .B ~/.config/runlisprc exist, then their contents are parsed as options. .hP \*o If an environment variable .B RUNLISP_OPTIONS is defined, then its contents is parsed as options. .PP A simple quoting and escaping system is implemented to allow spaces and other special characters to be included in argument words in the script, configuration files, and environment variable. The details of all of this are given in the section .B Operation below. . .PP The options accepted are as follows. . .TP .B "\-\-help" Write a synopsis of .BR runlisp 's command-line syntax and a description of the command-line options to standard output and immediately exit with status 0. . .TP .B "\-\-version" Write .BR runlisp 's version number to standard output and immediately exit with status 0. . .TP .B "\-C" Clear the list of preferred Lisp implementations. . .TP .B "\-D" Don't check for a custom Lisp image. Usually, .B runlisp tries to start Lisp systems using a custom image, so that they'll start more quickly; the .RB ` \-D ' option forces the use of the default `vanilla' image provided with the system. There's not usually any good reason to prefer the vanilla image, except for performance comparisons, or debugging .B runlisp itself. . .TP .B "\-E" Don't read embedded options from the second line of the .I script file. This has no effect in eval mode. . .TP .BI "\-I " imagedir Look in .I imagedir for custom Lisp images. This option overrides the default image directory, which is set at compile time. . .TP .BI "\-L " sys , sys ,\fR... Use one of the named Lisp systems. Each .I sys must name a supported Lisp system. This option may be given more than once: the effect is the same as a single option listing all of the systems named, in the same order. If a system is named more than once, a warning is issued (at verbosity level 1 or higher), and all but the first occurrence is ignored. . .TP .BI "\-P " sys , sys ,\fR... Set the relative preference order of Lisp systems: systems listed earlier are more preferred. Each .I sys must name a supported Lisp system. This option may be given more than once: the effect is the same as a single option listing all of the systems named, in the same order. If a system is named more than once, a warning is issued (at verbosity level 1 or higher), and all but the first occurrence is ignored. Unmentioned systems are assigned lowest preference: if a .RB ` \-L ' option is given, then this provides a default preference ordering; otherwise, an ordering hardcoded into the program is used. The first acceptable Lisp system, according to the preference order just described, which actually exists, is the one selected. . .TP .BI "\-e " expr Evaluate the expression(s) .I expr and discard the resulting values. This option causes .B runlisp to execute in .I eval mode. . .TP .BI "\-l " file Read and evaluate forms from the .IR file . This option causes .B runlisp to execute in .I eval mode. . .TP .B "\-n" Don't actually start the Lisp environment. This may be helpful for the curious, in conjunction with .RB ` \-v ' to increase the verbosity. . .TP .BI "\-p " expr Evaluate the expression(s) .I expr and print the resulting value(s) to standard output (as if by .BR prin1 ). If a form produces multiple values, they are printed on a single line, separated by a single space character; if a form produces no values at all, then nothing is printed \(en not even a newline character. This option causes .B runlisp to execute in .I eval mode. . .TP .B "\-q" Don't print warning messages. This option may be repeated: each use reduces verbosity by one step, counteracting one .RB ` \-v ' option. The default verbosity level is 1, which prints only warning measages. . .TP .B "\-v" Print informational or debugging messages. This option may be repeated: each use increases verbosity by one step, counteracting one .RB ` \-q ' option. The default verbosity level is 1, which prints only warning measages. Higher verbosity levels print informational and debugging messages. . .PP The .RB ` \-e ', .RB ` \-l ', and .RB ` \-p ' options may only be given on the command-line itself, not following a .RB `@ RUNLISP: ' marker in a script, in a configuration file, or in the .B RUNLISP_OPTIONS environment variable. These options may be given multiple times: they will be processed in the order given. If any of these options is given, then no .I script name will be parsed; instead, use .RB ` \-l ' to load code from files. The .IR arguments , if any, are still made available to the evaluated forms and loaded files. . .SS "Operation" The .B runlisp program behaves as follows. .PP The first thing it does is parse its command line. Options must precede positional arguments, though the boundary may be marked explicitly using .RB ` \-\- ' if desired. If the command line contains any of .RB ` \-e ', .RB ` \-l ', or .RB ` \-p ', then .B runlisp treats all of its positional arguments as .I arguments to provide to the given forms and files, and runs in .I eval mode; otherwise, the first positional argument becomes the .I script name, the remaining ones become .IR arguments , and .B runlisp runs in .I script mode. .PP In .I script mode, .B runlisp reads the second line of the script file, and checks to see if it contains the string .RB ` @RUNLISP: '. If so, then the following text is parsed for .IR "embedded options" , as follows. The text is split into words separated by sequences of whitespace characters. Whitespace, and other special characters, can be included in a word by .I quoting or .IR escaping . Text between single quotes .BR ' ... ' is included literally, without any further interpretation; text between double quotes .BR """" ... """" is treated literally, except that escaping can still be used to escape (e.g.) double quotes and the escape character itself. Outside of single quotes, a backslash .RB ` \e ' causes the following character to be included in a word regardless of its usual meaning. (None of this allows a newline character to be included in a word: this is simply not possible.) A word which is .RB ` \-\- ' before processing quoting and escaping marks the end of embedded options. As a concession to Emacs users, if the sequence .RB ` \-*\- ' appears at the start of a word before processing quoting and escaping, then everything up to and including the next occurrence of .RB ` \-*\- ' is ignored. The resulting list of words is processed as if it held further command-line options. However, .B runlisp is now committed to .I script mode, so .RB ` \-e ', .RB ` \-l ', and .RB ` \-p ' options may not appear in a script file's embedded options list. (This feature allows scripts to provide options even if they use .BR env (1) to find .B runlisp on the .BR PATH , or to provide more than one option, since many operating systems pass the text following the interpreter name on a .RB ` #! ' line as a single argument, without further splitting it at spaces.) .PP If a file named .B .runlisprc exists in the user's home directory, then this file is read to discover more options. (If the variable .B HOME is set in the environment, then its value is assumed to name the user's home directory; otherwise, the home directory is determined by looking up the process's real uid in the password database.) Lines consisting entirely of whitespace, and lines whose first whitespace character is either .RB ` # ' or .RB ` ; ' are ignored in this file. Other lines are split into words, and processed as additional command-line options, as described for embedded options above, except that: a .RB ` \-\- ' marker does not terminate word splitting; and Emacs-style .RB ` \-*\- ... \-*\- ' local variable lists are not ignored. Each line is processed separately, so an option and its argument must be written on the same line. By this point .B runlisp will have committed to .I script or .I eval mode, so .RB ` \-e ', .RB ` \-l ', and .RB ` \-p ' options may not appear in a configuration file. .PP If a file .B runlisprc exists in the user's .I "configuration home" directory, then it is processed as for .B .runlisprc above. If a variable .B XDG_CONFIG_HOME is set in the environment, then its value is assumed to name the configuration home; otherwise, the configuration home is the directory .B .config in the user's home directory, as determined above. .PP If the variable .B RUNLISP_OPTIONS is set in the environment, then its value is split into words and processed as additional command-line options, as for a line of a configuration file as described above. .PP The list of .I "acceptable Lisp implementations" is determined. If any .RB ` \-L ' options have been issued, then the list of acceptable implementations consists of all of the implementations mentioned in .RB ` -L ' options in any of the places .B runlisp looked for options, in the order of their first occurrence. (If an implementation is named more than once, then .B runlisp prints a warning to stderr and ignores all but the first occurrence.) If no .RB ` \-L ' option is given, then .B runlisp uses a default list, which consists of all of the supported Lisp implementations in an hardcoded order which reflects the author's arbitrary preferences. .PP The list of .I "preferred Lisp implementations" is determined. If any .RB ` \-P ' options have been issued .I "since the last" .IB ` \-C ' .IR "option" , then the list of preferred implementations consists of all of the implementations mentioned in .RB ` \-P ' options after the last occurrence of .RB ` \-C ', in the order of their first occurrences. (If an implementation is named more than once, then .B runlisp prints a warning to stderr and ignores all but the first occurrence.) If no .RB ` \-P ' option is given, or a .RB ` \-C ' option appears after all of the .RB ` \-P ' options, then the list of preferred implementations is empty. .PP Acceptable Lisp implementations are tried in turn. First, the preferred implementations which are also listed as acceptable implementations are tried, in the order in which they appear in the preferred implementations list; then, the remaining acceptable implementations are tried in the order in which they appear in the acceptable implementations list. To .I try a Lisp implementation means to construct a command line (whose effect will be described below) and pass it to the .BR execvp (3) function. If that succeeds, the Lisp implementation runs; if it fails with .B ENOENT then other Lisp systems are tried; if it fails with some other error, then .B runlisp reports an error message to stderr and exits unsuccessfully (with code 127). If the .RB ` \-n ' option was given, then .B runlisp just simulates the behaviour of .BR execvp (3), printing messages to stderr if the verbosity level is sufficiently high, and exits. .PP In .I script mode, the script is invoked. In .I eval mode, the instructions given in .RB ` \-e ', .RB ` \-l ', and .RB ` \-p ' options are carried out, in the order in which the appeared in the command line. The details of the environment in which Lisp code is executed are described next. . .SS "Script environment" Code in scripts and forms invoked by .B runlisp may assume the following facts about their environment. .hP \*o The keyword .B :runlisp-script is added to the .B *features* list if .B runlisp is running in .I script mode. .hP \*o Most Lisp systems support a user initialization file which they load before entering the REPL; some also have a system initialization file. The .B runlisp program arranges .I not to read these files, so that the Lisp environment is reasonably predictable, and to avoid slowing down script startup with things which are convenient for use in an interactive session, but can't be relied upon by a script anyway. .hP \*o The Unix standard input, standard output, and standard error files are available through the Lisp .BR *standard-input* , .BR *standard-output* , and .BR *error-output* streams, respectively. .hP \*o Both .B *compile-verbose* and .B *load-verbose* are set to nil. On CMU\ CL, .B ext:*require-verbose* is also nil. Alas, this is insufficient to muffle noise while loading add-on systems on some implementations. .hP \*o If an error is signalled, and not caught by user code, then the process will print a message to stderr and exit with a nonzero status. The reported message may be a long, ugly backtrace, or a terse error report. If no error is signalled but not caught, then the process will exit with status 0. .hP \*o The initial package is .BR COMMON-LISP-USER , which has no symbols `present' (i.e., imported or interned). .hP \*o The .B asdf and .B uiop systems are already loaded. Further systems can be loaded using .B asdf:load-system as usual. The script name (which is only meaningful if .B runlisp is in .I script mode, obviously) and arguments are available through the .B uiop:argv0 function and .B uiop:*command-line-arguments* variable, respectively. . .\"-------------------------------------------------------------------------- . .SH "BUGS" .hP \*o Loading ASDF systems is irritatingly noisy with some Lisp implementations. Suggestions for how to improve this are welcome. .hP \*o More Lisp implementations should be supported. I've supported the ones I have installed. I'm not willing to put a great deal of effort into supporting non-free Lisp implementations; but help supporting free Lisps is much appreciated. .hP \*o The protocol for passing the script name through to .B uiop (specifically, through the .B __CL_ARGV0 environment variable) is terribly fragile, but supporting .B uiop is obviously a better approach than introducing a .BR runlisp -specific interface to the same information. I don't know how to fix this: suggestions are welcome. . .SH "SEE ALSO" .BR dump-runlisp-image (1). . .SH "AUTHOR" Mark Wooding, . .\"----- That's all, folks --------------------------------------------------