Chapter 2 Operating a CL Development EnvironmentThis chapter
covers some of the hands-on techniques used when working with a CL development environment,
specifically, the Allegro CL® environment from Franz Inc. If you are completely unfamiliar
with any Lisp language, you may wish to reference Chapter 3 as you read this
chapter. http://www.alu.org/table/systems.htm These systems follow the same basic principles, and most of what you learn and write on one system can be applied and ported over to others. The examples in this guide were prepared using Allegro CL for Linux. Where possible, we will note Allegro CL-specific syntax and extensions.
2.1 Installing a CL EnvironmentInstalling a CL
environment is generally a straightforward process. For Allegro CL on Linux,
this basically involves running a simple shell script which steps you through
some licensing information, then proceeds to unpack the distribution, and sets
up the CL executable and supporting files.
2.2 Running CL in a Shell WindowThe most
primitive and simplest way to run CL is directly from the Unix (Linux) shell
from within a terminal window. Most programmers do not work this way on a daily
basis because other modes of use provide more power and convenience with fewer
keystrokes. 2.2.1 Starting CL from a Terminal WindowTo start a CL session from a terminal window, simply type lisp from the Unix (or DOS) command line. Assuming your shell execution path is set up properly and CL is installed properly, you will see some introductory information, then will be presented with a Command Prompt which should look very similar to the following: USER(1): CL has entered
its read-eval-print loop, and is waiting for you to type something
which it will then read, evaluate to obtain a return-value, and finally print this resulting
return-value. 2.2.2 Stopping CL from a Terminal WindowNow that you have learned how to start CL, you should probably know how to stop it. In Allegro CL, one easy way to stop the CL process is to type (excl:exit) at the Command Prompt. This should return you to the shell. In very rare cases, a stronger hammer is required to stop the CL process, in which case you can try typing (excl:exit 0 :no-unwind t) Try It: Now try starting and stopping CL several
times, to get a feel for it. In general, you should notice that CL starts much
more quickly on subsequent invocations. This is because the entire executable file
has already been read into the computer's memory and does not have to be read
from the disk every time. (in-package :user) (defun hello () Save the file to disk. Now, at the CL prompt in the shell where you started the CL environment, compile and load this file as follows (text after the "USER" prompt represents what you have to type; everything else is text printed by CL): USER(3):
(compile-file "/tmp/hello") USER(4): (load
"/tmp/hello") By default, the
compile-file
command
will look for files with the .lisp suffix, and the load command will
load the resulting compiled machine-code (binary) file, which by default will
have the extension .fasl. The extension ".fasl" stands
for "FASt Loading" file. USER(5):
(hello) You should see the String Hello, World! printed (without double-quotes), then the returned String (with double-quotes) will be printed as well. In the next chapter, The CL Language, we will learn more about exactly what is going on here. For now the main point to understand is the idea of compiling and loading definitions from files, and invoking Functions by typing expressions at the CL command line.
2.3 Running CL inside a Text EditorA more powerful way of developing with CL is by running it from within a Unix (or DOS) shell that is running inside a buffer in a powerful text editor, such as Gnu Emacs1. One advantage of this approach is that the editor (in our example, Emacs) keeps a history of the entire session: both the expressions the programmer has typed, as well as everything that CL has printed. All these items can be easily reviewed or recalled. 2.3.1 A Note on Emacs and Text EditorsTo develop
using Common Lisp, you can, of course, use any text editor of your choice,
although Emacs happens to be especially synergistic for working with CL, for
reasons we will discuss later. 2.3.2 Emacs TerminologyAs you will
learn in the Emacs Tutorial, when working with Emacs you make frequent use of key chords. Similar to
"chords" on a piano, keychords can allow some powerful text processing
with relatively few sequential keystrokes.
2.3.3 Starting, Stopping, and Working With CL inside an Emacs ShellTo start Emacs, type emacs or gnuemacs then start a Unix (or DOS) shell within emacs by typing M-x shell. Now type lisp inside this shell's window to start a CL session there. To shut down a session, exit CL exactly as above by typing (xcl:exit) Exit from the shell by typing Exit and finally
exit from Emacs by typing C-x C-c or M-x kill-emacs. Note that it is good
practice always to exit from CL before exiting from Emacs. Otherwise the CL
process may be left as an "undead" (zombie) process. (list 1 2 3) (+ 1 2 3) (> 3 4) (< 3 4) Now, of course, you can edit, compile, load, and test your hello.lisp file as we did in Section 2.2. But this time you are staying within a single environment (the text editor environment) to achieve all these tasks.
2.4 Running CL as a subprocess of EmacsAn even more
powerful way of developing with Allegro CL is by running it within Emacs in
conjunction with a special Emacs/Lisp interface provided by Franz Inc. This
technique provides all the benefits of running in an Emacs shell as outlined
above, but is more powerful because the Emacs-CL interface extends Emacs with
several special commands. These commands interact with the CL process, making
the editor appear to be "Lisp-aware." The combination of Emacs with the
Emacs- CL interface results in a development environment whose utility
approaches that of the vintage Symbolics Lisp Machines, which many Lisp aficionados
still consider to be technology advanced well beyond anything produced today. 2.4.1 Starting the CL subprocess within EmacsTo enable your Emacs to function in the proper manner, place the following expressions in a file named .emacs in your home directory:
Table 2.1: Common Commands of the Emacs-Lisp Interface (setq
load-path As above, you may have to modify this pathname to point to your actual installed location of Allegro CL (acl5). Once you have added these lines to your .emacs file, you should be able to restart emacs, then issue the command: M-x fi:common-lisp to start CL
running and automatically establish a network connection between the Emacs
process and the CL process (in theory, the two processes could be running on different
machines, but in practice they usually will run on the same machine). Accept
all the defaults when prompted. emacs -f fi:common-lisp This will start Emacs, which itself will immediately launch CL. 2.4.2 Working with CL as an Emacs subprocessOnce you have
started CL within Emacs, you will be presented with a special buffer named *common-lisp*
which in many
ways is similar to simply running CL within a shell within Emacs as above. But
now you have several more capabilities available to you, as outlined in Table
2.1.
In short, Emacs becomes a remarkably powerful, infinitely customizable, CL integrated development environment. 2.4.3 Compiling and Loading a File from an Emacs bufferTry it: Try starting Emacs with a CL subprocess as
outlined above. If you have trouble, consult the URL listed above for complete
instructions on running the Lisp-Emacs interface. (defun hello
() Now, compile and load the contents of this Function definition with C-M-x. Finally, switch to the *common-lisp* window again with C-x o, and try invoking the hello Function by calling it in normal Lisp fashion: USER(5):
(hello) You should see
the results printed into the same *common-lisp* buffer.
2.5 Integrated Development EnvironmentSome CL implementations support or integrate with an IDE, or Integrated Development Environment. Such environments provide visual layout and design capabilities for User Interfaces and other graphical, visual techniques for application development. For example, such a system is available for Allegro CL on the Microsoft platforms. The details of these systems are covered in their own documentation and are beyond the scope of this guide.
2.6 The User Init FileWhen CL begins
execution, it usually looks for an initialization file, or "init" file, to
load. When CL loads this file, it will read and evaluate all the commands
contained in it. .clinit.cl in the user's home directory on Unix/Linux, and c:"clinit.cl on Windows
systems. (in-package :user) (defun
load-project () This will have
the effect of defining a convenient Function the user can then invoke to load
the files for the current project. Note the call to the in-package Function, which
tells CL which Package to make "current" when loading this file. As we
will see in more detail in Section 3.7, CL Packages allow programs to be
separated into different "layers," or "modules." Notice also that in
the calls to load we do not specify a file "type" extension, e.g. .lisp or .fasl. We are making
use of the fact that the load Function will look first for a binary file
(of type fasl), and if this is not found it will then look for a file of type lisp. In this
example we assume that our Lisp files will already have been compiled into
up-to-date binary fasl files.
2.7 Using CL as a scripting languageAlthough CL is usually used in the interactive mode described above while developing a program, it can be also used as a scripting language in more of a "batch" mode. For example, by running CL as: lisp -e '(load "~/script")' < datafile1 > datafile2 it will load all of the Function definitions and other expressions in file script.fasl or script.lisp, will process datafile1 on its Standard Input, and will create datafile2 with anything it writes to its Standard Output. Here is an example of a simple script.lisp file: (in-package :user) (defun
process-data () (process-data) This file
defines a Function to process the datafile, then calls this Function to cause
the actual processing to occur.
2.8 Debugging in CLCL provides one
of the most advanced debugging and error-handling capabilities of any language
or environment. The most obvious consequence of this is that your application
will very rarely "crash" in a fatal manner. When an error occurs in a CL
program, a break occurs. CL prints an error message, enters the debugger, and presents the
user with one or more possible restart actions. This is similar to running
inside a debugger, or in "debug mode," in other languages, but in CL this ability
comes as a built-in part of the language. USER(95): (+
'r 4) Restart
actions (select using :continue): The number [1] at the front of the prompt indicates that we are in the debugger, at Level 1. The debugger is itself a CL Command Prompt just like the toplevel Command Prompt, but it has some additional functionality. The next section provides a partial list of commands available to be entered directly at the debugger's Command Prompt: 2.8.1 Common debugger commands
Franz Inc.'s Allegro Composer product also offers graphical access to these commands, as well as additional functionality. 2.8.2 Interpreted vs Compiled CodeCL works with
both compiled and interpreted code. When you type expressions at a Command Prompt, or use CL's load Function to load
lisp
source
files directly, you are introducing interpreted code into the system. This
code does not undergo any optimization or translation into a lower-level machine
representation - internally to CL it exists in a form very similar to its
source code form. CL must do
considerable work every time such code is evaluated, since it must be
translated into lower-level machine instructions on each use. 2.8.3 Use of (break) and C-c to interruptIn order to cause a break in your program interactively, issue the C-c command. When running inside Emacs, you must use a "double" C-c, because the first C-c will be intercepted by Emacs. Depending on what your application is doing, it may take a few moments for it to respond to your break command. Once it responds, you will be given a normal debugger level, as described above. 2.8.4 ProfilingCL has built-in
functionality for monitoring its own performance. The most basic and commonly used
component is the time Macro. You can "wrap" the time Macro around any
expression. USER(2): (time
(dotimes (n 10000) (* n 2))) cpu time (non-gc) 130 It is often
interesting to look at the difference in time between interpreted
and compiled code. The example above is interpreted, since we typed it directly
at the Command Line, so CL had no opportunity to optimize the dotimes. In compiled
form, the above code consumes only one millisecond as opposed to 147
milliseconds.
2.9 Developing Programs and Applications in CLFor developing a serious application in CL, you will want to have a convenient procedure in place for starting up your development session. 2.9.1 A Layered ApproachThe development
session consists of your favorite text editor with appropriate customizations,
and a running CL process with any standard code loaded into it. While you can
certainly develop serious applications on top of base CL, typically you will
work in a layered fashion, on top of some standard tools or libraries, such as an embedded
language, a webserver, etc. 2.9.2 Compiling and Loading your ProjectAn individual project
will generally consist of a tree of directories and files in your computer's filesystem.
We will refer to this directory tree as the project's codebase.
CL does not
dictate one standard way of accomplishing this task, and in fact, several
options are available. One option is to use a defsystem package, which
will allow you to prepare a special file, similar to a "make" file, which
lists out all your project's source files and their required load order.
Allegro CL contains its own Defsystem package as an extension to CL, and the
open-source MK:Defsystem is available through Sourceforge (http://www.sourceforge.net). 2.9.3 Creating an Application "Fasl" FileFasl files in
Allegro CL and most other CL systems have the convenient property that they can
simply be concatenated, e.g. with the Unix/Linux cat command, to
produce a single fasl file. Loading this
single file will have the same efiect as loading all the individual files which
went into it, in the same order as they were concatenated. 2.9.4 Creating an Image FileLoading Lisp
source files or compiled binary files into memory at the start of each session
can become slow and awkward for large programs. excl:dumplisp The Image File is typically named with a .dxl extension. Once you have created an Image File, you can start a session simply by starting CL with that Image File, as follows: lisp -I <image-file-name>.dxl You must then compile/load any files that have changed since the Image File was created. Starting CL with the Image File has the same effect as starting a base CL and loading all your application files, but is simpler and much faster. 2.9.5 Building Runtime ImagesCL Image files
built with excl:dumplisp contain the entire CL environment, and may also contain information which
is specific to a certain machine or certain site. Allegro CL also provides a
mechanism for building runtime images, which contain only the
information needed to run an end-user application. These Runtime Images can be
packaged and distributed just as with any stand-alone software application. 2.9.6 Using an Application Init FileIn some cases,
for a finished production application, you will want the CL process to execute
certain commands upon startup (for example, loading some data from a database).
However, you do not want to depend on the end-user having the appropriate .clinit.cl in his or her
home directory. For such cases,
you can specify a difierent location for the init file, which can be installed
along with the application itself. One way to accomplish this is with the -q command-line
argument to the lisp command. This argument will tell CL to look in the current directory,
rather than in the default location, for the init file. cd
$MYAPPfiHOME In this example, both the application's init file and the application's image file would be housed in the directory named by the environment variable $MYAPP_HOME.
2.10 Using CL with Other Languages and EnvironmentsOne of CL's strong points is its exibility in working with other environments. In this section we will briey mention six different ways in which CL can integrate and/or communicate with other languages and environments. 2.10.1 Interfacing with the Operating SystemOne of the most basic means of interacting with the outside world is simply to invoke commands at the operating system level, in similar fashion to Perl's "system" command. In Allegro CL, one way to accomplish this is with the Function excl:run-shell-command. This command takes a String which represents a command (possibly with arguments) to be executed through an operating system shell, such as the "C" shell on Unix: (excl:run-shell-command "ls") The Standard
Output from a shell command invoked in this fashion will be inherited by CL's Standard
Output, so you will see it in the normal CL console. Alternatively, you can
specify that the output go to another location, such as a file, or a variable
defined inside the CL session. 2.10.2 Foreign Function InterfaceAllegro CL's foreign function interface allows you to load compiled libraries and object code from C, C++, Fortran, and other languages, and call functions defined in this code as if they were defined natively in CL. This technique requires a bit more setup work than using simple shell commands with excl:run-shell-command, but it will provide better performance and more transparent operation once it is set up. 2.10.3 Interfacing with CorbaCorba, or the
Common Object Request Broker Architecture, is an industry-standard mechanism
for connecting applications written in different object-oriented languages. 2.10.4 Custom Socket ConnectionsJust about every CL implementation provides a mechanism to program directly with network sockets, in order to implement "listeners" and network client applications. As a practical example, Figure 2.1 shows a Telnet server, written by John Foderaro of Franz Inc., in 22 lines of code in Allegro CL. This Telnet server will allow a running CL process to accept a Telnet login on port 4000 on the machine on which it is running, and will present the client with a normal CL Command Prompt (for security, it will by default only accept connections from the local machine). 2.10.5 Interfacing with Windows (COM, DLL, DDE)Most Commercial CL implementations for the Microsoft Windows platform will allow CL applications to use various Microsoft-specific means for integrating with the Microsoft platform. For example, an Allegro CL application can be set up to run as a COM Server, or compiled into a DLL to be used by other applications. 2.10.6 Code Generation into Other LanguagesCL excels at
reading and generating CL code. It is also a powerful tool for analyzing and
generating code in other languages. An example of this can be found in Chapter
5, where we use a convenient CL macro to generate HTML for a web page.
|