@@@ work in progress
[runlisp] / runlisp.conf
CommitLineData
7b8ff279
MW
1;;; -*-conf-windows-*-
2
3;; Summary of syntax.
4;;
5;; Sections are started with a line `[NAME]', starting in the leftmost
6;; column. Empty lines and lines starting with `;' -- /without/ preceding
7;; whitespace -- are ignored. Assignments have the form `VAR = VALUE'; the
8;; VALUE may be continued across multiple lines, if they begin with
9;; whitespace. All of the lines are stripped of initial and final whitespace
10;; and concatenated with spaces.
11;;
12;; Values may contain substitutions:
13;;
14;; * ${[SECTION:]VAR[?ALT]} -- replace with the value of VAR in SECTION; if
15;; not found, use ALT instead. (If ALT isn't provided, it's an error.)
16;;
17;; * $?[SECTION:]VAR{YES[|NO]} -- look up VAR in SECTION (or in the
18;; (original) current section, and `@COMMON'); if found, use YES,
19;; otherwise use NO.
20;;
21;; Variables are looked up starting in the home (or explicitly specified)
22;; section, then proceeding to the parents assigned to `@PARENTS'.
23;; (`@PARENTS' usually defaults to `@COMMON'; the parent of `@COMMON' is
24;; `@BUILTIN'; `@BUILTIN' and `@CONFIG' have no parents.)
25;;
26;; At top-level, the text is split into words at whitespace, unless prevented
27;; by double- and single-quote, or escaped by `\'. Within single quotes, all
28;; characters are treated literally. Within double quotes, `\' and `$' still
29;; works. A variable reference within quotes, or within a word, suppresses
30;; word-splitting and quoting, within the variable value -- but `$'
31;; expansions still work.
32
33;;;--------------------------------------------------------------------------
34[@COMMON]
35
36;; Turn `#!' into a comment-to-end-of-line. This is used in all Lisp
37;; invocations, even though some of them don't apparently need it. For
38;; example, SBCL ignores an initial line beginning `#!' as a special feature
39;; of its `--script' option. Other Lisps won't do this, so a countermeasure
40;; like the following is necessary in their case. For the sake of a
41;; consistent environment, we ignore `#!' lines everywhere, even in Lisps
42;; which have their own, more specific, solution to this problem.
43ignore-shebang =
44 (set-dispatch-macro-character
45 #\\# #\\!
46 (lambda (#1=#:stream #2=#:char #3=#:arg)
47 (declare (ignore #2# #3#))
48 (values (read-line #1#))))
49
50;; Clear all present symbols from the `COMMON-LISP-USER' package. Some Lisps
51;; leave débris in `COMMON-LISP-USER' -- for example, ECL leaves some
52;; allegedly useful symbols lying around, while ABCL has a straight-up bug in
53;; its `adjoin.lisp' file.
54clear-cl-user =
55 (let ((#4=#:pkg (find-package "COMMON-LISP-USER")))
56 (with-package-iterator (#5=#:next #4# :internal)
57 (loop (multiple-value-bind (#6=#:anyp #7=#:sym #8=#:how)
58 (#5#)
59 (declare (ignore #8#))
60 (unless #6# (return))
61 (unintern #7# #4#)))))
62
63;; Add `:runlisp-script' to `*features*' so that scripts can tell whether
64;; they're supposed to sit quietly and be debugged in a Lisp session or run
65;; as a script.
66set-script-feature =
67 (pushnew :runlisp-script *features*)
68
69;; Load the system's ASDF.
70require-asdf =
71 (require "asdf")
72
73;; Prevent ASDF from upgrading itself. Otherwise it will do this
74;; automatically if a script invokes `asdf:load-system', but that will have a
75;; bad effect on startup time, and risks spamming the output streams with
76;; drivel.
77inhibit-asdf-upgrade =
78 (funcall (intern "REGISTER-IMMUTABLE-SYSTEM"
79 (find-package "ASDF"))
80 "asdf")
81
82;; Upgrade ASDF from the source registry.
83upgrade-asdf =
84 (funcall (intern "UPGRADE-ASDF" (find-package "ASDF")))
85
86;; Common actions when resuming a custom image.
87image-restore =
88 (uiop:call-image-restore-hook)
89
90;; Common prelude for script startup in vanilla images. Most of this is
91;; already done in custom images.
92run-script-prelude =
93 (progn
94 (setf *load-verbose* nil *compile-verbose* nil)
95 ${require-asdf}
96 ${inhibit-asdf-upgrade}
97 ${ignore-shebang}
98 ${set-script-feature})
99
100;; Common prelude for dumping images.
101dump-image-prelude =
102 (progn
103 ${require-asdf}
104 ${upgrade-asdf}
105 ${inhibit-asdf-upgrade}
106 ${ignore-shebang}
107 ${set-script-feature})
108
109image-path = ${@CONFIG:image-dir}/${image-file}
110
111;;;--------------------------------------------------------------------------
112[sbcl]
113
114command = ${@ENV:SBCL?sbcl}
115image-file = sbcl+asdf.core
116
117run-script =
118 ${command} --noinform
119 $?@IMAGE{--core "${image-path}" --eval "${image-restore}" |
120 --eval "${run-script-prelude}"}
121 --script ${@SCRIPT}
122
123dump-image =
124 ${command} --noinform --no-userinit --no-sysinit --disable-debugger
125 --eval "${dump-image-prelude}"
126 --eval "(sb-ext:save-lisp-and-die \"${@IMAGE|q}\")"
127
128
129;;;--------------------------------------------------------------------------
130[ccl]
131
132command = ${@ENV:CCL?ccl}
133image-file = ccl+asdf.image
134
135run-script =
136 ${command} -b -n -Q
137 $?@IMAGE{-I "${image-path}" -e "${image-restore}" |
138 -e "${run-script-prelude}"}
139 -l ${@SCRIPT} -e "(ccl:quit)" --
140
141;; A snaglet occurs here. CCL wants to use the image name as a clue to where
142;; the rest of its installation is; but in fact the image is nowhere near its
143;; installation. So we must hack...
144dump-image =
145 ${command} -b -n -Q
146 -e "${dump-image-prelude}"
147 -e "(ccl::in-development-mode
148 (let ((#1=#:real-ccl-dir (ccl::ccl-directory)))
149 (defun ccl::ccl-directory ()
150 (let* ((#2=#:dirpath
151 (ccl:getenv \"CCL_DEFAULT_DIRECTORY\")))
152 (if (and #2# (plusp (length (namestring #2#))))
153 (ccl::native-to-directory-pathname #2#)
154 #1#))))
155 (compile 'ccl::ccl-directory))"
156 -e "(ccl:save-application \"${@IMAGE|q}\"
157 :init-file nil
158 :error-handler :quit)"
159
160;;;--------------------------------------------------------------------------
161[clisp]
162
163;; CLisp causes much sadness. Superficially, it's the most sensible of all
164;; of the systems supported here: you just run `clisp SCRIPT -- ARGS ...' and
165;; it works.
166;;
167;; The problems come when you want to do some preparatory work (e.g., load
168;; `asdf') and then run the script. There's a `-x' option to evaluate some
169;; Lisp code, but it has three major deficiencies.
170;;
171;; * It insists on printing the values of the forms it evaluates. It
172;; prints a blank line even if the form goes out of its way to produce no
173;; values at all. So the whole thing has to be a single top-level form
174;; which quits the Lisp rather than returning.
175;;
176;; * For some idiotic reason, you can have /either/ `-x' forms /or/ a
177;; script, but not both. So we have to include the `load' here
178;; explicitly. I suppose that was inevitable because we have to inhibit
179;; printing of the result forms, but it's still a separate source of
180;; annoyance.
181;;
182;; * The icing on the cake: the `-x' forms are collectively concatenated --
183;; without spaces! -- and used to build a string stream, which is then
184;; assigned over the top of `*standard-input*', making the original stdin
185;; somewhat fiddly to track down.
186;;
187;; There's a `-i' option which will load a file without any of this
188;; stupidity, but nothing analogous for immediate expressions.
189
190clisp-common-startup =
191 (setf *standard-input* (ext:make-stream :input))
192 (load "${@SCRIPT|q}" :verbose nil :print nil)
193 (ext:quit)
194
195command = ${@ENV:CLISP?clisp}
196image-file = clisp+asdf.mem
197
198run-script =
199 ${command}
200 $?@IMAGE{-M "${image-path}" -q
201 -x "(progn
202 ${image-restore}
203 ${clisp-common-startup})" |
204 -norc -q
205 -x "(progn
206 ${run-script-prelude}
207 ${clisp-common-startup})"}
208 --
209
210dump-image =
211 ${command} -norc -q -q
212 -x "${dump-image-prelude}"
213 -x "(ext:saveinitmem \"${@IMAGE|q}\" :norc t :script t)"
214
215;;;--------------------------------------------------------------------------
216[ecl]
217
218command = ${@ENV:ECL?ecl}
219image-file = ecl+asdf
220
221run-script =
222 $?@IMAGE{"${image-path}" -s ${@SCRIPT} |
223 ${@ENV:ECL?ecl} "${@ECLOPT}norc"
224 "${@ECLOPT}eval" "(progn
225 ${run-script-prelude}
226 ${clear-cl-user})"
227 "${@ECLOPT}shell" ${@SCRIPT}}
228 --
229
230dump-image =
231 "${@CONFIG:data-dir}/dump-ecl"
232 "${@IMAGE}" "${command}" "${@ECLOPT}" "${@TMPDIR}"
233
234;;;--------------------------------------------------------------------------
235[cmucl]
236
237command = ${@ENV:CMUCL?cmucl}
238image-file = cmucl+asdf.core
239
240run-script =
241 ${command}
242 $?@IMAGE{-core "${image-path}" -eval "${image-restore}" |
243 -batch -noinit -nositeinit -quiet
244 -eval "(progn
245 (setf ext:*require-verbose* nil)
246 ${run-script-prelude})"}
247 -load ${@SCRIPT} -eval "(ext:quit)" --
248
249dump-image =
250 ${command} -batch -noinit -nositeinit -quiet
251 -eval "${dump-image-prelude}"
252 -eval "(ext:save-lisp \"${@IMAGE|q}\"
253 :batch-mode t :print-herald nil
254 :site-init nil :load-init-file nil)"
255
256;;;--------------------------------------------------------------------------
257[abcl]
258
259;; CLisp made a worthy effort, but ABCL still manages to take the prize.
260;;
261;; * ABCL manages to avoid touching the `stderr' stream at all, ever. Its
262;; startup machinery finds `stdout' (as `java.lang.System.out'), wraps it
263;; up in a Lisp stream, and uses the result as `*standard-output*' and
264;; `*error-output*' (and a goodly number of other things too). So we
265;; must manufacture a working `stderr' the hard way.
266;;
267;; * There doesn't appear to be any easy way to prevent toplevel errors
268;; from invoking the interactive debugger. For extra fun, the debugger
269;; reads from `stdin' by default, so an input file which somehow manages
270;; to break the script can then take over its brain by providing Lisp
271;; forms for the debugger to evaluate.
272;;
273;; * And, just to really top everything off, ABCL's `adjoin.lisp' is
274;; missing an `(in-package ...)' form at the top, so it leaks symbols
275;; into the `COMMON-LISP-USER' package.
276
277command = ${@ENV:ABCL?abcl}
278
279abcl-startup =
280 (let ((#9=#:script "${@SCRIPT|q}"))
281 ${run-script-prelude}
282 ${clear-cl-user}
283 (setf *error-output*
284 (java:jnew "org.armedbear.lisp.Stream"
285 \'sys::system-stream
286 (java:jfield "java.lang.System" "err")
287 \'character
288 java:+true+))
289 (handler-case (load #9# :verbose nil :print nil)
290 (error (error)
291 (format *error-output* "~A (unhandled error): ~A~%" #9# error)
292 (ext:quit :status 255))))
293
294run-script =
295 ${command} --batch --noinform --noinit --nosystem
296 --eval "${abcl-startup}"
297 --
298
299;;;----- That's all, folks --------------------------------------------------