From: Jeff Dalton
Subject: Re: Q: How do I compile Lisp source into an executable?
Date: 
Message-ID: <D5t3G9.ED3@cogsci.ed.ac.uk>
In article <··········@eclipse.torolab.ibm.com> ·····@flogger.torolab.ibm.com (Itrat Khan) writes:
>Is there a way to compile a Lisp program? I've read the FAQ which makes
>it sound like you can't or that it's not a standard thing. I'm using
>GNU Common Lisp 1.0 for AIX to run a short LISP program. I'd like this 
>program to be a standalone executable. Currently, I do something like 
>this:
>
>  gcl < source.lsp
>
>to run my Lisp code. Unfortunately, this dumps out all the "interactive"
>stuff like the results of a setq and stuff. This still works for me 
>since all my output goes to files, but it's ugly. (Can you turn this 
>output off?)
>
>I find it hard to believe that something as old as Lisp can't be compiled
>into an executable. I'd appreciate any suggestions or explanations about
>compiling Lisp programs. For now, I'll just keep using the interpreter.

Distinguish between:
    Lisp (a family of languages),
    Common Lisp (one language in the family),
    Common Lisp implementations.

Lisp (the family) is fairly old.  The present-day languages and
implementations are less so.  A number of Lisps are small and easy
to implement as interpreters.  A compiler is harder.  So there
are a large number of Lisp interpreters out there.  However,
Lisp compilers are fairly common.  Almost all Common Lisp
implementations have a compiler of one sort or another.
Most compile to machine code, but there's at least one byte-compiler.

Whether a compiler exists and how it's used depends on the language
and the implementation.

In Common Lisp, you can use the function compile-file to compile
a file of Lisp code.  The load function can be used to load both
compiled and non-compiled files.  In GCL on ondinary Unix machines
(I don't know about the AIX version), you can save an image with
si:save-system.  This saves the whole GCL system, plus any code
you've loaded in.  The result is kind of large.  Other Lisps
might let you save something much smaller.

Example:

  Run GCL and type

    (compile-file "mycode.lsp")

  [Optionally] exit and rerun it (so you get a cleaner image).  Then:

    (load "mycode.o")

    (si:save-system "mysystem")

The file mysystem should be an executable.  It will behave like an
ordinary GCL except that your code will be built-in.  However, you
can change its behavior by redefining si:top-level.  When doing
this, I use the following, which I define in different ways for
different Common Lisps (this is the AKCL/GCL version):

  (defun save-image (filename top-level-fn)
    (setf (symbol-function 'si:top-level)
          top-level-fn)
    (si:save-system filename))

I also define things like this (again the AKCL/GCL versions):

(defun argc ()
  (si:argc))

(defun argv (n) ; -> string or nil
  (if (< n (si:argc))
      (si:argv n)
    nil))

And here's an example of a top-level fn that can be installed as
si:top-level (as above):

(defun a-top-level ()
  (handler-bind ((condition #'last-resort-condition-handler))
    (top-level-init)
    (main-program)
    (bye 0)))

(defun top-level-init ()
  (let ((init-file-p t)
        (i 1))
    (labels ((arg ()
               (argv i))
             (pop-arg ()
               (prog1 (arg) (incf i))))
      (loop
        (when (null (arg))
          (return))
        (case (intern (string-upcase (arg)))
          (-load    (pop-arg) (load (pop-arg)))
          (-break   (pop-arg) (break "~A" '-break))
          (-eval    (pop-arg) (eval (read-from-string (pop-arg))))
	  ...)))))

An alternative to building a large image is to write a shell script
that runs GCL (or perhaps a modified GCL) and tells it to load
your compiled code.  By a "modified GCL" I have in mind that you
would save a full image, but it would be one that you could use
in a number of different cases.  For instance, you might provide
convenient command-line arguments as in a-top-level above.

-- jd