chiark / gitweb /
@@@ work in progress
[runlisp] / runlisp.conf
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.
43 ignore-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.
54 clear-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.
66 set-script-feature =
67         (pushnew :runlisp-script *features*)
68
69 ;; Load the system's ASDF.
70 require-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.
77 inhibit-asdf-upgrade =
78         (funcall (intern "REGISTER-IMMUTABLE-SYSTEM"
79                          (find-package "ASDF"))
80                  "asdf")
81
82 ;; Upgrade ASDF from the source registry.
83 upgrade-asdf =
84         (funcall (intern "UPGRADE-ASDF" (find-package "ASDF")))
85
86 ;; Common actions when resuming a custom image.
87 image-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.
92 run-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.
101 dump-image-prelude =
102         (progn
103           ${require-asdf}
104           ${upgrade-asdf}
105           ${inhibit-asdf-upgrade}
106           ${ignore-shebang}
107           ${set-script-feature})
108
109 image-path = ${@CONFIG:image-dir}/${image-file}
110
111 ;;;--------------------------------------------------------------------------
112 [sbcl]
113
114 command = ${@ENV:SBCL?sbcl}
115 image-file = sbcl+asdf.core
116
117 run-script =
118         ${command} --noinform
119                 $?@IMAGE{--core "${image-path}" --eval "${image-restore}" |
120                          --eval "${run-script-prelude}"}
121                 --script ${@SCRIPT}
122
123 dump-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
132 command = ${@ENV:CCL?ccl}
133 image-file = ccl+asdf.image
134
135 run-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...
144 dump-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
190 clisp-common-startup =
191         (setf *standard-input* (ext:make-stream :input))
192         (load "${@SCRIPT|q}" :verbose nil :print nil)
193         (ext:quit)
194
195 command = ${@ENV:CLISP?clisp}
196 image-file = clisp+asdf.mem
197
198 run-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
210 dump-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
218 command = ${@ENV:ECL?ecl}
219 image-file = ecl+asdf
220
221 run-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
230 dump-image =
231         "${@CONFIG:data-dir}/dump-ecl"
232                 "${@IMAGE}" "${command}" "${@ECLOPT}" "${@TMPDIR}"
233
234 ;;;--------------------------------------------------------------------------
235 [cmucl]
236
237 command = ${@ENV:CMUCL?cmucl}
238 image-file = cmucl+asdf.core
239
240 run-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
249 dump-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
277 command = ${@ENV:ABCL?abcl}
278
279 abcl-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
294 run-script =
295         ${command} --batch --noinform --noinit --nosystem
296                 --eval "${abcl-startup}"
297                 --
298
299 ;;;----- That's all, folks --------------------------------------------------