$Revision: 5.0.2.18 $
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 Delivery introduction
2.0 Definitions
3.0 Developing the
application and preparing for delivery
3.1 A summary of the
delivery process
3.2 Legal and licensing
issues
3.3 Deciding on necessary
features
3.4 Deciding on
top-level (user interaction)
3.5 Packaging the product
3.6 Including all desired
modules
3.7 Defining the init
functionality
3.8 Specifying
the initial value of *package*
3.9 Setting up
logical pathname translations
3.10 Use of
shared libraries (foreign files)
3.11 CLOS training
3.11.1 Generic
functions, method combination, and discrimination
3.11.2
Effective methods
3.11.3 Caches for fast dispatching
3.11.4 Constructor functions
3.11.5 How to do CLOS start up
optimizations
3.11.6 make-instance optimization
4.0 Creating the deliverable
4.1 Resources
4.2 Defsystem
4.3 Tuning the application
4.4 More on the
development environment
4.5 GC parameters and
switches
4.6 GC cursors
4.7 Allegro Presto
4.8 Allegro Runtime
4.9 Windows specific
information
4.10 Installation of your application on Windows using
the Install Wizard
5.0 Patching your application
after delivery
5.1 The Allegro CL
patch naming scheme
5.2 Loading Allegro CL
patches
5.3 Patches for your
application
5.4 Creating patch files
in general
5.5 Creating a patch file
5.6 What to do with patch
files
5.7
Including application patches in an image at build time
5.8 Superseding a patch
5.9 Withdrawing a patch
5.10 Distributing patches
5.11 Loading patches
This document describes the application generation utility in Allegro CL. The facility differs from the image creation utility (see building_images.htm) in that the end result is not a single image file but a directory of files in theory suitable to be delivered to customers after suitable packaging.
excl:build-lisp-image
or excl:dumplisp
. Those created
with excl:dumplisp
have a parent
image (the image running when excl:dumplisp
is called). Characteristics of a parent image are inherited by a child image created with excl:dumplisp
. See also original
image.excl:dumplisp
, the image running when excl:dumplisp
is called is the parent
image. The child image, that created by excl:dumplisp
,
inherits characteristics of the parent image.excl:generate-application
is the functional entry point for developers to deliver an application. In short,
the task of this function is to build and assemble the files for the developer's
application into a single directory. This directory has many purposes. As a
developer, you might want to:
For the purposes of this document, it does not matter what the motivation of the
developer is, excl:generate-application
is used in the same way.
There are three distinct delivery types, as:
(1) is the most common case, by far. (3) is what is commonly called Lisp as a subroutine. (2) requires registration, either implicit or explicit. In the OLE samples there are examples of both.
It is important to understand that excl:generate-application
calls excl:build-lisp-image
and the latter starts a new (operating system) process to build the requested image.
Any errors that occur during the building of the image will be handled in the other
process. The development environment of the originating process (the one in which
the call to excl:generate-application
was made) cannot be used to debug the problem in the image creating process.
If you want to distribute your applications outside your organization or inside your organization to users with machines not licensed to run Allegro CL, you must be licensed to do so by Franz Inc. One type of license that allows distribution is an Allegro Runtime license. See runtime.htm. Please contact your Franz Inc. sales representative for information on licensing applications.
You need all the features necessary to run your application (whatever they may be). Certain items, like the debugger, the inspector, the tracer, will not be present in an image unless explicitly used or called for. If you are preparing a runtime delivery, be sure to check the license to see what modules cannot be included in the image. See
If you are building a standard Allegro Runtime image (see runtime.htm),
the value of the runtime keyword argument to generate-application (actually,
it is a build-lisp-image argument
accepted by generate-application)
should be :standard
. In that case, the compiler cannot be in the final image.
You must either specify include-compiler nil
or include-compiler
t
and discard-compiler t
. The latter choice allows the
compiler to be present during the build, which is sometimes useful. The compiler may be
included in a Dynamic Allegro Runtime image (value of runtime :dynamic
).
Are your users going to interact with your application through the Lisp top-level (so they will enter Lisp forms or at least one Lisp form), through a custom top-level of your own, or will users interact with your application via some graphical user interface? (Of course, some applications may have no top-level -- that is, little or no user interaction is necessary.)
If your application has a custom top-level, you must write its functionality and have
it initiated when the application image starts. You do this by having the function that is
the value of excl:*restart-app-function*
initiate your top-level, if there is one. If your application has no top level then the
value of excl:*restart-app-function*
should be the function that starts your application running.
If you want to use the standard Lisp top-level, leave the value of excl:*restart-app-function*
nil
. Any initializations you might want to do can be done by the function
that is the value of excl:*restart-init-function*
.
A minimal top-level is provided if you build an image with the include-tpl argument to build-lisp-image (or generate-application, which accepts build-lisp-image arguments). See 10.0 Minimal top levels in building_images.htm for more information.
In the past, it was possible to deliver a application as a single file (called a standalone
application). This is no longer possible. We have, however, created a precise method
to help you easily create and identify all the necessary parts of your application for it
to be complete. excl:generate-application
is the entry point to creating your application. This function creates a directory
containing all the files making up your application.
A standard Allegro CL image on startup does not contain all the system modules that a
program may invoke. Instead, certain modules are left out (and contained in the bundle
file, typically sys:files.bu but the name varies, or in a fasl file in sys:;code;).
When a module is called for with cl:require, it is looked for according
to the sys:*require-search-list*
,
which usually looks in sys:;code; and, if it is not there, in the bundle file
(which is essentially a collection of fasl files). Further, when an important
function associated with the facility is called (e.g. cl:trace for the
trace module, ff:def-foreign-call
for the foreign module, etc.), the system detects that the module must be loaded and loads
it automatically (a process called autoloading).
However, the bundle file, files.bu or whatever it is named, generally cannot be distributed with applications. (It is explicitly forbidden to distribute the bundle file, usually files.bu but the name varies, with a runtime image. If you have a VAR license, you may or may not be allowed to distribute the bundle file, depending on the terms of the license. In this document, we assume you are not permitted to distribute the bundle file. If you have any questions about licensing issues, please contact your Franz Inc. Sales Representative. If you have an Allegro Runtime license, see runtime.htm)
Therefore, if you want functionality in your application, you must ensure that it is loaded into the image.
The file sys:develenv.cl contains a list of cl:require's that load optional functionality for the Lisp development environment. Some of the cl:require's in this file are explicitly forbidden by your Allegro CL Runtime or Allegro CL Dynamic Runtime license agreements, and those are identified by comments. Do not modify that file but rather copy it or the desired parts of it to your own file for use with your own application.
You should cl:require the modules you need for your application to
work properly. Check the autoloads.out file generated when the autoload-warning
keyword argument to excl:generate-application
is specified true. That will tell you what modules might be autoloaded in your application
and you can decide whether it is necessary to include the module. (Just because a module
might be autoloaded, that does not mean that it will be autoloaded in your application.
Modules are typically autoloaded when an important function associated with the module is
called. If your application does not call a function that triggers an autoload, the
autoload won't occur.)
Look at the file sys:;code;aclstart.cl. It is the source for the startup
routine used by Lisp (the function start-lisp-execution) along with the
sources for some ancillary functionality. (Note that the low-level initialization,
including mapping of .so/.dll files built with the image -- systems libraries and
others -- has already been performed when start-lisp-execution is called.
As with any UNIX or Windows program, failure to find a needed shared object or Library
file (so/sl/dll) during the low-level startup causes immediate program failure usually
accompanied by a terse message identifying the unfound file. ff:list-all-foreign-libraries
can be used to identify dependencies on .so, .sl and .dll
files.)
To see exactly what Lisp is doing when it starts up, regarding the loading of the Lisp shared library, you can set the environment variable ACL_STARTUP_DEBUG. This will help diagnose errors in the startup process. Note that on Windows, the messages are displayed in the Console window.
Examining the source for start-lisp-execution will tell you the exact sequence of operations -- when the command-line arguments are processed, when the init files are read, etc., so you can know in what order to do things. The startup sequence is also given in startup.htm.
There are several places where a programmer can intervene in the startup process. One
relatively early place is the restart-actions list (the value of excl:*restart-actions*
).
Please note that this list may be used by Allegro CL or related functionality (such as
CLIM). Therefore, you should add to the list but do not remove items from it or destroy
it. Even earlier, -e command-line arguments are processed (assuming command-line
arguments are not ignored by the image). Slightly later (but with a different interface),
the ACL_STARTUP_HOOK environment variable is examined. If it has a value, that
value is read by read-from-string and the result is evaluated.
The final two locations for programmer intervention in startup are the functions which
are the values of excl:*restart-init-function*
and excl:*restart-app-function*
.
As you may see from aclstart.cl, if excl:*restart-init-function*
is non-nil
, it is assumed to name a function with no arguments and that
function is funcall'ed. The purpose of excl:*restart-init-function*
is to perform application initializations of any sort.
After excl:*restart-init-function*
completes, either excl:*restart-app-function*
is funcall'ed (if it is non-nil
) or a standard Lisp listener
is started (but not both). If your application has its own top-level, it should be started
with excl:*restart-app-function*
.
(Or if no top-level is needed, excl:*restart-app-function*
would perform whatever your application does.) Note that the function that is the value of
excl:*restart-app-function*
must not return. The consequences are undefined if it does return.
It is entirely your choice whether you use your own top-level or use the Lisp top-level. Note too that if you are using the normal top level, that is the image was built with the include-tpl argument to build-lisp-image true, you can start a Lisp top-level at any time by evaluating the following form:
(tpl:start-interactive-top-level *terminal-io* 'tpl:top-level-read-eval-print-loop nil)
Programmers who use a Lisp listener as a top-level often want the current package (the
value of *package*
) to be something other than the common-lisp-user
package when the user sees the first prompt. Evaluating the following two forms as part of
excl:*restart-init-function*
accomplishes this (replace :my-package
with the desired name, of course):
(tpl:setq-default *package* (find-package :my-package)) (rplacd (assoc 'tpl::*saved-package* tpl:*default-lisp-listener-bindings*) 'common-lisp:*package*)
The second form suppresses (on startup) the [changing package from ...] warning printed
by Allegro CL when the value of *package*
is changed by the system in a Lisp
listener (usually printed when the debugger is entered).
All logical pathname translations (except the one for sys: set up in the low-level startup code) are cleared as one of the first actions of start-lisp-execution (indeed, the first form in the function definition):
(defun start-lisp-execution () ... (flush-all-logical-pathname-translations) ...)
This is often not what an application developer wants. However, it is a conscious choice because the potential for mysterious bugs resulting from bogus translations being present in the image outweighed the cost of re-establishing the translations when needed.
If you want to use logical pathname translations in your application, then you will need to arrange for them to be present. You can do this in one of two ways:
excl:logical-pathname-translations-database-pathnames
prior to creating the image to tell the system about the additional translations file (and
the system will look at that file in addition to hosts.cl when it encounters an
unknown logical host). This solution is similar to the one just above but does not require
modifying hosts.cl which may be inconvenient to modify.excl:generate-application
causes all .so/.dll/.sl files loaded during image creation to
be copied to the directory it creates. It also arranges, upon image restart, for these
files to be reloaded from this directory (which is what will become sys:).
(This section was inadvertently left out of the original version of he 5.0 Allegro CL documentation.)
It is possible to significantly speed up the initialization of CLOS-based applications by gathering information about CLOS usage in the application and including that information in the application image. In this section, we discuss what information is useful for this purpose, how to collect it, and how to include it in an image.
Note about the development environment: Lisp users typically run in developer-environment mode. In that mode, the debugger, the code that runs the Emacs-Lisp interface, Allegro Composer (if ordered) etc. is loaded into Lisp. Often your application will not use those facilities and your application images will not want to include them. However, CLOS training will include information about those utilities (and then require you to have them available when you build your application image) unless you do one of the following:
This is the less-desirable solution. You can create an image without the development environment by specifying
:include-devel-env nil
in the call to build-lisp-image. You can then train with that image.
This is the better choice. You will see forms like
(clos::preload-constructors ([packages]))
and
(clos::precache-generic-functions ([packages]))
below. If no packages are listed, the entire system (including development environment features) will be trained. If packages are listed, only things in those packages will be trained. Packages are named by keywords. Typically, packages should include :user, :lisp, and the packages of your application. Thus, if your application packages are :foo and :bar, the preload-constructors form would be
(clos::preload-constructors (:user :lisp :foo :bar))
The preload-generic-functions form would similarly list the packages.
A generic function examines its arguments to determine which method or methods are applicable. This is called discrimination. The symbol-function of a generic-function is a discriminator function. There are various kinds of discriminators and the discriminator for a particular generic function may change during the execution of a program.
When Lisp determines that a generic function needs a different kind of discriminator it checks to see if the one it needs has already been built and, if not, creates one. The creation of a discriminator is relatively expensive since it involves the Lisp compiler.
When a CLOS application is loaded the generic-functions all have a simple discriminator which will select the correct discriminator when the generic function is first called. Therefore when a CLOS application starts it will run very slowly unless the discriminators it needs are already built. The only way to tell which discriminators your program needs is to run your program for a while and then look at the list of discriminators that exist. Allegro CL provides a mechanism for dumping out these discriminators and then loading them in with your program so that when the program starts all the discriminators it will need will already exist.
You can dump discriminator functions to a fasl file by compiling a source file that contains the following two lines after loading and running your application (note that the best optimization is achieved if you combine this with the caching optimization described below):
(in-package :clos) (preload-forms)
With method-combination a call to a generic function can result in a sequence of methods being called. The code that calls the methods and processes the results of each call is called an effective method. In order to make effective methods fast, Lisp compiles them. In order to cut down on the compilation cost, Lisp actually creates effective-method templates which are functions closed over the particular methods to be called.
Thus many effective methods can share the same code. Just as in the case of discriminators above, it is expensive to start a CLOS application running if the effective methods it will need haven't been compiled already. And again Allegro CL provides a way of saving the effective methods that the application has used so that they can be defined before the application starts.
You can dump effective methods to a fasl file by compiling a source file that contains the following two lines after loading and running your application (this is the same as for discriminator functions):
(in-package :clos) (preload-forms)
Generic functions use caching to implement fast dispatching. When an application starts the caches are empty so initial performance is degraded by having to handle cache misses. Allegro CL provides a way to fill the caches when an image starts up.
You can dump caches to a fasl file by compiling a source file that contains the following two lines after loading and running your application (see above under the heading Note about the development environment for information on ([packages]) in the following form):
(in-package :clos) (clos::precache-generic-functions ([packages]})
As we describe briefly below (under the heading make-instance optimization), calls to make-instance can be replaced with calls to some equivalent (but much faster) constructor functions. Allegro CL provides a way to preload compiled constructor functions.
You can dump constructors to a fasl file by compiling a source file that contains the following two lines after loading and running your application (see above under the heading Note about the development environment for information on ([packages]) in the following form):
(in-package :clos) (clos::preload-constructors ([packages]))
The four possible start-up optimizations were just described. Conveniently, two (discrimination and effective methods) are achieved with the same utility. All depend on information being available. Therefore, the following is the first step for all optimizations:
Once you have exercised your application sufficiently, you are ready to create the optimizing files. This is a standard fasl file created by compiling a special source file (described below).
(in-package :clos) (preload-forms) (clos::preload-constructors ([packages])) (clos::precache-generic-functions ([packages]))
Compile closopt.cl with compile-file. Lisp will put the discriminators, the effective methods, the constructors, and the contents of its CLOS caches into the resulting fasl file (closopt.fasl). If that file is built into the application binary image (it should be specified as one of the :lisp-files in a call to build-lisp-image, as an input-file in a call to generate-application, or required by another file specified in either location), then an application using CLOS will start up significantly faster.
Note that loading this file will not invoke the compiler so this can be loaded into a compilerless Lisp.
We have already discussed dumping make-instance constructor functions. Note that calls to make-instance where the class-name is a quoted constant and each of the keywords is a constant are transformed by the compiler into calls to constructor functions. A constructor function is a piece of code that is equivalent to the make-instance call except that it is significantly (10 to 100 times) faster.
The optimization is automatic when the call to make-instance is formed in a particular way.
In order for an optimized constructor function to be used certain restrictions apply:
Generic Function: | Condition for optimization: |
make-instance | Only system-supplied methods are applicable |
initialize-instance | Only system supplied-standard methods and user-supplied :after methods are applicable |
shared-initialize | Only system supplied-standard methods and user-supplied :after methods are applicable |
Conditions for creation of constructor functions: The calls to make-instance are replaced by calls to the constructor regardless of whether an optimized constructor can be used. The first time the constructor function is called, the restrictions are tested and if ok an optimized constructor is generated. When the restrictions are not obeyed the constructor calls make-instance. Redefining a class or one of its superclasses or adding/removing a method to one of the generic functions mentioned above causes the constructor function to be recomputed.
As stated above, excl:generate-application
assembles the files needed to deliver an application. generate-application
both builds the application's image file and copies any other files needed to support this
image. The definition of excl:generate-application
is:
(generate-application application-name destination-directory input-files &key allow-existing-directory application-administration application-files (application-type :exe) autoload-warning (copy-shared-libraries t) (copy-file-function 'sys:copy-file) debug image-only pure-files purify ...excl:build-lisp-image keyword args...)
The required arguments:
application-name
: the name of the application (i.e., "myapp"
).
When coerced to a pathname, this name should not have a directory or type. It is used to
create the name of the executable or .dll/.so/.sl and ancillary
files.destination-directory
: the name of a non-existent directory. It is
the directory used to create the output files. See image-only
keyword argument below.input-files
: the list of Lisp (.fasl or .cl)
files to be loaded, strings or pathnames. Symbols are allowed and signify modules to
be loaded with cl:require
. Note: this argument is passed to excl:build-lisp-image as the value of
the :lisp-files
keyword argument to that function. The keyword arguments:
allow-existing-directory
: allow destination-directory
to exist. If the value of this keyword argument is nil
and the directory
exists, then an error is signaled.application-files
: files which should merely be copied to the
destination directory.application-administration : allows the
specification of various application administrative tasks. The form of the value of
this keyword is(type-keyword ...) or ((type-keyword ...) (type-keyword ...) ...)
(:resource-command-line "...command line arguments...") [UNIX only]
([:shortcut | :batch-file] filename ...command line arguments...) [Windows only]
An error is signaled if |
application-type
: valid values: :exe
, :ole-in-proc-server
,
or :dll
. If :exe
is used, then application-name.exe
is created. If :ole-in-proc-server
or :dll
is used application-name.dll
is created.autoload-warning
: when non-nil
, the file autoloads.out
is created that contains the functions, macros and methods that could possibly be
autoloaded.copy-shared-libraries : if non-nil ,
then copy shared objects/libraries that have been loaded with the Common Lisp function load
, with the system-library keyword argument nil, by the time the image is dumped.
(See loading.htm#1.0 Using the load
function for details of the system-library argument.)The value of this
keyword argument can also be a lambda expression (you cannot use the For shared objects that are copied, the image that is created will load them from the
destination directory upon startup. That is, in the image built by |
copy-file-function
: This function will be used to copy files to
the destination directory. The default value is sys:copy-file and that function is likely
sufficient for most purposes. However, another function can be used if that is
insufficient. This function will be called by the image that calls generate-application
(not the image that builds the image).debug
: more information will be printed about progress as an aid
to debugging.image-only
: just build for the image, and possibly the .pll
file.pure-files
: a list of .cvs and .str files to be
put into the application's .pll file. See 4.0 Creating and using pll files
in miscellaneous.htm.purify
: do automatic purification of Lisp and the
application. This means all the strings and code vectors will be put into a .pll
file. If you choose this option, do not also specify a value for pure-files
.excl:generate-application
accepts and passes through to build-lisp-image
all of build-lisp-image
's keyword arguments except :lisp-files
.
The required input-files argument is used in place of :lisp-files
.
Even if a value is specified for :lisp-files
, it is ignored. See also the
description of the build-executable argument
above, as it is used (differently) by both generate-application and build-lisp-image.Resources are a way of specify default information for an application. The most common of which is command line arguments. Resources are handled differently on Windows and UNIX:
Resources are stored in a plain text file on UNIX. This file, sys:lisprc, if it exists can contain resource information for application startup. Currently, this is just command line arguments. The format of lisprc is:
.command-line: command line args...or
appname.command-line: command line args...where appname is the name of the Lisp executable used to start Lisp and command line args... are a list of valid command line arguments. appname should be used when there are multiple applications sharing the same directory and different command line argument resources are needed for each application.
For example, a sys:lisprc of
.command-line: -Qwould cause all applications in the directory this appears to start up quietly.
If there are both command line arguments in the resource file and given on the command line that starts the application, then command line arguments seen by the application are the concatenation of the resource command line and the given command line. This allows the given command line to override the resource command line.
Resources on Windows do not use sys:lisprc, since executables themselves have resources on Windows. The relevant resource types for delivery are icons and command lines.
There is a utility, setcmd.exe, in the bin/ subdirectory of the Allegro directory, that works only on Windows NT:
setcmd [-o | -p | -r] app.exe [arguments...]The -o flag allows you to set the command line for app.exe to the given arguments. The -p flag prints the command line resource in app.exe. The -r prints all resources in app.exe. setcmd can be used on .dlls as well. A sample call to a command prompt is:
C:\Program Files\acl50\bin\setcmd -o app.exe +cxWhen app.exe is then started, the console window will stay hidden (the meaning of the +cx argument, see startup.htm#3.0 Command line arguments).
There is an alternative method of setting resources, one that works on Windows 95/8 and that allows you to change the default icon for a program. This is how you would set the command line resource:
(require :res "winapi/res") (windows::set-cmd-line "lisp.exe" "foo.exe" "-I" "lisp.dxl")would change the default command line of lisp.exe to -I lisp.dxl by creating a new foo.exe. If you want to change the icon:
(windows::set-exe-icons "lisp.exe" "foo.exe" "ACL5ICON" "foo.ico")would change the icon of lisp.exe to that in foo.ico by creating a new foo.exe. "ACL5ICON" was found from running this command:
setcmd -r lisp.exe Resource type: Resource id: 3 (icon) Resource id: 1 Resource type: Resource id: 3 (icon) Resource id: 2 Resource type: Resource id: 3 (icon) Resource id: 3 Resource type: Resource id: 14 (group icon) Resource name: ACL5ICON Resource type: Resource id: 14 (group icon) Resource name: ACLCONICON
If the application is made up of many source files, then using the defsystem utility
(described in defsystem.htm) will help the management (for
compilation and loading) of the application. If defsystem is used, then it is easy, for
example, to create a single .fasl file representing the compiled application. See
defsystem.htm and the function concatenate-system
for
more information.
The application should be optimized. Allegro CL contains a space and time profiler that should be used to find places in the application which can be optimized. See profiling.htm. The optimization of Common Lisp source code has two components, aside from optimizing algorithms used in the application:
Both of the above can be done globally or locally to a particular function. Functions
which are known to be used frequently should be optimized by declaring the types of the
values bound to symbols, when the types are known and checked. Then, increasing the speed
compilation quality and decreasing the safety and debug qualities will allow the compiler
to produce smaller and faster code. These issues are discussed in compiling.htm.
Note particularly the :explain
declaration discussed that document, in 9.3 Help with declarations.
If the application will not use the development environment of Allegro CL, then certain features of it can be turned off or compiled out of the application. For example, you might use the following global proclamation:
(proclaim '(optimize (debug 0)))
It will cause the compiler to compile with no consideration for easy debugging (presumably your users will not debug your application). Currently, this means local names of variables and the argument list for functions and macros will not be saved. Although the saving is not great, if these features are not to be used, then there is no reason to have the compiler annotate the fasl files with them.
Another saving can be achieved by evaluating:
(setf (argument-saving) nil)
This will cause the runtime calling sequence to be more efficient on some architectures (RS/6000 currently).
Setting of GC parameters and switches appropriate to application-specific behavior is important for performance. gc.htm contains a complete discussion of the subject, and the only information included here is a check-list of items to consider.
:clip-new
(default: nil
)
If keeping newspace small so that scavenges are short is important, then this feature should be enabled. One negative aspect of this, however, is that garbage collections will be more frequent and this may cause more short-lived objects to be tenured, resulting in faster growth of the Allegro CL memory image. You should schedule more frequent global garbage collections to keep the image smaller if you set :clip-new to t.
:print
(default: nil
)
The users of many applications will not want to see the gc messages. Keeping this switch
nil
will prevent them from being printed. On the other hand, the gc message does explain why your application seems to have paused (during a gc). See also the discussion of gc cursors below.
:generation-spread
(default: 4)
Depending on the behavior of the application, changing the generation spread may cause less garbage to be tenured. The default value has been chosen for development but not the runtime environment of applications.
:free-bytes-new-other
(default: 131072)
:free-percent-new
(default: 25)
:free-bytes-new-pages
(default: 131072)
:expansion-free-percent-new
(default: 35)
:quantum
(default: 32)
These parameters determine the size of newspace after a scavenge. There must be at least :free-bytes-new-pages + :free-bytes-new-other bytes free, in addition to there being at least :free-percent-new percent of newspace free. :quantum specifies the number of pages (8k each) for newly created newspaces. The initial value is 32 for 256kb newspaces. :expansion-free-percent-new specifies the percent free in newly created newspaces.
:expansion-free-percent-old
(default: 35)
This specifies how much must be free in an oldspace after it is created. A new oldspace is created because there is some amount of data that needs to be tenured and there is no current oldspace that can hold it.
See gc.htm for more information on memory layout.
A gc cursor facility provides some visual clue to the user that a garbage collection is taking place. Application writers find gc cursors useful since their users may think the application has hung while in fact it is just gc'ing. Unfortunately, implementing a gc cursor is difficult. See gc.htm for more information.
In addition to the above parameters and switches, the variable excl:*global-gc-behavior*
determines whether or not a global gc is automatically performed when a certain number of
bytes have been tenured (moved into oldspace). excl:*tenured-bytes-limit*
specifies this limit. It is very important to note that an interactive application would
have execution suspended for an indeterminate amount of time if a global gc is
performed--scavenges are normally quite short, in comparison.
The initial values for the above parameters are reasonable defaults, but there may be better defaults for individual applications. See gc.htm for more information.
Allegro Presto is designed to limit system code loading to only what is required for the system's execution. See 3.0 The Allegro Presto algorithm in loading.htm for more information about Allegro Presto.
Allegro Runtime is a Franz Inc. product which licenses distribution of application
written in Allegro CL. Please contact your Franz Inc. sales representative if you want
more information on Allegro Runtime and its terms. See the document runtime.htm
for technical details of Allegro Runtime, including a list of restrictions on runtime
images. To produce a runtime image, the runtime keyword argument to excl:generate-application
(actually to excl:build-lisp-image
and passed to that function by excl:generate-application)
must be specified with a non-nil
value. See runtime.htm
for allowable values.
The file msvcrt.dll is needed by all Allegro CL applications generated on Windows (in releaases prior to 5.0.1 final, mfc42.dll was also needed but that is no longer true). If the copy-shared-libraries argument is true, generate-application copies these two files to a subdirectory of the destination-directory called system-dlls (this is a change from 5.0 where they were copied to destination-directory). When your application is installed, these dll's should be copied to the Windows system directory if necessary (i.e. if they are not already there with the same or a later version). In the system-dlls subdirectory, they will not be seen by your application or any other program.
These system dll's have presented a problem for Allegro CL applications. They are needed if the application is to run successfully but having them in more than one location where Windows sees them can create difficulties. In release 5.0, generate-application copied mfc42.dll and msvcrt.dll to destination-directory. However, we discovered there could be problems if they were also in the Windows system directory. But copying them to the Windows system directory blindly is also problematic because of version mismatch (if you overwrite a later version, other programs that depend on the later version may then fail).
Starting in 5.0.1, we have tried to mitigate this problem by providing an installation wizard (described in section 4.10 below) that does the right thing: it finds out if the dll files in the system-dlls subdirectory are in the Windows system directory already. Any that are not are copied to the Windows system directory. The versions of the ones that are present are compared to the versions of the files in system-dlls. Earlier versions are then updated (more precisely, are either then updated or things are arranged so they will be updated when Windows is restarted, so other running programs will not be affected).
Note that dll's loaded with load with :system-library specified as true (see loading.htm#1.0 Using the load function) are not copied to destination-directory or the system-dlls subdirectory. The only files that are copied to the system-dlls subdirectory are mfc42.dll and msvcrt.dll. (This may seem counter-intuitive, but we feel free to copy mfc42.dll and msvcrt.dll because Microsoft explicitly allows it.)
The Allegro CL Install Wizard, a new feature in 5.0.1, is a tool that application programmers writing Allegro CL-based applications can use to help deliver applications on the Windows platform.
In accordance with your license agreement, you can distribute Allegro CL-based applications. The files in the directory described in `1. Create the initial application directory' below are typically suitable for distribution, but again, this is controlled by your license. Ask your Franz Inc. sales representative for information on what your license allows if you are unsure. We assume in the remainder of this section those files are licensed for distribution.
Reasons for providing the Install Wizard. In 5.0, you could create a delivery directory, either with generate-application or the IDE's File | Build Project Distribution menu command. It was hoped that this directory was suitable for distribution, but there turned out to be problems getting system DLL's right, as described above in section 4.9 above. The main problem, recall, is doing the right thing with system DLL's like mfc42.dll and msvcrt.dll. They should be installed on an application user's machine if necessary but should not be installed if not necessary. Somehow, it must be determined whether such installation is necessary. For that reason, simply copying the directory that is the output of generate-application or Build Project Distribution is not enough. Further, when installing on Windows, various bookkeeping tasks like updating the registry must be performed. A program, usually named setup.exe, is typically provided to perform such tasks. The Install Wizard generates an appropriate setup.exe. Note: the user installing the application must have administrator privileges on Windows NT.
Note that programs like InstallShield (tm) also perform the tasks described above. The Install Wizard provided by Allegro CL is a simpler and less flexible variant of such a program.
Here are the steps for using the Install Wizard.
Use either generate-application or the IDE's File | Build Project Distribution to create a directory, which for example purposes we will call c:/foo/foo/. This will be a directory of files and subdirectories. This directory is named by the destination-directory argument to generate-application and by the Distribution directory dialog when using the Build Project Distribution menu command.
When generate-application or Build Project Distribution complete, you now have the initial application directory.
Run the Install Wizard via a shortcut on the Start | Programs | Allegro CL submenu. This will display the Install Wizard dialog, which has the following fields:
The Install Wizard will create a new directory (called the Output directory) and copy the files from the source directory to it. Further, it will generate a program named setup.exe and put it in the output directory.
The following buttons are on the bottom of the dialog: Build, Quit and Help. After filling in the fields, click on the Build button to create the directory specified in Output directory. Quit will exit without building anything. Clicking on Help displays this section of this document in a browser.
When the Install Wizard completes, the output directory is suitable for distributing to application users. We assume it is placed on a CD. How the CD is organized is up to you, the application writer. We assume the CD contains a single directory distdir/ which contains the contents of the output directory from above. (At the toplevel, it may have a file causing it to autorun when the CD is inserted into the drive. In any case, setup.exe must be in the same location with respect to all other files as it was in the output directory.) Note, this will work equally well if you are distributing on floppies or some other media.
Once you have the CD, the you as application developer have finished creating the distribution.
The application user (persumably your customer) receives the application CD and puts it into the CD drive. On the application user's machine, there is (presumably) no Allegro CL, and the source and output directories mention in 2 above do not exist either. Recall we assume the CD contains a single directory distdir/ which contains the contents of the output directory from 2 above. That directory includes the installation program setup.exe. To run setup.exe on Windows NT, the user must have administrator priviliges.
When the application user runs setup.exe (in our example, by inserting the CD into the drive and running distdir/setup.exe), setup.exe will ask the user for an installation directory for the application, which we will call appdir. This directory must not exist. setup.exe will create the directory and install the application. Specifically, setup.exe will do the following:
If at any time the installation program gets an error, it will undo any changes made to the disk containing appdir and to the Windows registry. That is, if the application does not install, then appdir will not exist and no application files will be left on the user's machine, and the registry will be left in the pre-installation state.
There may be bugs in the version of Allegro CL used to deliver your application and there may be bugs in your application code. Both need to be fixed for your users. Allegro CL bugs are typically fixed by patches supplied by Franz Inc. You, of course, have to decide how to provide fixes for bugs in your application, but you may wish to mimic the patch system used by Allegro CL. That system and the tools associated with it are the subject of this section.
The following two features are useful in a patch system:
The tools provided support both features. The tools are the sys:defpatch macro, the sys:load-patches function, and the excl:featurep predicate function.
We first describe the Allegro CL patch scheme and then discuss how you can adapt it to your application's needs. Allegro CL patch files are named as follows:
p<m><p><n>.<v>
So the first letter is p, followed by
For example, p0a001.001 is the first version of the first patch file on version 0 (ACL 5.0) for product a (Allegro CL base Lisp). p0a001.002 is the second version of the first patch file. p0a011.002 is the second version of the eleventh patch file.
All Allegro CL patches are placed in one directory, sys:;update, that is the update subdirectory of the Allegro directory, where Allegro CL was installed. (In earlier release on Unix, there were several patch directories. In version 5.0, there is one but patch files are coded according to product.)
Patches are loaded by sys:load-patches. It takes only keyword arguments and the arguments are:
update-directory | The directory in which to look for patch files. Defaults to the Allegro CL patch directory, sys:;update. |
product | Value should be nil , meaning load all patch files regardless
of the product code (the third letter of the filename, <p> above), or a character or list of
characters, meaning load only those files whose product code (third letter) match the
single character or is in the list of characters. |
patch-file-filter | A function of three arguments, a product code, a pathname, and a version (<m> above). Returns true if the pathname names a valid patch file (based on parsing the name and location only). |
patch-file-sorter | A function of three arguments, a product, a list of patch files (validated by the patch-file-filter), and a version (<m> above). Sorts the list into the order in which the files should be loaded. |
libfasl | A boolean indicating whether the patch files should be loaded in libfasl mode. See 3.0 The Allegro Presto algorithm in loading.htm for more information on libfasl loading. |
version | Specifies the version (<m> above). Should be a character object naming a decimal digit (#\0 - #\9). This is for use with application patches only. Defaults to #\0. |
You should have an update/ subdirectory to your application directory (or wherever sys: translates to in your application). Then you can distribute post-loadable Allegro CL patches file to customers. post-loadable means that the patch can be loaded into an existing image. However, not all Allegro CL patches are post-loadable. You must distribute a new image with patches loaded if you need to deliver a non-post-loadable Allegro CL patch to your customers.
The easiest way to provide loadable patches to your own application is to have a separate directory (say sys:;myapp-update) where your patches will go. Then mimic the Allegro CL patch naming scheme and call sys:load-patches, specifying update-directory to be the directory you chose. sys:load-patches should be called when your application starts up. As long as your patch files are created with sys:defpatch, described next, the scheme should work with your application.
If you want to use a different naming scheme, you will have to supply your own patch-file-filter and patch-file-sorter functions. See the description of sys:load-patches for advice on how to do that.
Again, please do not mix your application patch files with Allegro CL patch files in the same directory (unless you use your own naming scheme that cannot be confused with the Allegro CL naming scheme, and even then it is a bad idea). Franz Inc. reserves the right to use any product code at any time and so you cannot guarantee the uniqueness of filenames simply by using an apparently unused product code.
The following table describes the three attributes of patch files.
Attribute | Meaning |
post-loadable | Can be loaded into a running image (so named because loadable after -- post -- the original image build). |
superseded | This specific patch file has been superseded but a later version (a patch file with the same p<m><p><n> but a larger <v>, e.g. p0a005.001 might be superseded by p0a005.002). Note that loading a superseded patch file only updates the record of patches loaded but does not otherwise modify the image. |
withdrawn | This particular patch file has been withdrawn and there is no later version. Note that loading a withdrawn patch file only updates the record of patches loaded but does not otherwise modify the image. |
What is the purpose of the superseded and withdrawn attributes? Two problems with patch management are (1) ensuring that users have all necessary patches and (2) ensuring they do not have patches which (usually because of problems with the patch) have been superseded or withdrawn. The superseded and withdrawn attributes address the second problem. The Allegro CL scheme tries to ensure that users do not have inappropriate patch files by actually replacing superseded or withdrawn patches with new patch files with exactly the same name but different attributes. Then the patch-loading mechanism ensures that if two patches with the same id are loaded, the earlier version must be superseded. By providing superseded patches with the same file names as bad patches, users are thus unlikely to have an out-of-date patch file because those files are overwritten by the superseded or withdrawn patch file when the user received the updated set of patch files. This should become clearer as we describe the scheme in more detail.
A patch file is a compiled Lisp file. At the start of the patch file, there should be a sys:defpatch form, followed by the code that implements the patch. Therefore, a skeleton patch file will look like the following:
;; Our application
;; patch for report XXXX
(sys:defpatch "mpnnn" 1 ;; replace mpnnn with the product version (m),
;; product code (p), the patch id number (nnn) and
;; 1 with the patch version
"MESSAGE" ;; Brief patch information (should fit on one line)
:type :myapp ;; Type should be a keyword of your choosing.
;; Other arguments may be specified.
)
;; Put patch code after here ...
(in-package :blah)
The required arguments to sys:defpatch are:
id
A string identifying the patch number or name. This is usually the <m><p><nnn> of the patch file name and typically includes zero-filled numeric characters -- e.g. "0a001", "1j195", "0z234" -- but can include alphabetic characters and need not be exactly five characters long. It is not the patch file prefix. This id is unique to the patch.
version
A fixnum in the range 1 to 999 inclusive. This is the <v> of the patch file name.
desc
A string containing a brief description of the patch. Short strings are better because this string is printed by excl:dribble-bug when it reports information of patches and long strings may mess up the printing (by forcing line wraps). Example "Fixes filename bug" or "Speeds up processing employee info".
The keyword arguments to sys:defpatch are:
type
A keyword specifying the type of the patch. Default is
:unknown
. Application programmers should decide on a single type or a group of types for their application and classify their patches according to that scheme. When information on patches in an image is printed by excl:dribble-bug, there are organized by type. The following types are reserved by Allegro CL and should not be used by application programmers::lisp
,:clim
,:aclwin
,:clim
,:system
, and:allegro*
(any keyword starting with :allegro).defpatch-version
Default is 1. If a new version of sys:defpatch is supplied by Franz Inc., the default will be changed and patches with the old version will be rejected. In general, do not worry about this argument unless a new version of sys:defpatch is distributed (that distribution will include additional instructions).
post-loadable
Default
t
. Whent
, the patch file can be loaded into a running image. Whennil
. the patch file can only be included in an image during image creation with build-lisp-image. The patch load will abort if load-patches tries to load it into a running image.superseded
Default
nil
. If true, the patch (when loaded with load-patches) will be marked `superseded patch - more recent version exists' and the patch will not be (further) loaded. The compile-time effect of specifying this argument true is to ignore the remainder of the file after the sys:defpatch form.withdrawn
Default
nil
. If true, the patch (when loaded with load-patches) will be marked `withdrawn patch' and the patch will not be (further) loaded. The compile-time effect of specifying this argument true is to ignore the remainder of the file after the sys:defpatch form.
feature
Default
nil
. When non-nil
, value can be any form acceptable as an argument to excl:featurep. If excl:featurep returnsnil
when applied to the form, the patch loading is aborted. The reason for aborting printed by the system is the form that is the value of this argument (made into a string).compile-feature
Default
nil
. When true, value can be any form acceptable as an argument to excl:featurep.The compile-feature keyword argument is designed to facilitate producing patches for different platforms. For example, suppose a patch is only applicable to versions of Allegro CL that use os-threads for multiprocessing. Specifying
:os-threads
as the value of compile-feature will cause compilation to proceed when compiled by a platform that uses OS thread (only Windows in release 5.0) but to abort when compiled by a non-os-thread (Unix in 5.0) Allegro CL. Aborting is what you want in that case, since the patch is not needed for such platforms. The aborting of compilation will signal a condition which looks for asys::abort-patch-compiling
restart. If that restart is not present, an error is signaled (and the programmer must intervene to do something). More typically, compilation of patch files are done in a form like the following:(dolist (x patch-files) (restart-case (compile-file x) (sys::abort-patch-compiling (patch) ;; Actions of your choice, e.g printing a message like: (format t "Aborted patch file ~s, featurep returned nil" x))))
Compilation of the remaining patch files will continue and all relevant patch fasl files will be present when the dolist form completes.
How you and your application team will manage patch files depends on how you deliver your application and whether or not your customers can build new images with build-lisp-image. Only customers of properly licensed VARs and customers who hold an appropriate license from Franz Inc. for Allegro CL will be able to build new images. Customers (of yours) who receive runtime images (and are not independently licensed by Franz Inc.) cannot make new original images because dumplisp (called by build-lisp-image does not work in runtime images.
This is an issue because (1) patches which are not post-loadable (i.e. cannot be loaded into a running Lisp) can only be included in a new original image; and (2) post-loadable patches can be loaded into a running image but should not be loaded into an image which already contains them. Therefore, if you have runtime customers (who cannot build original images), you can send them post-loadable patches and arrange for those to be loaded automatically, but you may also send them new images from time to time (which include non-post-loadable patches but will usually include all available post-loadable patches as well). You must ensure that such users do not load the post-loadable patches in their possession which are already included in the current image.
Here is a possible scheme which will work for applications which are distributed as runtime images. (This is not the only possible scheme or even the best for your situation. It illustrates how the tools and their features can be used to produce a scheme that works.)
(sys:load-patches :update-directory
"sys:;update-myapp;" :product #\a)
(sys:load-patches);;
to load an Allegro CL patches in update/
(sys:load-patches :update-directory
"sys:;update-myapp;" :product #\b)
Note that even if your customer ignores your instruction to delete the p0a<nnn>.<vvv>
files from myapp-update, those (no longer valid) patches will not be loaded
because sys:load-patches
is looking for product b and those files
have product a.
The discussion under the previous heading concerns distributing patches to users who cannot themselves build an original image with build-lisp-image. You, however, will build original images (and perhaps your customers are licensed to do so as well). How do you include patch files in the image when it is built? You put appropriate sys:load-patches forms in custom.cl and make sure all your patches are in the directories specified in the sys:load-patches forms. Allegro CL patches can be put in the update subdirectory (they will be included automatically by the image build process).
Say you have sent a patch, p0a001.001 to your users. The sys:defpatch form at the top of the patch file is:
(sys:defpatch "0a001" 1 "Fixes whatever" :type :myapp)
A user complains that including the patch fixes the problem reported but seems to cause
another problem. You check it out and find that the patch does introduce new problems. So
you create a new version. You put it into a file and compile it to p0a001.002.
The sys:defpatch form at the head of the
file
is:
(sys:defpatch "0a001" 2 "Fixes whatever" :type :myapp)
We recommend that you also remake p0a001.001 with the following sys:defpatch form at its head:
(sys:defpatch "0a001" 1 "Fixes whatever" :type :myapp :superseded t)
When the compiler processes this sys:defpatch form, it stops compiling the file. Therefore, you can leave the original patch source (for later reference) without worrying that the patch fasl file will be larger than necessary or contain bogus compiled code. You can then tell your customer to put both files in the update directory, overwriting the p0a001.001 already present.
Why do we recommend producing a new p0a001.001 along with p0a001.002? Why not a new, corrected p0a001.001, or why not just tell the user to delete p0a001.001?
Well, you can do those things and often things would work just fine. But our experience is based on the fact that you cannot force users to do anything and the observation that users often misunderstand what you tell them to do or just do not do it (but think they have). The system we are describing is designed to avoid certain obvious problems and to catch mistakes or omissions by the user before they result in trouble.
Why not just update p0a001.001? Because you cannot then tell from a directory listing alone whether the user has the new, right patch or the old, bad patch.
Why not just tell the user to delete p0a001.001 (i.e. why remake the file)? This will work and it is not necessary to remake the file. But you really want your users to get rid of the bad patch file, which ensures that it never causes problems. You can tell your users to download all the patch files allowing overwriting of files. If they do that, the bad patch will be overwritten. Further, if (somehow) p0a001.002 is lost but p0a001.001 is marked superseded, it will not corrupt the image (as the bad patch would) and the dribble-bug output would make clear that a superseded patch has been recorded without its update having been loaded.
Occasionally, a patch must be simply withdrawn. A speed-enhancement patch which actually slows things down is one example (your idea for a speedup failed and you do not have other ideas). We again recommend replacing the existing patch file with a patch file marked superseded and creating a new patch file (with a later version number) marked withdrawn. Again, this allows you to tell from a directory listing whether the user is up-to-date or not and shows the fact that the patch is withdrawn in the dribble-bug output. So, the sys:defpatch form in the superseded p0a001.001 would be (like above):
(sys:defpatch "0a001" 1 "Fixes whatever" :type :myapp :superseded t)
And the sys:defpatch form in the p0a001.002, the withdrawn patch would be:
(sys:defpatch "0a001" 2 "Fixes nothing" :type :myapp :withdrawn t)
As with a superseded patch, when the compiler processes this sys:defpatch form, it stops compiling the file. Therefore, you can leave the original patch source (for later reference) without worrying that the patch fasl file will be larger than necessary or contain bogus compiled code.
In the era of the World Wide Web, ftp, and users around the world, a typical way to distribute patches to users is having them download the patches from an ftp (or www) site directly into the appropriate directory without actual human contact between you and your users. If you use this model, you should tell your users to download every patch, you should use the version and superseded mechanisms we describe above, and you should tell your users to expect files to be overwritten.
You can also, of course, distribute patches on request, one at a time, with instructions (which usually include `delete all earlier versions of this patch!') The more patch distribution has a human-contact element, the less you have to worry about old version and bad patches not being deleted. The more the system is automated, with less handholding, the more replacing bad patch files with superseded patch files and being very careful about version numbers becomes necessary.
Patches are compiled lisp files, and such files can be loaded in a number of ways. There is no reason a post-loadable patch file cannot be loaded with load. Often that is useful for quick tests. However, Allegro CL provides a patch-loading function carefully integrated with the patch system described in this section. As far as possible we recommend that you load with sys:load-patches.
The function excl:featurep returns true
or nil
as the features called for in its argument are or are not on *features*
.
It is thus a functional analog of the #+/#- reader macros. It is used by sys:load-patches to process the feature
argument in sys:defpatch forms.
Things to note
sys::abort-patch-loading
. If that restart is found, it is invoked. If
no such restart is found, an error is signaled. sys:load-patches sets up the restart
but no such restart will (likely) be present when loading a patch file with load.
Therefore, using load is best done with single or just a few patches but sys:load-patches should be used for any
automated procedure or when many patches are involved. Note that loading patches marked
withdrawn or superseded does not signal an error.*features*
while loading a patch since the patch file may
add a feature to that list, but the addition will be lost when the binding in undone.Copyright (C) 1998-1999, Franz Inc., Berkeley, CA. All Rights Reserved.