Newer
Older
;;; -*- Mode: Lisp; Package: Lisp; Log: code.log -*-
;;;
;;; **********************************************************************
;;; This code was written as part of the CMU Common Lisp project at
;;; Carnegie Mellon University, and has been placed in the public domain.
;;; If you want to use this code or any part of CMU Common Lisp, please contact
;;; Scott Fahlman or slisp-group@cs.cmu.edu.
;;;
(ext:file-comment
"$Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/code/save.lisp,v 1.20 1994/02/11 13:36:59 ram Exp $")
;;; **********************************************************************
;;;
;;; Dump the current lisp image into a core file. All the real work is done
;;; be C. Also contains various high-level initialization stuff: loading init
;;; files and parsing environment variables.
(export '(print-herald *herald-items* save-lisp *before-save-initializations*
*after-save-initializations* *environment-list* *editor-lisp-p*))
(defvar *before-save-initializations* nil
"This is a list of functions which are called before creating a saved core
image. These functions are executed in the child process which has no ports,
so they cannot do anything that tries to talk to the outside world.")
(defvar *after-save-initializations* nil
"This is a list of functions which are called when a saved core image starts
up. The system itself should be initialized at this point, but applications
might not be.")
(defvar *environment-list* nil
"An alist mapping environment variables (as keywords) to either values")
(defvar *editor-lisp-p* nil
"This is true if and only if the lisp was started with the -edit switch.")
;;; PARSE-UNIX-SEARCH-LIST -- Internal
;;;
;;; Returns a list of the directories that are in the specified Unix
;;; environment variable. Return NIL if the variable is undefined.
;;;
(defun parse-unix-search-list (var)
(let ((path (cdr (assoc var ext::*environment-list*))))
(when path
(do* ((i 0 (1+ p))
(p (position #\: path :start i)
(position #\: path :start i))
(pl ()))
((null p)
(let ((s (subseq path i)))
(if (string= s "")
(push "default:" pl)
(push (concatenate 'simple-string s "/") pl)))
(nreverse pl))
(let ((s (subseq path i p)))
(if (string= s "")
(push "default:" pl)
(push (concatenate 'simple-string s "/") pl)))))))
;;; ENVIRONMENT-INIT -- Internal
;;;
;;; Parse the LISP-ENVIRONMENT-LIST into a keyword alist. Set up default
;;; search lists.
;;;
(defun environment-init ()
(setq *environment-list* ())
(dolist (ele lisp-environment-list)
(let ((=pos (position #\= (the simple-string ele))))
(when =pos
(push (cons (intern (string-upcase (subseq ele 0 =pos))
*keyword-package*)
(subseq ele (1+ =pos)))
*environment-list*))))
(setf (search-list "default:") (list (default-directory)))
(setf (search-list "path:") (parse-unix-search-list :path))
(setf (search-list "home:")
(or (parse-unix-search-list :home)
(list (default-directory))))
(setf (search-list "library:")
(or (parse-unix-search-list :cmucllib)
'(#-hpux "/usr/misc/.cmucl/lib/"
#+hpux "/usr/local/cmucl/lib/"))))
;;;; SAVE-LISP itself.
(alien:def-alien-routine "save" (alien:boolean)
(file c-call:c-string)
(initial-function (alien:unsigned #.vm:word-bits)))
(defun save-lisp (core-file-name &key
(purify t)
(root-structures ())
(constants nil)
(init-function #'%top-level)
(site-init "library:site-init")
(print-herald t)
(process-command-line t))
"Saves a CMU Common Lisp core image in the file of the specified name. The
following keywords are defined:
:purify
If true (the default), do a purifying GC which moves all dynamically
allocated objects into static space so that they stay pure. This takes
somewhat longer than the normal GC which is otherwise done, but GC's will
done less often and take less time in the resulting core file.
:constants
These should be a list of the main entry points in any newly loaded
systems and a list of any large data structures that will never again
be changed. These need not be supplied, but locality and/or GC performance
will be better if they are. They are meaningless if :purify is NIL.
This is the function that starts running when the created core file is
resumed. The default function simply invokes the top level
read-eval-print loop. If the function returns the lisp will exit.
:load-init-file
If true, then look for an init.lisp or init.fasl file when the core
file is resumed.
:site-init
If true, then the name of the site init file to load. The default is
library:site-init. No error if this does not exist.
If true (the default), print out the lisp system herald when starting."
(when (fboundp 'eval:flush-interpreted-function-cache)
(eval:flush-interpreted-function-cache))
(purify :root-structures root-structures :constants constants)
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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
(flet
((restart-lisp ()
(catch '%end-of-the-world
(with-simple-restart (abort "Skip remaining initializations.")
(catch 'top-level-catcher
(reinit)
(dolist (f *before-save-initializations*) (funcall f))
(dolist (f *after-save-initializations*) (funcall f))
(environment-init)
(when site-init
(load site-init :if-does-not-exist nil :verbose nil))
(when process-command-line
(ext::process-command-strings))
(setf *editor-lisp-p* nil)
(macrolet ((find-switch (name)
`(find ,name *command-line-switches*
:key #'cmd-switch-name
:test #'(lambda (x y)
(declare (simple-string x y))
(string-equal x y)))))
(when (and process-command-line (find-switch "edit"))
(setf *editor-lisp-p* t))
(when (and load-init-file
(not (and process-command-line
(find-switch "noinit"))))
(let* ((cl-switch (find-switch "init"))
(name (and cl-switch
(or (cmd-switch-value cl-switch)
(car (cmd-switch-words
cl-switch))))))
(if name
(load (merge-pathnames name #p"home:")
:if-does-not-exist nil)
(or (load "home:init" :if-does-not-exist nil)
(load "home:.cmucl-init"
:if-does-not-exist nil))))))
(when process-command-line
(ext::invoke-switch-demons *command-line-switches*
*command-switch-demons*))
(when print-herald
(print-herald))))
(funcall init-function))
(unix:unix-exit 0)))
(let ((initial-function (get-lisp-obj-address #'restart-lisp)))
(without-gcing
(save (unix-namestring core-file-name nil) initial-function))))
nil)
;;;; PRINT-HERALD support.
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
(defvar *herald-items* ()
"Determines what PRINT-HERALD prints (the system startup banner.) This is a
database which can be augmented by each loaded system. The format is a
property list which maps from subsystem names to the banner information for
that system. This list can be manipulated with GETF -- entries are printed
in, reverse order, so the newest entry is printed last. Usually the system
feature keyword is used as the system name. A given banner is a list of
strings and functions (or function names). Strings are printed, and
functions are called with an output stream argument.")
(setf (getf *herald-items* :common-lisp)
`("CMU Common Lisp "
,#'(lambda (stream)
(write-string (lisp-implementation-version) stream))
", running on "
,#'(lambda (stream) (write-string (machine-instance) stream))))
(setf (getf *herald-items* :bugs)
'("Send bug reports and questions to cmucl-bugs@cs.cmu.edu."
terpri
"Loaded subsystems:"))
;;; PRINT-HERALD -- Public
;;;
(defun print-herald (&optional (stream *standard-output*))
"Print some descriptive information about the Lisp system version and
configuration."
(let ((res ()))
(do ((item *herald-items* (cddr item)))
((null item))
(push (second item) res))
(fresh-line stream)
(dolist (item res)
(dolist (thing item)
(typecase thing
(string
(write-string thing stream))
(function (funcall thing stream))
((or symbol cons)
(funcall (fdefinition thing) stream))
(t
(error "Unrecognized *HERALD-ITEMS* entry: ~S." thing))))
(fresh-line stream)))
;;;; Random functions used by worldload.
(defun assert-user-package ()
(unless (eq *package* (find-package "USER"))
(error "Change *PACKAGE* to the USER package and try again.")))
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
;;; MAYBE-BYTE-LOAD -- Interface
;;;
;;; If Name has been byte-compiled, and :runtime is a feature, then load the
;;; byte-compiled version, otherwise just do normal load.
;;;
(defun maybe-byte-load (name &optional (load-native t))
(let ((bname (make-pathname
:defaults name
:type #.(c:backend-byte-fasl-file-type c:*target-backend*))))
(cond ((and (featurep :runtime)
(probe-file bname))
(load bname))
(load-native
(load name)))))
;;; BYTE-LOAD-OVER -- Interface
;;;
;;; Replace a cold-loaded native object file with a byte-compiled one, if it
;;; exists.
;;;
(defun byte-load-over (name)
(load (make-pathname
:defaults name
:type #.(c:backend-byte-fasl-file-type c:*target-backend*))
:if-does-not-exist nil))