| 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 | run-script = |
| 152 | ${command} --noinform |
| 153 | $?@image{--core "${image-path}" --eval "${image-restore}" | |
| 154 | --eval "${run-script-prelude}"} |
| 155 | --script "${@script}" |
| 156 | |
| 157 | dump-image = |
| 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}\")" |
| 161 | |
| 162 | ;;;-------------------------------------------------------------------------- |
| 163 | [ccl] |
| 164 | |
| 165 | command = ${@ENV:CCL?ccl} |
| 166 | image-file = ${@name}+asdf.image |
| 167 | |
| 168 | run-script = |
| 169 | ${command} -b -n -Q |
| 170 | $?@image{-I "${image-path}" -e "${image-restore}" | |
| 171 | -e "${run-script-prelude}"} |
| 172 | -l "${@script}" -e "(ccl:quit)" -- |
| 173 | |
| 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... |
| 177 | dump-image = |
| 178 | ${command} -b -n -Q |
| 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 () |
| 183 | (let* ((#1=#:dirpath |
| 184 | (ccl:getenv \"CCL_DEFAULT_DIRECTORY\"))) |
| 185 | (if (and #1# (plusp (length (namestring #1#)))) |
| 186 | (ccl::native-to-directory-pathname #1#) |
| 187 | #0#)))) |
| 188 | (compile 'ccl::ccl-directory))" |
| 189 | -e "(ccl:save-application \"${@image-new|q}\" |
| 190 | :init-file nil |
| 191 | :error-handler :quit)" |
| 192 | |
| 193 | ;;;-------------------------------------------------------------------------- |
| 194 | [clisp] |
| 195 | |
| 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 |
| 198 | ;; it works. |
| 199 | ;; |
| 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. |
| 203 | ;; |
| 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. |
| 208 | ;; |
| 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 |
| 213 | ;; annoyance. |
| 214 | ;; |
| 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. |
| 219 | ;; |
| 220 | ;; There's a `-i' option which will load a file without any of this |
| 221 | ;; stupidity, but nothing analogous for immediate expressions. |
| 222 | |
| 223 | clisp-common-startup = |
| 224 | (setf *standard-input* (ext:make-stream :input)) |
| 225 | (load "${@script|q}" :verbose nil :print nil) |
| 226 | (ext:quit) |
| 227 | |
| 228 | command = ${@ENV:CLISP?clisp} |
| 229 | image-file = ${@name}+asdf.mem |
| 230 | |
| 231 | run-script = |
| 232 | ${command} |
| 233 | $?@image{-M "${image-path}" -q |
| 234 | -x "(progn |
| 235 | ${image-restore} |
| 236 | ${clisp-common-startup})" | |
| 237 | -norc -q |
| 238 | -x "(progn |
| 239 | ${run-script-prelude} |
| 240 | ${clisp-common-startup})"} |
| 241 | -- |
| 242 | |
| 243 | dump-image = |
| 244 | ${command} -norc -q -q |
| 245 | -x "${dump-image-prelude}" |
| 246 | -x "(ext:saveinitmem \"${@image-new|q}\" :norc t :script t)" |
| 247 | |
| 248 | ;;;-------------------------------------------------------------------------- |
| 249 | [ecl] |
| 250 | |
| 251 | command = ${@ENV:ECL?ecl} |
| 252 | image-file = ${@name}+asdf |
| 253 | |
| 254 | run-script = |
| 255 | $?@image{"${image-path}" -s "${@script}" | |
| 256 | ${@ENV:ECL?ecl} "${@ecl-opt}norc" |
| 257 | "${@ecl-opt}eval" "(progn |
| 258 | ${run-script-prelude} |
| 259 | ${clear-cl-user})" |
| 260 | "${@ecl-opt}shell" "${@script}"} |
| 261 | -- |
| 262 | |
| 263 | dump-image = |
| 264 | "${@data-dir}/dump-ecl" |
| 265 | "${@image-new}" "${command}" "${@ecl-opt}" "${@tmp-dir}" |
| 266 | |
| 267 | ;;;-------------------------------------------------------------------------- |
| 268 | [cmucl] |
| 269 | |
| 270 | command = ${@ENV:CMUCL?cmucl} |
| 271 | image-file = ${@name}+asdf.core |
| 272 | |
| 273 | run-script = |
| 274 | ${command} |
| 275 | $?@image{-core "${image-path}" -eval "${image-restore}" | |
| 276 | -batch -noinit -quiet |
| 277 | -eval "(handler-bind |
| 278 | ((warning |
| 279 | (lambda (#0=#:c) |
| 280 | (declare (ignore #0#)) |
| 281 | (invoke-restart |
| 282 | 'muffle-warning)))) |
| 283 | (setf ext:*require-verbose* nil) |
| 284 | ${run-script-prelude} |
| 285 | ${clear-cl-user})"} |
| 286 | -load "${@script}" -eval "(ext:quit)" -- |
| 287 | |
| 288 | dump-image = |
| 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)" |
| 294 | |
| 295 | ;;;-------------------------------------------------------------------------- |
| 296 | [abcl] |
| 297 | |
| 298 | ;; CLisp made a worthy effort, but ABCL still manages to take the prize. |
| 299 | ;; |
| 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. |
| 305 | ;; |
| 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. |
| 311 | ;; |
| 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. |
| 315 | |
| 316 | command = ${@ENV:ABCL?abcl} |
| 317 | |
| 318 | abcl-startup = |
| 319 | (let ((#0=#:script "${@script|q}")) |
| 320 | ${run-script-prelude} |
| 321 | ${clear-cl-user} |
| 322 | (setf *error-output* |
| 323 | (java:jnew "org.armedbear.lisp.Stream" |
| 324 | \'sys::system-stream |
| 325 | (java:jfield "java.lang.System" "err") |
| 326 | \'character |
| 327 | java:+true+)) |
| 328 | (handler-case (load #0# :verbose nil :print nil) |
| 329 | (error (error) |
| 330 | (format *error-output* "~A (unhandled error): ~A~%" #0# error) |
| 331 | (ext:quit :status 255)))) |
| 332 | |
| 333 | run-script = |
| 334 | ${command} --batch --noinform --noinit --nosystem |
| 335 | --eval "${abcl-startup}" |
| 336 | -- |
| 337 | |
| 338 | ;;;----- That's all, folks -------------------------------------------------- |