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
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.
17 ;; Values may contain substitutions:
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.)
22 ;; * $?[SECTION:]VAR{YES[|NO]} -- look up VAR in SECTION (or in the
23 ;; (original) current section, and `@COMMON'); if found, use YES,
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.)
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.
38 ;;;--------------------------------------------------------------------------
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.
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.
56 (set-dispatch-macro-character
58 (lambda (#1000=#:stream #1001=#:char #1002=#:arg)
59 (declare (ignore #1001# #1002#))
60 (values (read-line #1000#))))
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.
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)
71 (declare (ignore #1204#))
72 (unless #1202# (return))
73 (unintern #1203# #1200#)))))
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
79 (pushnew :runlisp-script *features*)
81 ;; Load the system's ASDF.
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"))))))
107 ;; Upgrade ASDF from the source registry.
109 (funcall (intern "UPGRADE-ASDF" (find-package "ASDF")))
111 ;; Common actions when resuming a custom image.
113 (uiop:call-image-restore-hook)
115 ;; Common prelude for script startup in vanilla images. Most of this is
116 ;; already done in custom images.
119 (setf *load-verbose* nil *compile-verbose* nil)
121 ${inhibit-asdf-upgrade}
123 ${set-script-feature})
125 ;; Common prelude for dumping images.
130 ${inhibit-asdf-upgrade}
132 ${set-script-feature})
134 ;; An expression to determine the version information for the running Lisp.
137 (lisp-implementation-type)
138 (multiple-value-list (lisp-implementation-version)))
140 (asdf:component-version (asdf:find-system "asdf"))))
142 ;; Full pathname to custom image.
143 image-path = ${@image-dir}/${image-file}
145 ;;;--------------------------------------------------------------------------
148 command = ${@ENV:SBCL?sbcl}
149 image-file = ${@name}+asdf.core
152 ${command} --noinform
153 $?@image{--core "${image-path}" --eval "${image-restore}" |
154 --eval "${run-script-prelude}"}
155 --script "${@script}"
158 ${command} --noinform --no-userinit --no-sysinit --disable-debugger
159 --eval "${dump-image-prelude}"
160 --eval "(sb-ext:save-lisp-and-die \"${@image-new|q}\")"
162 ;;;--------------------------------------------------------------------------
165 command = ${@ENV:CCL?ccl}
166 image-file = ${@name}+asdf.image
170 $?@image{-I "${image-path}" -e "${image-restore}" |
171 -e "${run-script-prelude}"}
172 -l "${@script}" -e "(ccl:quit)" --
174 ;; A snaglet occurs here. CCL wants to use the image name as a clue to where
175 ;; the rest of its installation is; but in fact the image is nowhere near its
176 ;; installation. So we must hack...
179 -e "${dump-image-prelude}"
180 -e "(ccl::in-development-mode
181 (let ((#0=#:real-ccl-dir (ccl::ccl-directory)))
182 (defun ccl::ccl-directory ()
184 (ccl:getenv \"CCL_DEFAULT_DIRECTORY\")))
185 (if (and #1# (plusp (length (namestring #1#))))
186 (ccl::native-to-directory-pathname #1#)
188 (compile 'ccl::ccl-directory))"
189 -e "(ccl:save-application \"${@image-new|q}\"
191 :error-handler :quit)"
193 ;;;--------------------------------------------------------------------------
196 ;; CLisp causes much sadness. Superficially, it's the most sensible of all
197 ;; of the systems supported here: you just run `clisp SCRIPT -- ARGS ...' and
200 ;; The problems come when you want to do some preparatory work (e.g., load
201 ;; `asdf') and then run the script. There's a `-x' option to evaluate some
202 ;; Lisp code, but it has three major deficiencies.
204 ;; * It insists on printing the values of the forms it evaluates. It
205 ;; prints a blank line even if the form goes out of its way to produce no
206 ;; values at all. So the whole thing has to be a single top-level form
207 ;; which quits the Lisp rather than returning.
209 ;; * For some idiotic reason, you can have /either/ `-x' forms /or/ a
210 ;; script, but not both. So we have to include the `load' here
211 ;; explicitly. I suppose that was inevitable because we have to inhibit
212 ;; printing of the result forms, but it's still a separate source of
215 ;; * The icing on the cake: the `-x' forms are collectively concatenated --
216 ;; without spaces! -- and used to build a string stream, which is then
217 ;; assigned over the top of `*standard-input*', making the original stdin
218 ;; somewhat fiddly to track down.
220 ;; There's a `-i' option which will load a file without any of this
221 ;; stupidity, but nothing analogous for immediate expressions.
223 clisp-common-startup =
224 (setf *standard-input* (ext:make-stream :input))
225 (load "${@script|q}" :verbose nil :print nil)
228 command = ${@ENV:CLISP?clisp}
229 image-file = ${@name}+asdf.mem
233 $?@image{-M "${image-path}" -q
236 ${clisp-common-startup})" |
239 ${run-script-prelude}
240 ${clisp-common-startup})"}
244 ${command} -norc -q -q
245 -x "${dump-image-prelude}"
246 -x "(ext:saveinitmem \"${@image-new|q}\" :norc t :script t)"
248 ;;;--------------------------------------------------------------------------
251 command = ${@ENV:ECL?ecl}
252 image-file = ${@name}+asdf
255 $?@image{"${image-path}" -s "${@script}" |
256 ${@ENV:ECL?ecl} "${@ecl-opt}norc"
257 "${@ecl-opt}eval" "(progn
258 ${run-script-prelude}
260 "${@ecl-opt}shell" "${@script}"}
264 "${@data-dir}/dump-ecl"
265 "${@image-new}" "${command}" "${@ecl-opt}" "${@tmp-dir}"
267 ;;;--------------------------------------------------------------------------
270 command = ${@ENV:CMUCL?cmucl}
271 image-file = ${@name}+asdf.core
275 $?@image{-core "${image-path}" -eval "${image-restore}" |
276 -batch -noinit -quiet
280 (declare (ignore #0#))
283 (setf ext:*require-verbose* nil)
284 ${run-script-prelude}
286 -load "${@script}" -eval "(ext:quit)" --
289 ${command} -batch -noinit -quiet
290 -eval "(progn ${dump-image-prelude} ${clear-cl-user})"
291 -eval "(ext:save-lisp \"${@image-new|q}\"
292 :batch-mode t :print-herald nil
293 :site-init nil :load-init-file nil)"
295 ;;;--------------------------------------------------------------------------
298 ;; CLisp made a worthy effort, but ABCL still manages to take the prize.
300 ;; * ABCL manages to avoid touching the `stderr' stream at all, ever. Its
301 ;; startup machinery finds `stdout' (as `java.lang.System.out'), wraps it
302 ;; up in a Lisp stream, and uses the result as `*standard-output*' and
303 ;; `*error-output*' (and a goodly number of other things too). So we
304 ;; must manufacture a working `stderr' the hard way.
306 ;; * There doesn't appear to be any easy way to prevent toplevel errors
307 ;; from invoking the interactive debugger. For extra fun, the debugger
308 ;; reads from `stdin' by default, so an input file which somehow manages
309 ;; to break the script can then take over its brain by providing Lisp
310 ;; forms for the debugger to evaluate.
312 ;; * And, just to really top everything off, ABCL's `adjoin.lisp' is
313 ;; missing an `(in-package ...)' form at the top, so it leaks symbols
314 ;; into the `COMMON-LISP-USER' package.
316 command = ${@ENV:ABCL?abcl}
319 (let ((#0=#:script "${@script|q}"))
320 ${run-script-prelude}
323 (java:jnew "org.armedbear.lisp.Stream"
325 (java:jfield "java.lang.System" "err")
328 (handler-case (load #0# :verbose nil :print nil)
330 (format *error-output* "~A (unhandled error): ~A~%" #0# error)
331 (ext:quit :status 255))))
334 ${command} --batch --noinform --noinit --nosystem
335 --eval "${abcl-startup}"
338 ;;;----- That's all, folks --------------------------------------------------