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