dumplisp

$Revision: 5.0.2.4 $

The document introduction.htm provides an overview of the Allegro CL documentation with links to all major documents. The document index.htm is an index with pointers to every documented object (operators, variables, etc.) The revision number of this document is below the title. These documents may be revised from time to time between releases.

1.0 Introduction to excl:dumplisp
2.0 Changes from earlier releases
3.0 Finding additional files
4.0 Uses of excl:dumplisp
5.0 excl:dumplisp will fail under some conditions
6.0 <allegro directory>/code/aclstart.cl is the source code for startup
7.0 Creating an application
8.0 Creating a customized image
9.0 When the dumped image starts 1: values of global variables
10.0 When the dumped image starts 2: command-line arguments
11.0 When the dumped image starts 3: reading init files
12.0 When the dumped image starts 4: restart actions
13.0 When the dumped image starts 5: the two restart functions
14.0 The emacs-lisp interface and dumped images
15.0 Dumping a prestoized image
16.0 Standalone image: not supported
17.0 How the dumped image finds loaded library files
18.0 Logical pathnames and the dumped image
19.0 How the dumped image finds its Allegro directory
20.0 How to use the dumped image

1.0 Introduction to excl:dumplisp

The function excl:dumplisp writes an image file from the current running Lisp image. It has many options and many uses. Unlike the two other function that create new images, excl:build-lisp-image and excl:generate-application, excl:dumplisp preserves much of the environment of the running image. Both excl:build-lisp-image and excl:generate-application create new images from external constituent parts that inherit nothing from the running image.

2.0 Changes from earlier releases

In all earlier releases of Allegro CL on UNIX, excl:dumplisp produced an executable image file that contained the Lisp heap. It was typically a large file. It could be a standalone executable, depending on no other file on certain operating systems and only on standard library files -- libc.so, e.g -- on others. (Other files might be needed but the need for them could usually be delayed until the application had properly initialized, allowing effective strategies for finding files to be wholly implemented in application code.) Because the new model requires a small executable and a separate image file, standalone images are no longer possible.

Earlier releases on Windows machines used the small executable/large image model, so the change from 3.0.x to 5.0, in this regard, involves function name changes (excl:dumplisp instead of save-image) along with the much greater changes to the general Lisp.

3.0 Finding additional files

One advantage of the small executable/large image model is that all image files use the same executable, so there needs only be one executable file on a machine (or on  a network). This means that the location of that executable can be used as a starting location which can be a reference point for finding other necessary files.

