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