Newer
Older
SOFTWARE_FILE=.
SOFTWARE_SYSTEM=
SOFTWARE_INIT_FORMS=
SYSTEMS_PATHS=
INCLUDE_PATH=
LISPS="sbcl clisp ccl cmucl ecl gclcvs allegro lispworks lisp gcl"
WRAPPER_CODE=
DUMP=
RESTART=
IMAGE_BASE=
IMAGE_DIR=
IMAGE=
# END OF CL-LAUNCH CONFIGURATION
# This file was generated by CL-Launch 2.16
# This file was automatically generated and contains parts of CL-Launch
#
# Please send your improvements to the author:
# fare at tunes dot org < http://www.cliki.net/Fare%20Rideau >.
#
# CL-Launch is available under the terms of the bugroff license.
# http://www.geocities.com/SoHo/Cafe/5947/bugroff.html
# You may at your leisure use the LLGPL instead < http://www.cliki.net/LLGPL >
#
# This software can be used in conjunction with any other software:
# the result may consist in pieces of the two software glued together in
# a same file, but even then these pieces remain well distinguished, and are
# each available under its own copyright and licensing terms, as applicable.
# The parts that come from the other software are subject to the terms of use
# and distribution relative to said software, which may well be
# more restrictive than the terms of this software (according to lawyers
# and the armed henchmen they got the taxpayers to pay to enforce their laws).
# The bits of code generated by cl-launch, however, remain available
# under the terms of their own license, and you may service them as you wish:
# manually, using cl-launch --update or whichever means you prefer.
# That said, if you believe in any of that intellectual property scam,
# you may be subject to the terms of my End-Seller License:
# http://www.livejournal.com/users/fare/21806.html
#
PROG="$0"
# Find and execute the most appropriate supported Lisp implementation
# to evaluate software prepared with CL-Launch.
#
ECHOn () { printf '%s' "$*" ;}
simple_term_p () {
case "$1" in *[!a-zA-Z0-9-+_,.:=%/]*) return 1 ;; *) return 0 ;; esac
}
kwote0 () { ECHOn "$1" | sed -e "s/\([\\\\\"\$\`]\)/\\\\\\1/g" ;}
kwote () { if simple_term_p "$1" ; then ECHOn "$1" ; else kwote0 "$1" ; fi ;}
load_form_0 () { echo "(load $1 :verbose nil :print nil)" ;}
load_form () { load_form_0 "\"$(kwote "$1")\"" ;}
ECHO () { printf '%s\n' "$*" ;}
DBG () { ECHO "$*" >& 2 ;}
abort () { ERR="$1" ; shift ; DBG "$*" ; exit "$ERR" ;}
ABORT () { abort 42 "$*" ;}
DO_LISP=do_exec_lisp
HASH_BANG_FORM='(set-dispatch-macro-character #\# #\! #'\''(lambda(stream char arg)(declare(ignore char arg))(values (read-line stream))))'
PACKAGE_FORM=" #.(progn(defpackage :cl-launch (:use :cl))())"
MAYBE_PACKAGE_FORM=
implementation_cmucl () {
implementation "${CMUCL:-cmucl}" || return 1
OPTIONS="${CMUCL_OPTIONS:- -quiet -noinit}"
EVAL=-eval
ENDARGS=--
IMAGE_ARG=-core
EXEC_LISP=exec_lisp_noarg
# exec_lisp works fine, except in the corner case when the program's user
# would use arguments that cmucl would process as its own arguments, even
# though they are meant for the Lisp program. cmucl provides no way to
# specify that arguments after "--" don't really matter.
# And so we use exec_lisp_noarg.
BIN_ARG=CMUCL
OPTIONS_ARG=CMUCL_OPTIONS
if [ -z "$CL_LAUNCH_DEBUG" ] ; then
OPTIONS="${OPTIONS} -batch"
fi
}
implementation_lisp () {
implementation ${CMULISP:=lisp} || return 1
CMUCL=$CMULISP
implementation_cmucl "$@"
}
implementation_sbcl () {
implementation "${SBCL:-sbcl}" || return 1
OPTIONS="${SBCL_OPTIONS:- --noinform --userinit /dev/null}"
# We purposefully specify --userinit /dev/null but NOT --sysinit /dev/null
EVAL=--eval # SBCL's eval can only handle one form per argument.
ENDARGS=--end-toplevel-options
IMAGE_ARG="EXECUTABLE_IMAGE" # we use executable images
# if you want to test non-executable images, uncomment the one below,
# and comment out the :executable t in (defun dump-image ...)
# -IMAGE_ARG=--core
STANDALONE_EXECUTABLE=t # requires sbcl 1.0.21.24 or later.
EXEC_LISP=exec_lisp
BIN_ARG=SBCL
OPTIONS_ARG=SBCL_OPTIONS
if [ -z "$CL_LAUNCH_DEBUG" ] ; then
OPTIONS="${OPTIONS} --disable-debugger"
fi
}
implementation_clisp () {
implementation "${CLISP:-clisp}" || return 1
OPTIONS="${CLISP_OPTIONS:- -norc --quiet --quiet}"
EVAL=-x
LOAD=-i
# if the first argument begins with - there might be problems,
# so we avoid that and take the cdr or ext:*args*
# IMAGE_ARG=-M # for use without :executable t
IMAGE_ARG="EXECUTABLE_IMAGE" # we don't use this by default
STANDALONE_EXECUTABLE=t # will mostly work as of clisp 2.44, but with a (in)security backdoor.
# For details, see the thread at http://sourceforge.net/forum/message.php?msg_id=5532730
EXEC_LISP=exec_lisp
BIN_ARG=CLISP
OPTIONS_ARG=CLISP_OPTIONS
if [ -z "$CL_LAUNCH_DEBUG" ] ; then
OPTIONS="${OPTIONS} -on-error exit"
else
OPTIONS="${OPTIONS} -on-error debug"
fi
implementation_lispworks () { ### NOT EXTENSIVELY TESTED
implementation "${LISPWORKS:-lispworks}" || return 1
OPTIONS="${LISPWORKS_OPTIONS:- -siteinit - -init -}" #
LOAD=-build #### No such thing found in the online documentation.
#! EVAL=-eval # No such thing found in the online documentation.
#! ENDARGS="--"
IMAGE_ARG="EXECUTABLE_IMAGE" # we don't use this by default
EXEC_LISP=exec_lisp_file
BIN_ARG=LISPWORKS
OPTIONS_ARG=LISPWORKS_OPTIONS
if [ -z "$CL_LAUNCH_DEBUG" ] ; then
: # OPTIONS="${OPTIONS} ..."
else
: # OPTIONS="${OPTIONS} ..."
fi
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
}
prepare_arg_form () {
ENDARGS= F=
for arg ; do
F="$F\"$(kwote "$arg")\""
done
MAYBE_PACKAGE_FORM="$PACKAGE_FORM"
LAUNCH_FORMS="(defparameter cl-launch::*arguments*'($F))${LAUNCH_FORMS}"
}
exec_lisp_noarg () {
prepare_arg_form "$@"
exec_lisp
}
exec_lisp_file () {
prepare_arg_form "$@"
LOADFILE=${TMP:-/tmp}/cl-load-file-$(date +%s)-$$
cat > $LOADFILE <<END
${MAYBE_PACKAGE_FORM}
${HASH_BANG_FORM}
${LAUNCH_FORMS}
END
$LISP_BIN $IMAGE_OPT $IMAGE $OPTIONS $LOAD "$LOADFILE"
RET=$?
rm -f $LOADFILE
exit $RET
}
implementation_clisp_noarg () {
implementation_clisp
EXEC_LISP=exec_lisp_noarg
# For testing purposes
}
implementation_clisp_file () {
implementation_clisp
EXEC_LISP=exec_lisp_file
# For testing purposes
}
implementation_ccl () {
# ClozureCL, nee OpenMCL, forked from MCL, formerly Macintosh Common Lisp, nee Coral Common Lisp
implementation "${CCL:-ccl}" || return 1
OPTIONS="${CCL_OPTIONS:- --no-init}"
# IMAGE_ARG=--image-name # -I
IMAGE_ARG=EXECUTABLE_IMAGE # depends on our using :prepend-kernel t
# (finish-output) is essential for ccl, that won't do it by default,
# unlike the other lisp implementations tested.
EXEC_LISP=exec_lisp
# exec_lisp will work great for 1.1 and later.
# For earlier versions, use exec_lisp_arg instead:
# 1.0 doesn't support --, and the latest 1.1-pre060826 snapshot has a bug
# whereby it doesn't stop at -- when looking for a -I or --image-file argument.
BIN_ARG=CCL
OPTIONS_ARG=CCL_OPTIONS
if [ -z "$CL_LAUNCH_DEBUG" ] ; then
OPTIONS="${OPTIONS} --batch"
fi
}
implementation_openmcl () {
implementation "${OPENMCL:=openmcl}" || return 1
CCL="$OPENMCL"
CCL_OPTIONS="$OPENMCL_OPTIONS"
implementation_ccl "$@" && BIN_ARG=OPENMCL
}
implementation_gcl () {
implementation "${GCL:-gcl}" || return 1
EVAL=-eval
ENDARGS=--
IMAGE_ARG=EXECUTABLE_IMAGE
BIN_ARG=GCL
OPTIONS_ARG=GCL_OPTIONS
export GCL_ANSI=t
EXEC_LISP=exec_lisp
if [ -z "$CL_LAUNCH_DEBUG" ] ; then
OPTIONS="${OPTIONS} -batch"
fi
}
implementation_ecl () {
implementation "${ECL:-ecl}" || return 1
OPTIONS="${ECL_OPTIONS:- -q -norc}"
EVAL=-eval
ENDARGS=--
#IMAGE_ARG="-q -load" # for :fasl
IMAGE_ARG="EXECUTABLE_IMAGE" # for :program
BIN_ARG=ECL
OPTIONS_ARG=ECL_OPTIONS
EXEC_LISP=exec_lisp
if [ -n "$CL_LAUNCH_DEBUG" ] ; then
PROGN="(handler-bind((error'invoke-debugger))(progn(set'si::*break-enable*'t)"
NGORP="))"
fi
# work around brokenness in c-l-c packaging of ECL,
# at least still as of ecl 0.9j-20080306-4 and c-l-c 6.17
if [ -z "$ECL" ] &&
[ "/usr/bin/ecl" = "$LISP_BIN" ] &&
[ -x "/usr/lib/ecl/ecl-original" ] ; then
LISP_BIN=/usr/lib/ecl/ecl-original
fi
}
implementation_gclcvs () {
implementation "${GCLCVS:=gclcvs}" || return 1
GCL="$GCLCVS"
implementation_gcl "$@" && BIN_ARG=GCLCVS
}
implementation_allegro () {
implementation "${ALLEGRO:-acl}" || return 1
OPTIONS="${ALLEGRO_OPTIONS:- -QQ -qq}"
EVAL=-e
ENDARGS=--
IMAGE_ARG=-I
EXEC_LISP=exec_lisp
BIN_ARG=ALLEGRO
OPTIONS_ARG=ALLEGRO_OPTIONS
if [ -z "$CL_LAUNCH_DEBUG" ] ; then
OPTIONS="${OPTIONS} -batch -backtrace-on-error"
fi
if [ -n "$USE_CLBUILD" ] ; then
if CLBUILD_BIN="`which clbuild 2> /dev/null`" ; then
LISP_BIN="$CLBUILD_BIN --implementation $IMPL lisp"
return 0
else
return 1
fi
elif [ -x "$1" ] ; then
elif LISP_BIN="`which "$1" 2> /dev/null`" ; then
return 0
else
return 1
fi
}
trylisp () {
IMPL="$1" ; shift
implementation_${IMPL} "$@"
}
do_exec_lisp () {
if [ -n "$IMAGE" ] ; then
if [ "x$IMAGE_ARG" = xEXECUTABLE_IMAGE ] ; then
LISP_BIN= IMAGE_OPT=
else
IMAGE_OPT="$IMAGE_ARG"
fi
fi
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
$EXEC_LISP "$@"
}
no_implementation_found () {
ABORT "$PROG: Cannot find a supported lisp implementation.
Tried the following: $*"
}
ensure_implementation () {
trylisp "$1" || no_implementation_found "$1"
}
try_all_lisps () {
for l in $LISP $LISPS ; do
if trylisp $l ; then
$DO_LISP "$@"
return 0
fi
done
no_implementation_found "$LISP $LISPS"
}
exec_lisp () {
# SBCL wants only one form per --eval so we need put everything in one progn.
# However we also want any in-package form to be evaluated before any of the
# remaining forms is read, so we get it to be evaluated at read-time as the
# first thing in the main progn.
# GNU clisp allows multiple forms per -x but prints the result of every form
# evaluated and so we also need put everything in a single progn, and that progn
# must quit before it may return to the clisp frame that would print its value.
# CMUCL allows multiple forms per -eval and won't print values, so is ok anyway.
# I don't know about other Lisps, but they will all work this way.
LAUNCH_FORM="${PROGN}${MAYBE_PACKAGE_FORM}${HASH_BANG_FORM}${LAUNCH_FORMS}${NGORP}"
### This is partial support for CLBUILD.
if [ -n "$USE_CLBUILD" ] ; then
if [ -z "$IMAGE_OPT" ] ; then
OPTIONS=
else
ABORT "Cannot use clbuild with a non-executable image different from clbuild's"
fi
fi
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
if [ -n "$CL_LAUNCH_VERBOSE" ] ; then set -x ; fi
exec $LISP_BIN $IMAGE_OPT $IMAGE $OPTIONS $EVAL "$LAUNCH_FORM" $ENDARGS "$@"
}
launch_self () {
LAUNCH_FORMS="$(load_form "$PROG")"
try_all_lisps "$@"
}
invoke_image () {
if [ "x$IMAGE_ARG" = xEXECUTABLE_IMAGE ] ; then
LISP_BIN= IMAGE_OPT=
else
IMAGE_OPT="$IMAGE_ARG"
fi
PACKAGE_FORM=
HASH_BANG_FORM=
LAUNCH_FORMS="(cl-launch::resume)"
"$EXEC_LISP" "$@"
}
export CL_LAUNCH_PID=$$
export CL_LAUNCH_FILE="$PROG"
## execute configuration-provided code
eval "$WRAPPER_CODE"
### END OF CL-LAUNCH SHELL WRAPPER
launch_self "$@"
ABORT
# |#
#+xcvb (module ())
#| ;;; cl-launch 2.16 lisp header
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
|# ;;;; Silence our lisp implementation for quiet batch use...
#| We'd like to evaluate as little as possible of the code without compilation.
This poses a typical bootstrapping problem: the more sophistication we want
to distinguish what to put where in what dynamic environment, the more code
we have to evaluate before we may actually load compiled files. And, then,
it is a waste of time to try to compile said code into a file. Moving things
to the shell can only help so much, and reduces flexibility. Our best bet is
to tell sbcl or cmucl to not try to optimize too hard.
|#
#-cl-launch (eval-when (:load-toplevel :execute :compile-toplevel)
(declaim (optimize (speed 1) (safety 2) (compilation-speed 3) #-gcl (debug 1)
#+sbcl (sb-ext:inhibit-warnings 3)
#+sbcl (sb-c::merge-tail-calls 3) ;-- this plus debug 1 (or sb-c::insert-debug-catch 0 ???) should ensure all tail calls are optimized, says jsnell
#+cmu (ext:inhibit-warnings 3)))
#+gcl ;;; If using GCL, do some safety checks
(when (or #-ansi-cl t)
(format *error-output*
"CL-Launch only supports GCL in ANSI mode. Aborting.~%")
(lisp:quit))
#+gcl
(when (or (< system::*gcl-major-version* 2)
(and (= system::*gcl-major-version* 2)
(< system::*gcl-minor-version* 7)))
(pushnew :gcl-pre2.7 *features*))
(setf *print-readably* nil ; allegro 5.0 notably will bork without this
*load-verbose* nil *compile-verbose* nil *compile-print* nil)
#+cmu (setf ext:*gc-verbose* nil)
#+clisp (setf custom:*source-file-types* nil custom:*compiled-file-types* nil)
#+gcl (setf compiler::*compiler-default-type* (pathname "")
compiler::*lsp-ext* "")
#+ecl (require 'cmp)
;;;; Ensure package hygiene
(unless (find-package :cl-launch)
(if (find-package :common-lisp)
(defpackage :cl-launch (:use :common-lisp))
(make-package :cl-launch :use '(:lisp))))
(in-package :cl-launch))
#-cl-launch (defmacro dbg (tag &rest exprs)
"simple debug statement macro:
outputs a tag plus a list of source expressions and their resulting values, returns the last values"
(let ((res (gensym))(f (gensym)))
`(let ((,res))
(flet ((,f (fmt &rest args) (apply #'format *trace-output* fmt args)))
(,f "~&~A~%" ,tag)
,@(mapcan
#'(lambda (x)
`((,f "~& ~S => " ',x)
(,f "~{~S~^ ~}~%" (setf ,res (multiple-value-list ,x)))))
exprs)
(apply 'values ,res)))))
#-cl-launch (eval-when (:load-toplevel :execute :compile-toplevel)
;; Import a few symbols if needed
#+common-lisp-controller
(map () #'import
'(clc::*source-root*
clc::*fasl-root*
clc::calculate-fasl-root
clc::source-root-path-to-fasl-path
clc::alternative-root-path-to-fasl-path
clc::*redirect-fasl-files-to-cache*))
;;; define getenv and quit in ways that minimize package conflicts
;;; (use-package :cl-launch) while in cl-user.
#+(or clozure allegro gcl clisp ecl)
(import '#+clozure ccl::getenv
#+allegro sys:getenv
#+gcl system:getenv
#+clisp ext:getenv
#+ecl si:getenv
:cl-launch)
#+(or cmu sbcl lispworks)
(defun getenv (x)
#+sbcl (sb-ext:posix-getenv x)
#+lispworks (lispworks:environment-variable x)
#+cmu (cdr (assoc (intern x :keyword) ext:*environment-list*)))
(defun quit (&optional (code 0) (finish-output t))
(when finish-output ;; essential, for ClozureCL, and for standard compliance.
(finish-outputs))
#+cmu (unix:unix-exit code)
#+clisp (ext:quit code)
#+sbcl (sb-unix:unix-exit code)
#+gcl (lisp:quit code)
#+allegro (excl:exit code :quiet t)
#+ecl (si:quit code)
#+lispworks (lispworks:quit :status code :confirm nil :return nil :ignore-errors-p t)
#-(or cmu clisp sbcl clozure gcl allegro ecl lispworks)
(error "Quitting not implemented")))
#-cl-launch (eval-when (:load-toplevel :execute :compile-toplevel)
;;;; Load ASDF
(ignore-errors (require :asdf))
;;; Here is a fallback plan in case the lisp implementation isn't asdf-aware.
(unless (and (find-package :asdf) (find-symbol "OUTPUT-FILES" :asdf))
(defvar *asdf-path*
(or (and (getenv "ASDF_PATH") (probe-file (getenv "ASDF_PATH")))
(probe-file (merge-pathnames "src/asdf/asdf.lisp"
(user-homedir-pathname)))
(probe-file "/usr/share/common-lisp/source/cl-asdf/asdf.lisp")
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
(probe-file "/usr/share/common-lisp/source/asdf/asdf.lisp")))
(when *asdf-path*
(ignore-errors (load *asdf-path* :verbose nil :print nil)))))
#-cl-launch (eval-when (:load-toplevel :execute :compile-toplevel)
;;; Even in absence of asdf, at least create a package asdf.
(unless (find-package :asdf)
(make-package :asdf)))
#-cl-launch (eval-when (:load-toplevel :execute :compile-toplevel)
;;; Try to share this with asdf, in case we get asdf to support it one day.
(map () #'import
'(asdf::*output-pathname-translations*
asdf::resolve-symlinks
asdf::oos asdf::load-op asdf::find-system)))
;;;; CL-Launch Initialization code
#-cl-launch (progn
(pushnew :cl-launch *features*)
;;#+ecl (require 'cmp) ; ensure we use the compiler (we use e.g. *ecl-library-directory*)
(dolist (s '(*arguments* getenv quit compile-and-load-file
compile-file-pathname* apply-pathname-translations
*output-pathname-translations*
apply-output-pathname-translations))
(export s))
;; To dynamically recompute from the environment at each invocation
(defvar *cl-launch-file* nil)
(defvar *verbose* nil)
(defvar *lisp-fasl-cache* nil "lisp fasl cache hierarchy")
(defvar *lisp-fasl-root* nil "top path for the fasl cache for current implementation")
;; To dynamically recompute from the command-line at each invocation
(defvar *arguments* nil "command-line parameters")
;; Variables that define the current system
(defvar *dumped* nil)
(defvar *restart* nil)
(defvar *init-forms* nil)
(defvar *quit* t)
;; Provide compatibility with clc 6.2
(defvar *redirect-fasl-files-to-cache* t)
(defun raw-command-line-arguments ()
nil
#+ecl (loop for i from 0 below (si:argc) collect (si:argv i))
#+gcl si:*command-args*
#+cmu extensions:*command-line-strings*
#+clozure ccl:*unprocessed-command-line-arguments*
#+sbcl sb-ext:*posix-argv*
#+allegro sys:command-line-arguments
#+lispworks sys:*line-arguments-list*
#+clisp (cons "--" ext:*args*))
(let* ((raw (raw-command-line-arguments))
(cooked #+sbcl raw #-sbcl
(if (eq *dumped* :standalone)
raw
(member "--" raw :test 'string-equal))))
(cdr cooked)))
#+gcl-pre2.7 (defun ensure-directories-exist (x) "hope for the best" nil)
(defvar *implementation-name* nil
"The name of the implementation, used to make a directory hierarchy for fasl files")
(defvar *temporary-directory* "/tmp/"
"The name of the implementation, used to make a directory hierarchy for fasl files")
(defun compute-arguments ()
(setf *cl-launch-file* (getenv "CL_LAUNCH_FILE")
*temporary-directory* (ensure-directory-name (or (getenv "TMP") "/tmp"))
#+gcl #+gcl system::*tmp-dir* *temporary-directory* ; basic lack fixed after gcl 2.7.0-61, but ending / required still on 2.7.0-64.1
*verbose* (when (getenv "CL_LAUNCH_VERBOSE") t)
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
*implementation-name* (unique-directory-name #-ecl *verbose*)
*lisp-fasl-cache*
(let* ((cache-env (getenv "LISP_FASL_CACHE"))
(cache-spec
(cond
((null cache-env)
(merge-pathnames
#p".cache/lisp-fasl/"
;;(make-pathname :directory (list :relative ".cache" "lisp-fasl"))
(user-homedir-pathname)))
((equal cache-env "NIL") nil)
(t (dirname->pathname cache-env)))))
(when cache-spec
(ensure-directories-exist cache-spec)
(resolve-symlinks cache-spec)))
*lisp-fasl-root*
(let* ((root-env
(when (getenv "LISP")
(let ((r (getenv "LISP_FASL_ROOT")))
(when r (if (equal r "NIL") :disabled
(dirname->pathname r))))))
(root-spec
(or root-env
(when *lisp-fasl-cache*
(merge-pathnames
(make-pathname
:directory (list :relative *implementation-name*))
*lisp-fasl-cache*)))))
(when root-spec
(ensure-directories-exist root-spec)
(resolve-symlinks root-spec))))
(calculate-output-pathname-translations)
(setf *arguments*
(or *arguments* (command-line-arguments))))
(defun register-paths (paths)
#-asdf (declare (ignore paths))
#+asdf
(dolist (p (reverse paths))
(pushnew p asdf::*central-registry* :test 'equal)))
(defun load-stream (&optional (s #-clisp *standard-input*
#+clisp *terminal-io*))
;; GCL 2.6 can't load from a string-input-stream
;; ClozureCL 1.2 cannot load from either *standard-input* or *terminal-io*
;; Allegro 5, I don't remember but it must have been broken when I tested.
(do ((eof '#:eof) (x t (read s nil eof))) ((eq x eof)) (eval x))
(load s :verbose nil :print nil))
(defun load-string (string)
(with-input-from-string (s string) (load-stream s)))
(defun finish-outputs ()
(finish-output *error-output*)
(finish-output))
(defun %abort (code fmt &rest args)
(apply #'format *error-output* fmt args)
(quit code))
(defun resume ()
(compute-arguments)
(do-resume))
(defun do-resume ()
(when *restart* (funcall *restart*))
(when *init-forms* (load-string *init-forms*))
(finish-outputs)
(when *quit* (quit 0)))
(defun dump-image (filename &key standalone (package :cl-user))
(setf *dumped* (if standalone :standalone :wrapped)
*arguments* nil
*package* (find-package package)
*features* (remove :cl-launched *features*))
:start-package *package*
:keep-global-handlers nil
:executable (if standalone 0 t) ;--- requires clisp 2.48 or later.
(when standalone
(list
:norc t
:script nil
:init-function #'resume
;; :parse-options nil ;--- requires a non-standard patch to clisp.
)))
#+sbcl
(progn
;;(sb-pcl::precompile-random-code-segments) ;--- it is ugly slow at compile-time (!) when the initial core is a big CLOS program. If you want it, do it yourself
(setf sb-ext::*gc-run-time* 0)
(apply 'sb-ext:save-lisp-and-die filename
:executable t ;--- always include the runtime that goes with the core
(when standalone (list :toplevel #'resume :save-runtime-options t)))) ;--- only save runtime-options for standalone executables
#+cmu
(progn
(ext:gc :full t)
(setf ext:*batch-mode* nil)
(setf ext::*gc-run-time* 0)
(extensions:save-lisp filename))
#+clozure
(ccl:save-application filename :prepend-kernel t)
#+allegro
(progn
(sys:resize-areas :global-gc t :pack-heap t :sift-old-areas t :tenure t) ; :new 5000000
(excl:dumplisp :name filename :suppress-allegro-cl-banner t))
#+lispworks
(if standalone
(lispworks:deliver 'resume filename 0 :interface nil)
(hcl:save-image filename :environment nil))
#+gcl
(progn
(si::set-hole-size 500) (si::gbc nil) (si::sgc-on t)
(si::save-system filename))
#-(or clisp sbcl cmu clozure allegro gcl lispworks)
(%abort 11 "CL-Launch doesn't supports image dumping with this Lisp implementation.~%"))
(defun run (&key paths load system dump restart init (quit 0))
(pushnew :cl-launched *features*)
(compute-arguments)
(when paths (register-paths paths))
(if dump
(build-and-dump dump load system restart init quit)
(build-and-run load system restart init quit)))
(defun read-function (string)
(eval `(function ,(read-from-string string))))
(defun build-and-load (load system restart init quit)
(do-build-and-load load system restart init quit))
#+(and gcl (not gcl-pre2.7))
(defun build-and-load (load system restart init quit)
(unwind-protect
(do-build-and-load load system restart init quit)
(cleanup-temporary-files)))
(defun do-build-and-load (load system restart init quit)
(when load
(cond
((eq load t) (load-stream))
((streamp load) (load-stream load))
((eq load :self) (load-file *cl-launch-file*))
(t (load-file load))))
(when system
#+asdf
(load-system system :verbose *verbose*)
#-asdf
(%abort 10 "ERROR: asdf requested, but not found~%"))
(setf *restart* (when restart (read-function restart))
*init-forms* init
*quit* quit))
(defun build-and-run (load system restart init quit)
(build-and-load load system restart init quit)
(do-resume))
#-ecl
(defun build-and-dump (dump load system restart init quit)
(build-and-load load system restart init quit)
(dump-image dump :standalone (getenv "CL_LAUNCH_STANDALONE"))
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
#+(or ecl (and gcl (not gcl-pre2.7)))
(progn
(defvar *temporary-filenames* nil)
(defun copy-stream (i o &key (element-type 'character))
(loop with size = 8192
with buf = (make-array size :element-type element-type)
for n = (read-sequence buf i)
while (plusp n)
do (write-sequence buf o :end n)))
(defun call-with-new-file (n f)
(with-open-file (o n :direction :output :if-exists :error :if-does-not-exist :create)
(funcall f o)))
(defun dump-stream-to-file (i n)
(call-with-new-file n (lambda (o) (copy-stream i o))))
(defun copy-file (src dst)
(with-open-file (i src :direction :input :if-does-not-exist :error :element-type '(unsigned-byte 8))
(with-open-file (o dst :direction :output :if-exists :supersede :element-type '(unsigned-byte 8))
(copy-stream i o :element-type '(unsigned-byte 8)))))
(defun dump-sexp-to-file (x n)
(call-with-new-file
n
(lambda (o) (write x :stream o :pretty t :readably t))))
(defvar *temporary-file-prefix*
(format nil "~Acl-launch-~A-" *temporary-directory* (getenv "CL_LAUNCH_PID")))
(defun make-temporary-filename (x)
(concatenate 'string *temporary-file-prefix* x))
(defun register-temporary-filename (n)
(push n *temporary-filenames*)
n)
(defun temporary-filename (x)
(register-temporary-filename (make-temporary-filename x)))
(defun temporary-file-from-foo (dumper arg x)
(let ((n (temporary-filename x)))
(funcall dumper arg n)
n))
(defun temporary-file-from-stream (i x)
(temporary-file-from-foo #'dump-stream-to-file i x))
(defun temporary-file-from-sexp (i x)
(temporary-file-from-foo #'dump-sexp-to-file i x))
(defun temporary-file-from-file (f x)
(with-open-file (i f :direction :input :if-does-not-exist :error)
(temporary-file-from-stream i x)))
(defun ensure-lisp-file (x &optional (name "load.lisp"))
(cond
((eq x t) (temporary-file-from-stream *standard-input* "load.lisp"))
((streamp x) (temporary-file-from-stream x "load.lisp"))
((eq x :self) (ensure-lisp-file-name *cl-launch-file* name))
(t (ensure-lisp-file-name x name))))
(defun ensure-lisp-file-name (x &optional (name "load.lisp"))
(let ((p (pathname x)))
(if (equal (pathname-type p) "lisp")
p
(temporary-file-from-file p name))))
(defun cleanup-temporary-files ()
(loop for n = (pop *temporary-filenames*)
while n do
(ignore-errors (delete-file n)))))
;;; choose which strategy you try to debug...
#+ecl (defun build-and-dump (&rest r) (apply #'yyy-build-and-dump r))
;;; Attempt at adapting the code from cl-launch 2.07
;;; seems to break earlier than the yyy- method below.
(defun xxx-build-and-dump (dump load system restart init quit)
(setf *compile-verbose* *verbose*
c::*suppress-compiler-warnings* (not *verbose*)
c::*suppress-compiler-notes* (not *verbose*))
(let* ((cl-launch-objects
(let* ((*features* (remove :cl-launch *features*))
(header (or *compile-file-pathname* *load-pathname* (getenv "CL_LAUNCH_HEADER")))
(header-file (ensure-lisp-file header "header.lisp"))
(object (compile-file-pathname* header-file :system-p t)))
(compile-file header-file :output-file object :system-p t)
(list object)))
(list
(compile-and-load-file (ensure-lisp-file load "load.lisp")
:verbose *verbose* :system-p t :load t))))
(system-objects
(when system
(let* ((target (find-system system))
(build (make-instance 'asdf::program-op)))
(asdf:perform build target)
(asdf:input-files build target))))
(standalone (getenv "CL_LAUNCH_STANDALONE"))
*load-verbose* nil
*dumped* ,(if standalone :standalone :wrapped)
*arguments* nil
,@(when restart `(*restart* (read-function ,restart)))
,@(when init `(*init-forms* ,init))
,@(unless quit `(*quit* nil))))
`(progn
,init-code
,(if standalone '(resume) '(si::top-level))))
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
(c::builder :program (parse-namestring dump)
:lisp-files
(append cl-launch-objects file-objects system-objects)
:epilogue-code epilogue-code)))
(cleanup-temporary-files)
(quit)))
;;; Attempt at compiling directly with asdf-ecl's make-build and temporary wrapper asd's
;;; Fails with weird linking errors.
#+ecl (defvar *in-compile* nil)
#+ecl
(defun yyy-build-and-dump (dump load system restart init quit)
(unwind-protect
(let* ((*compile-verbose* *verbose*)
(*in-compile* t)
(c::*suppress-compiler-warnings* (not *verbose*))
(c::*suppress-compiler-notes* (not *verbose*))
(*features* (remove :cl-launch *features*))
(header (or *compile-file-pathname* *load-pathname* (getenv "CL_LAUNCH_HEADER")))
(header-file (ensure-lisp-file header "header.lisp"))
(load-file (when load (ensure-lisp-file load "load.lisp")))
(standalone (getenv "CL_LAUNCH_STANDALONE"))
(init-code
`(unless *in-compile*
(setf
*load-verbose* nil
*dumped* ,(if standalone :standalone :wrapped)
*arguments* nil
,@(when restart `(*restart* (read-function ,restart)))
,@(when init `(*init-forms* ,init))
,@(unless quit `(*quit* nil)))
,(if standalone '(resume) '(si::top-level))))
(init-file (temporary-file-from-sexp init-code "init.lisp"))
(prefix-sys (temporary-filename "prefix"))
(program-sys (temporary-filename "program"))
(prefix-sysdef
`(asdf:defsystem ,prefix-sys
:depends-on () :serial t
:components ((:file "header" :pathname ,header-file)
,@(when load-file `((:file "load" :pathname ,load-file))))))
(program-sysdef
`(asdf:defsystem ,program-sys
:depends-on (,prefix-sys
,@(when system `(,system)))
:components ((:file "init" :pathname ,init-file))))
(prefix-asd (temporary-file-from-sexp prefix-sysdef "prefix.asd"))
(program-asd (temporary-file-from-sexp program-sysdef "program.asd")))
(load prefix-asd)
(load program-asd)
(asdf::make-build program-sys :type :program)
(si:system (format nil "cp -p ~S ~S"
(namestring (first (asdf:output-files (make-instance 'asdf::program-op)
(find-system program-sys))))
dump)))
(cleanup-temporary-files))
(quit))
;;;; Find a unique directory name for current implementation for the fasl cache
;;; (modified from SLIME's swank-loader.lisp)
(defparameter *implementation-features*
'(:allegro :lispworks :sbcl :clozure :cmu :clisp :ccl :corman :cormanlisp
:armedbear :gcl :ecl :scl))
(defparameter *os-features*
'(:macosx :linux :windows :mswindows :win32
:solaris :darwin :sunos :hpux :unix))
(defparameter *architecture-features*
'(:powerpc :ppc
:x86-64 :amd64 :x86 :i686 :i586 :i486 :pc386 :iapx386 :pentium3
:sparc64 :sparc
:hppa64 :hppa))
#+(or cmu scl sbcl ecl lispworks armedbear cormanlisp)
(lisp-implementation-version)
#+clozure (format nil "~d.~d.fasl~d"
ccl::*openmcl-major-version*
ccl::*openmcl-minor-version*
(logand ccl::fasl-version #xFF))
#+allegro (format nil
"~A~A~A"
excl::*common-lisp-version-number*
(if (eq 'h 'H) "A" "M") ; ANSI vs MoDeRn
(if (member :64bit *features*) "-64bit" ""))
#+clisp (let ((s (lisp-implementation-version)))
(subseq s 0 (position #\space s)))
#+gcl (let ((s (lisp-implementation-version))) (subseq s 4)))
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
(defun ensure-directory-name (dn)
(if (eql #\/ (char dn (1- (length dn)))) dn
(concatenate 'string dn "/")))
(defun dirname->pathname (dn)
(parse-namestring (ensure-directory-name dn)))
(defun unique-directory-name (&optional warn)
"Return a name that can be used as a directory name that is
unique to a Lisp implementation, Lisp implementation version,
operating system, and hardware architecture."
(flet ((first-of (features)
(find-if #'(lambda (f) (find f *features*)) features))
(maybe-warn (value fstring &rest args)
(cond (value)
(t (when warn (apply #'warn fstring args))
"unknown"))))
(let ((lisp (maybe-warn (first-of *implementation-features*)
"No implementation feature found in ~a."
*implementation-features*))
(os (maybe-warn (first-of *os-features*)
"No os feature found in ~a." *os-features*))
(arch (maybe-warn (first-of *architecture-features*)
"No architecture feature found in ~a."
*architecture-features*))
(version (maybe-warn (lisp-version-string)
"Don't know how to get Lisp ~
implementation version.")))
(substitute-if #\_ (lambda (x) (find x " /:\\(){}[]$#`'\""))
(format nil "~(~@{~a~^-~}~)" lisp version os arch)))))
;;;; Redefine the ASDF output-files method to put fasl's under the fasl cache.
;;; (taken from common-lisp-controller's post-sysdef-install.lisp)
;;#-common-lisp-controller (progn ; BEGIN of progn to disable caching when clc is detected
(defparameter *wild-path*
(make-pathname :directory '(:relative :wild-inferiors)
:name :wild :type :wild :version nil))
(defun wilden (path)
(merge-pathnames *wild-path* path))
#-asdf
(defun resolve-symlinks (x)
#+allegro (excl:pathname-resolve-symbolic-links x)
#-(or allegro gcl-pre2.7)
(truename x))
(defvar *output-pathname-translations* nil
"a list of pathname translations, where every translation is a list
of a source pathname and destination pathname.")
(defun exclude-from-cache (&rest dirs)
(dolist (dir dirs)
(when dir
(let* ((p (if (pathnamep dir) dir (dirname->pathname dir)))
(n #+asdf (resolve-symlinks p) #-asdf p)
(w (wilden n)))
(pushnew (list w w)
cl-launch::*output-pathname-translations*
:test #'equal)))))
(defun calculate-output-pathname-translations ()
(setf *output-pathname-translations*
`(#+(and common-lisp-controller (not gcl))
,@(progn
(ensure-directories-exist (calculate-fasl-root))
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
(let* ((sr (resolve-symlinks *source-root*))
(fr (resolve-symlinks *fasl-root*))
(sp (wilden sr))
(fp (wilden fr)))
`((,sp ,fp)
(,fp ,fp)
,@(when *redirect-fasl-files-to-cache*
`((,(wilden "/")
,(wilden (merge-pathnames
(make-pathname :directory '(:relative "local")) fr))))))))
#-(and common-lisp-controller (not gcl))
,@(when (and *lisp-fasl-root* (not (eq *lisp-fasl-root* :disabled)))
`((,(wilden "/") ,(wilden *lisp-fasl-root*))))))
;; Do not recompile in private cache system-installed sources
;; that already have their accompanying precompiled fasls.
#+(or clisp sbcl cmucl gcl) ; no need for ECL: no source/fasl couples there.
(exclude-from-cache
#p"/usr/lib/"
#+clisp ext:*lib-directory*
#+gcl system::*lib-directory*
#+ecl c::*ecl-library-directory*
#+sbcl (getenv "SBCL_HOME")
#+cmu (truename #p"library:")))
(defun apply-pathname-translations
(path &optional (translations *output-pathname-translations*))
#+gcl-pre2.7 path ;;; gcl 2.6 lacks pathname-match-p, anyway
#-gcl-pre2.7
(loop
for (source destination) in translations
when (pathname-match-p path source)
do (return (translate-pathname path source destination))
finally (return path)))