User of ACL 4.3 and earlier on UNIX machines should contrast this new behavior with the old. With the old large executable image model, the executable image file could be anywhere (for example, a programmer's home directory) and some other means had to be provided to locate other files. The means varied over time. In 4.3, an environment variable ALLEGRO_CL_HOME was used. With the new model, the location of the executable is taken as the reference point for finding files so no specific location must be supplied when Lisp starts up. (You can specify a location with the -H argument if you wish. However, that should not be necessary.)

4.0 Uses of excl:dumplisp

You might use excl:dumplisp for the following purposes (as well as others not listed):

5.0 excl:dumplisp will fail under some conditions

In order for excl:dumplisp to work, it must examine the currently running image. For this reason, excl:dumplisp will fail if:

6.0 <allegro directory>/code/aclstart.cl is the source code for startup

Allegro CL does a number of things when it starts up before it prints the first prompt and is ready to accept input. Programmers may want to know what it does and in what order, so that programmer modifications and customizations can be done at the right time. Allegro CL calls the function excl::start-lisp-execution on startup. The source for that function and for several associated functions (that process command-line arguments and read initialization files, e.g.) can be found in the file sys:;code;aclstart.cl, equivalently <allegro directory>/code/aclstart.cl. See also startup.htm where startup is described in English rather than Lisp code.

7.0 Creating an application

Please see delivery.htm for a detailed discussion of creating images for delivery.

8.0 Creating a customized image

A typical customization is loading a complicated program and thus saving the time to load whenever you start Lisp (but quicker startup should be balanced against additional disk space usage).

9.0 When the dumped image starts 1: values of global variables

When a Lisp Listener (which presents the prompt to users and accepts and processes typed input) starts up, bindings are set up for many Common Lisp and Allegro CL-specific global variables. The bindings come from alists, one of which is the value of excl:*cl-default-special-bindings*. Here is part of excl:*cl-default-special-bindings*:

;; From excl:*default-cl-special-bindings* (a few values only)
;; (*PRINT-LENGTH*) is equivalent to (*PRINT-LENGTH* . NIL).
(*PRINT-LENGTH*) (*PRINT-LEVEL*) (*PRINT-RADIX*) (*PRINT-BASE* . 10)
(*PRINT-PRETTY* . T) (*PRINT-ESCAPE* . T)

Note that each variable in the portion of the alist shown is associated with a specific value (nil for *print-length*, *print-level* and *print-radix*, 10 for *print-base*, and t for *print-pretty* and *print-escape*). When a Lisp listener is started in the dumped image, *print-length* in that listener will be nil regardless of its value when excl:dumplisp was called, as this example shows:

;; We bring up Allegro CL and note that *print-length* has initial value NIL.
USER(1): *print-length*
NIL
;; We set the value of *print-length* to 20:
USER(2): (setq *print-length* 20)
20
USER(3): *print-length*
20
;; and we dump the image:
USER(4): (excl:dumplisp :name "my-image")
USER(5): (exit)
;; Now we start my-image:
==============================================================
Starting image `my-image'
[...]
;; Note that *print-length* is NIL, not 20:
USER(1): *print-length*
NIL
USER(2):

The listener in the restarted image gets the value of *print-length* from the excl:*cl-default-special-bindings* alist, where *print-length* is associated explicitly with nil. The value in the parent image is not relevant. In order to ensure that *print-length* (or any variable whose name appears on either alist) have the desired value in the listener when the dumped image is started, you must modify the appropriate alist. The easiest way to do this it with tpl:setq-default. This macro is like setq: its first argument should be a symbol and is not evaluated; its second argument should be a value and is evaluated. It modifies the alist appropriately (see the definition for a complete description) but does not affect the current value. Thus:

;; We bring up Allegro CL and note that *print-length* has initial value NIL.
USER(1): *print-length*
NIL
;; We use TPL:SETQ-DEFAULT to modify the EXCL:*CL-DEFAULT-SPECIAL-BINDINGS*
;; entry referring to *PRINT-LENGTH* so new bindings will be to 20, not NIL:
USER(2): (tpl:setq-default *print-length* 20)
20
USER(3): *print-length* ;; its value in the current listener is unchanged
NIL
;; and we dump the image:
USER(4): (excl:dumplisp :name "my-image")
USER(5): (exit)
;; Now we start my-image:
==============================================================
Starting image `my-image'
[...]
;; Note that *print-length* is 20, not NIL:
USER(1): *print-length*
20
USER(2):

Recall that changes to the reader (such as setting a macro-character) are stored in *readtable* and that variable appears on excl:*cl-default-special-bindings*.

This same issue affects setting values from an initialization file. A discussion very similar to this one appears in startup.htm.

10.0 When the dumped image starts 2: command-line arguments

Command-line arguments are processed as usual or ignored as the ignore-command-line-arguments keyword argument to excl:dumplisp is nil (the default) or t. The emacs-lisp interface uses command-line arguments to start up. See below under the heading 14.0 The emacs-lisp interface and dumped images for information on starting the interface when command-line arguments are ignored.

Command-line arguments are available, of course, with sys:command-line-arguments and related functions. They are just ignored by Allegro CL's startup routine when ignore-command-line-arguments is true.

11.0 When the dumped image starts 3: reading init files

There are various initialization files that might be read: ~/.clinit.cl, <working-directory>/.clinit.cl (if <working-directory> is different than ~), ~/ and <working directory>/clinit.cl, and sys:siteinit.cl. These files will be looked for if excl:*read-init-files* is t when the image is dumped (just <working-directory>/.clinit.cl and clinit.cl and sys:siteinit.cl. if excl:*read-init-files* is :no-home). This variable should be set (not bound) prior to the call to excl:dumplisp. Setting this variable after Lisp has started up only affects its value in dumped images. It is not used by Lisp after startup has completed.

Command-line arguments can suppress the reading of some or all initialization files (see startup.htm). Since command-line arguments processed before initialization files are read, the value of this variable can be changed using them -- e.g. specify `-e (setq excl:*read-init-files* t)' on the command-line -- assuming command-line arguments are not ignored.

12.0 When the dumped image starts 4: restart actions

The variable excl:*restart-actions*, if non-nil, should be a list of functions of no arguments (function names or function objects are acceptable). These functions are called in order, after the command-line arguments are processed and the init files are read. The purpose of this variable is to do system initializations. Do not set this variable or you may eliminate values put on the list by Allegro CL and its associated products (CLIM, for example, uses this variable). Instead, use push or pushnew to add items if desired.

Programmers are in fact discouraged from using this variable. excl:*restart-init-function* and excl:*restart-app-function* (both described under the next heading) are better suited to application code while excl:*restart-actions* is best left to Allegro CL and its associated products. Both excl:*restart-init-function* and excl:*restart-app-function* are processed at the end of the startup procedure. excl:*restart-actions* is processed early in the procedure, too early for certain actions (like starting CLIM) to succeed.

13.0 When the dumped image starts 5: the two restart functions

At the end of the startup procedure, Allegro CL examines the variable excl:*restart-init-function*. If it is non-nil, its value is assumed to be a function of no arguments (either a function name or a function object) and that function is called. The function typically will return. It is designed for late initializations (perhaps based on information supplied by initialization files), possibly cleanup of state from the pre-dumplisp image, application tasks like printing an information message or an application banner, reading an application-specific initialization file, processing application command-line arguments, etc.

When the excl:*restart-init-function* returns, Allegro CL examines excl:*restart-app-function*. If it is nil, a standard Lisp listener is started. If it is non-nil, its value is assumed to be a function of no arguments (either a function name or a function object) and that function is called. The function should not return (the behavior if it does return is undefined.) excl:*restart-app-function* is designed to provide an application top-level when the application does not want to use the standard Lisp listener as a top-level.

There are two restart functions specifically to divide the two purposes of a restart function in earlier versions of Allegro CL: application-specific initializations and providing an application top-level. Note that, a listener is started if excl:*restart-app-function* is nil but not when excl:*restart-app-function* returns (indeed, the behavior if excl:*restart-app-function* returns is undefined). Note that excl:*restart-app-function* can start its own Lisp listener by evaluating the following form:

(tpl:start-interactive-top-level *terminal-io*
   #'tpl:top-level-read-eval-print-loop nil)

See the definitions of tpl:start-interactive-top-level and tpl:top-level-read-eval-print-loop.

14.0 The emacs-lisp interface and dumped images

This issue is also discussed in eli/readme.htm. The Emacs-Lisp interface provides a close coupling of Allegro CL and Emacs. What is important with respect to dumped images is how the interface is started. It can only be started by invoking Allegro CL within Emacs with the function fi:common-lisp. Images invoked in that way cause the Emacs-Lisp interface to be started with the command line arguments "-e (excl:start-emacs-lisp-interface t)" (plus any additional command line arguments you specify). This will be ineffective if processing of those command line arguments is suppressed because the image was dumped with the ignore-command-line-arguments argument to excl:dumplisp specified true.

If you create an image which ignores command-line arguments and you want the emacs-lisp interface started, you must take responsibility for evaluating (excl:start-emacs-lisp-interface t). This could be done as part of the excl:*restart-init-function*.

There is one minor complication: you may want to handle the case where you are starting the image in some fashion other than calling fi:common-lisp within Emacs (for example, starting Lisp in a shell). In that case, calling excl:start-emacs-lisp-interface will not, of course, do anything effective. Calling the function is not an error. However, it does print a cryptic string to the listener, which you may want to avoid. The solution to that problem is, instead of unconditionally calling excl:start-emacs-lisp-interface, to look yourself for "-e (excl:start-emacs-lisp-interface t)" among the command line arguments and only call excl:start-emacs-lisp-interface if it appears. The following code (which actually simply looks for the first -e argument and evaluates its companion argument) will do that:

(let ((e-arg (member "-e" (system:command-line-arguments
                            :application nil)
                    :test #'string=)))
    (when e-arg
      (eval (with-standard-io-syntax
            (read-from-string (cadr e-arg))))))

15.0 Dumping a prestoized image

The Allegro presto utility allows libfasl loading of compiled functions. Libfasl loading is described in detail in loading.htm. In brief, when a fasl file is libfasl loaded, only part of the function information is actually loaded into Lisp. The remainder (called the call-time function info) remains in the fasl file and is only loaded if the function is actually called. Partially loaded functions contain a pointer to the (typically absolute) pathname of the file that contains the call-time function info.

The problem this poses when dumping images should be clear: the dumped image will contain stub functions with pointers to the absolute pathnames of files containing call-time function info. If the dumped image is run on a different machine (or on the same machine but when a different set of filesystems are mounted), Lisp may be unable to resolve call-time function info and thus signal an error.

If you are going to run the image on the same machine (and particularly in the same directory) and the machine will have the same filesystems mounted (or, equivalently for this purpose, if all the files are local to the machine), you probably do not have to worry too much about this issue. But if you want to be able to run the image on arbitrary machines, do the following before calling excl:dumplisp.

  1. Choose a filename where unloaded call-time function info can be stored. You can specify a pathname but it is often easiest to specify a filename with no path. You will pass this filename as a string to the function sys:presto-build-lib. As an example, let us choose "myfile".
  2. Run the following code (replace "myfile" in the second line with the filename you chose and add whatever arguments you want to the call to excl:dumplisp in the second line):

(sys:presto-build-lib "myfile")
(excl:dumplisp)

You will see in the current directory a file named savedcl (that is the dumped Lisp image) and a file named myfile (that contains the unresolved call-time function info). Make sure that myfile is in whatever directory (on whatever machine) you run savedcl. Call-time function info needed by savedcl will be loaded from myfile.

Note that you can specify a different name for the saved image with the name keyword argument to excl:dumplisp.

Unfortunately there is no way to tell Lisp to resolve all stub functions. You can find out exactly what files contain call-time function info by calling the function sys:presto-fasl-set. It is best to do a global gc immediately prior to calling that function (the information about stub functions and files is stored in weak objects -- a global gc guarantees that weak objects with no live elements are flushed). Thus:

(excl:gc t)
(sys:presto-fasl-set)

Note that if sys:presto-fasl-set returns nil, all functions are fully loaded. Assuming excl:*libfasl* is nil (to prevent autoloading in libfasl mode), if sys:presto-fasl-set does return nil, you can call excl:dumplisp without worrying about stub functions or calling sys:presto-build-lib.

16.0 Standalone image: not supported

Because Allegro CL now requires an executable file and an image file, standalone images (images that depend on no other files) are no longer possible.

17.0 How the dumped image finds loaded library files

Foreign loading is done on Unix by `loading' .so or .sl files with dlopen() or an equivalent and on Windows by loading .dll files. Dumped images must find these files when it starts up.

The pathnames of loaded .so files are stored. So long as those pathnames are valid when the image is restarted, things should work correctly. However, to guarantee that the dumped image finds the .so files when it restarts, even if run on a different machine or network, you can use one of the following methods.

  1. Use pathnames that will be valid when the dumped image restarts (and, as we describe, logical pathnames can be made valid in the dumped image); or
  2. Unload the .so files prior to dumplisp and reload them as part of the startup procedure (perhaps as an action taken by excl:*restart-init-function*). We describe both methods in some detail.

Using logical pathnames and making them valid in the dumped image. Lisp stores the pathnames of all loaded .so files as they are specified to load (or :ld). It uses these stored pathnames when a dumped image is restarted to find the files and reload them. We recommend these steps for loading .so files. Because logical pathnames are used and because a translations file is specified (~/myhosts), all that is needed is to ensure that file contains the correct translation for the logical host.

  1. Specify the needed files to be loaded with logical pathnames.
  2. Modify excl:logical-pathname-translations-database-pathnames before dumping the image so that some file under your control (~/myhosts, e.g.) is examined along with sys:hosts.cl.
  3. Make sure that file has the correct translation for the logical pathnames used to identify the .so files.

For example, suppose you want to load /usr/mydir/mysos/foo.so into an image that will be dumped. The following transcript shows the actions in the pre-dumped image and modifications to the external logical hosts file.

USER(1): (setf (logical-pathname-translations "myso")
           '((";**;*.*" #p"/usr/mydir/mysos/")))
((#p";**;*.*" #p"/usr/mydir/mysos/"))
USER(2): :ld myso:b.so
; Foreign loading myso:b.so.
USER(3): (push "~/myhosts" (logical-pathname-translations-database-pathnames))
("~/myhosts" "sys:hosts.cl")
USER(4): (dumplisp :name "mycl")
Warning: shared object files have been loaded into this image, and so the
resulting image will depend on myso:b.so for successful operation.
USER(5):
;; ~/myhosts contains:
"myso" '(";**;*.*" #p"/usr/mydir/mysos/")

Unloading all .so files and reloading them upon startup. In this example, we unload the (in our case single) .so file with ff:unload-foreign-library and show how to modify excl:*restart-init-function* so the .so file is reloaded. We end with a couple of notes and warnings.

USER(1): :ld /usr/mydir/mysos/b.so
; Foreign loading /usr/mydir/mysos/b.so.
USER(2): (ff:unload-foreign-library "/usr/mydir/mysos/b.so")
NIL
USER(3): (defun reload-my-so () (load "/usr/mydir/mysos/b.so"))
RELOAD-MY-SO
USER(4): (setq excl:*restart-init-function* 'reload-my-so)
USER(5): (dumplisp :name "mycl")
;; NOTE: no warning about loaded .so files.
USER(6):
;; The new image comes up as follows (note the message about foreign loading):
Allegro CL 5.0 [SPARC; R1] (7/11/98 15:01)

Copyright (C) 1985-1998, Franz Inc., Berkeley, CA, USA. All Rights Reserved.
;; Starting socket daemon and emacs-lisp interface...
; Foreign loading /usr/mydir/mysos/b.so.
USER(1):

Notes and warnings:

  1. Certain Allegro CL utilities may dynamically load .so files. (CLIM does if loading into a running image rather than being built into the image, e.g.). These files are specified with logical pathnames with host sys:, so they should be found without programmer intervention.
  2. The *restart-init-function* in our example is very simple and not very useful. In real situations, programmers would likely get information from a command-line argument or an initialization file about the location of the needed files and act on that information.
  3. The files must be found and reloaded before any foreign function that requires them is called.

18.0 Logical pathnames and the dumped image

All logical pathname translations are flushed as the first action when a dumped image restarts. This is a feature. There is no way for Lisp to tell whether the translations are valid upon restart (and they almost certainly will not be valid if the image is restarted on a different machine on a different network). Rather than devise a way to communicate to Lisp whether to flush translations on startup (and thus overload the few ways available to communicate with restarting images), Allegro CL instead provides tools for properly re-establishing translations using specific files.

The function excl:logical-pathname-translations-database-pathnames returns a list of pathname namestrings. Initially, it returns the list ("sys:hosts.cl"). You may use push or pushnew to add other strings naming files. For example,

USER(5): (logical-pathname-translations-database-pathnames)
("sys:hosts.cl")
USER(6): (pushnew "~/myhosts" (logical-pathname-translations-database-pathnames))
("~/myhosts" "sys:hosts.cl")
USER(6): (logical-pathname-translations-database-pathnames)
("~/myhosts" "sys:hosts.cl")

When looking for a translation for a logical pathname, Lisp will look first in ~/myhosts and then in sys:hosts.cl. It is not an error if a named file does not exist. Therefore, your translations should be added to hosts.cl in the Allegro directory or to a file of your own which you push onto excl:logical-pathname-translations-database-pathnames as described above. (Many users of Lisp may not have permission to modify hosts.cl. Indeed, having several users modifying that file is impractical.)

19.0 How the dumped image finds its Allegro directory

The Allegro directory is the location of the executable file (lisp or lisp.exe). In the separate executable/image model (new to Unix users of Allegro CL but familiar to Windows users), finding the directory using the executable is simple and should work without problems.

20.0 How to use the dumped image

The image is specified to the executable with the –I argument, Thus, if the dumped image is named myimage.dxl, and lisp.exe is the executable, then this starts a Lisp using myimage.dxl:

% lisp.exe [+ args if any, Windows only] –I <path>/myimage.dxl [other args]

If no -I argument is specified, the executable looks for an image in the same directory with the same name as itself (thus lisp.exe will look for lisp.dxl). If you have created an image for general use, you may wish to copy it to the Allegro directory (assuming you have permission to do so) and copy the executable to have the same name.

Copyright (C) 1998-1999, Franz Inc., Berkeley, CA. All Rights Reserved.