The index for the Allegro CL Documentation is in index.htm. The documentation is described in introduction.htm.
This document contains the following sections:
1.0 Delivery introductionThis 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.
generate-application is the functional entry point for developers to deliver an application. (generate-application is only available in Enterprise versions of Allegro CL.) 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, 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 generate-application calls 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 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. account manager 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 Allegro CL runtime license to see what modules cannot be included in the image. See 3.6 Including all desired modules for information on insuring all needed and licensed functionality is included in the delivery image.
generate-application only
builds runtime images (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) must be one of
:standard
(the default),
:dynamic
or :partners
. If
:standard
, 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
) and in a Partner's Runtime
image (value of runtime :partners
). Partner's Runtime is
described in Allegro CL
Partner's Runtime in runtime.htm.
Allegro CL supports non-ASCII character sets and supports to specification of a locale which specifies the standard character set to be used. If the locale where the application being generated by generate-application is different from the locale on the machine where the application is generated, then the necessary code for switching external formats must be included in the image or available to the application. This is most easily done by specifying the runtime-bundle keyword argument true. See Locales in applications in iacl.htm.
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 your application image
starts. You do this by having the function that is the value of
*restart-app-function*
initiate your top-level. If your application has no top-level, then
the value of *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
*restart-app-function*
nil
. Any initailizations that
are necessary can be done by the function that is the value of *restart-init-function*
.
Warning for users calling generate-application from the IDE:
the value of *restart-app-function*
may be a function which
starts the IDE. That value will be inherited if the
restart-app-function keyword argument to generate-application (or build-lisp-image) is unspecified. Be
sure to specify it nil
if you want to use the
standard Lisp top-level, rather than leaving it unspecified.
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 Minimal top levels in building-images.htm for more information.
In the past, it was possible to deliver an 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. 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 require, it is looked for according to
the *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. trace for the trace
module, 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, see Autoloading in
implementation.htm).
However, the bundle file supplied with the distribution, 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. account manager. If you have an Allegro Runtime license, see runtime.htm)
However, a new feature in release 6.0 allows creation of a bundle
file specifically for a runtime application. Specify
:runtime-bundle t
in your call to generate-application and a files.bu
will be created and placed in the application directory. This file may
be distributed with your application.
Or you can ensure that all desired modules are loaded into the image. The remainder of this section describes how to do that (the description is from the 5.0.1 documentation. In 5.0.1, there was no runtime-bundle keyword argument to generate-application.
The file sys:develenv.cl contains a list of require's that load optional functionality for the Lisp development environment. Some of the 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 require the modules you need for your application to work properly. Check the autoloads.out file generated when the autoload-warning keyword argument to 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.)
If you determine a module which a function might autload is not needed in your application, you should consider fmakunbound'ing the function, so calling it generates an undefined function error rather than a file not found error (in a runtime application with no bundle file, an error of some sort will be signaled when a function that triggers an autoload is called).
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. 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 *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 *restart-init-function*
and *restart-app-function*
. As you
may see from aclstart.cl, if *restart-init-function*
is
true, 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 *restart-init-function*
completes, either
*restart-app-function*
is funcall'ed (if it is
true) or a standard Lisp listener is started (but
not both). If your application has its own top-level, it should be
started with *restart-app-function*
. (Or if no top-level is
needed, *restart-app-function*
would perform whatever
your application does.) Note that the function that is the value of
*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 the
function that is the value of *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:
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:).
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, 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, 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.
There is a relatively simple example showing how to create an application in examples/testapp/. See readme.txt in that directory for information on the example, which is designed to show how to package an application. The code in the examples/testapp/ directory can be freely used.
The definition of 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) debugimage-only pure-files purify runtime-bundle ...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. Keywords are allowed
and signify modules to
be loaded with require.
Note: this argument is passed to
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
(the default) 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 ...) ...) .
(type-keyword ...) can be:
(:resource-command-line "...command line arguments...")
[UNIX only] This creates a lisprc in the destination directory which sets the default command line arguments to ...command line arguments.... See the 4.1 Resources section below for more information.
This creates either a batch file or a shortcut named filename that will initialize
the application. command line arguments are the arguments to One use of this is for OLE registration. For example: '(:shortcut "One-time registration of ~a""-register") If the given foo.exe -- -register 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 true, the file autoloads.out
is created that contains the functions, macros and methods that could possibly be
autoloaded.build-executable
:
this is a build-lisp-image
keyword argument but
is also used by
generate-application
if a value is supplied. The value
must name a Lisp executable file (such as "mlisp" on Unix or "mlisp.exe" on
Windows). It is used by
build-lisp-image
to start the Lisp
process that builds the image. Unless image-only
is true,
generate-application
copies a Lisp executable to the application
directory. The executable specified as the value of
this argument is the one copied.
See the description of this argument in building-images.htm for information on when it is useful: a value is specified either when a custom executable has been built (see main.htm or when you want a character size in the new image that is different from the charcater size in the running image. On this last point, see The character size in the resulting image in building-images.htm.
The value of this
keyword argument can also be a lambda expression (you cannot use the |
copy-file-function
: This function will
be used to copy files to
the destination directory. The default value is
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). If the default is used,
all keyword arguments to copy-file are called with their default values.
It is simple to write your own function which calls
copy-file with other
argument values, fi desired.
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
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
.runtime-bundle
: if specified t
a bundle file named files.bu will be placed in the application
directory. This file contains the modules allowable in a runtime
image. This means that such modules need not be loading into the
application image during the application build. This argument is new
in release 6.0.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 to 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\acl60\bin\setcmd -o app.exe +cxWhen app.exe is then started, the console window will stay hidden (the meaning of the +cx argument, see Command line arguments in startup.htm).
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) (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""ACLICON""foo.ico")would change the icon of lisp.exe to that in foo.ico by creating a new foo.exe. "ACLICON" 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: ACLICON 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 in that document, in
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 global garbage collections more frequently 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
*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). *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 The Allegro Presto algorithm in loading.htm for more information about Allegro Presto.
Because much of the size saving obtained by Allegro Presto can be achieved with pll files and other techniques, and because Allegro Presto adds significant compexity to code and images, it is intended to remove the Allegro Presto facility in a future release.
Allegro Runtime is a Franz Inc. product which licenses distribution of
applications written in Allegro CL. Please contact your Franz
Inc. account manager 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. generate-application only produces runtime
images. The runtime defaults to
:standard
and must be either
:standard
or :dynamic
. See
runtime.htm for allowable values.
The file msvcrt.dll is needed by all Allegro CL applications generated on Windows (in releases 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 all needed system DLL's 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 Installation of your application on Windows using the Install Wizard 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 Using the load
function in loading.htm) 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, added in release 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. account manager 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 Windows specific information 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, then 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 mentioned 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.
It is best to test an application on a different machine from the one it was developed on, as this ensures that machine-specific dependencies (presence of system libraries, for example) are better controlled for. However, even testing on the same machine can provide useful information. Because most necessary files are in the application directory, even after installation, the machine dependency problem is reduced. (Note that on Windows, ACL DLL's are installed in system directories so you must be sure that the application is not working just because the ones from the Allegro CL installation are present.)
Evalaution copies of Allegro CL have a built-in expiration date (paid-up licensed copies do not have an expiration date). Applications built from evaluation copies will display the following when started:
WARNING: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WARNING: Application will expire in XXX days. WARNING: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
where `XXX' is the number of days until expiration. If you believe you have a paid-up, licensed copy of Allegro CL and you see that warning when your application starts, please contact Franz Inc. for advice, since such a warning should not appear. (Submit a bug report as described in Reporting bugs in introduction.htm.)
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 defpatch macro, the load-patches function, and the 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 releases on Unix, there were several patch directories. In version 5.0 and later, there is one but patch files are coded according to product.)
Patches are loaded by 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 The Allegro Presto algorithm in loading.htm for more information on libfasl loading. Note: use of Allegro Presto is deprecated and the facility may be removed in a future release. |
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 load-patches, specifying update-directory to be the directory you chose. 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 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 dribble-bug, they 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 true, value can be any form acceptable as an argument to featurep. If 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 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 threads (only Windows in release 6.0) but to abort when compiled by a non-os-threads (Unix in 6.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.)
*restart-init-function*
, the following
load-patches forms
are evaluated: (sys:load-patches :update-directory
"sys:;update-myapp;" :product #\a)
(sys:load-patches);; to load an Allegro CL patches in
update/
*restart-init-function*
is
changed to(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 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 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-2000, Franz Inc. Berkeley, CA., USA. All rights reserved. Created 2000.10.5.