Commit | Line | Data |
---|---|---|
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. | |
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 -------------------------------------------------- |