Since Common Lisp is a language standard (not an implementation) it is hard to provide a single set of instructions or guidelines that would work for all implementations. There are various implementations of Common Lisp that target native machine code, C code, bytecode, JVM, etc. So the build instructions, project structure, etc. depend on the target.

## Using SBCL

Here is a minimal example that builds a Lisp program into a binary executable with SBCL:

    (defun main ()
      (format t "hello, world~%"))
    (sb-ext:save-lisp-and-die "hello" :executable t :toplevel #'main)

The SBCL-specific `save-lisp-and-die` function saves the Lisp process as a core image. The `:executable t` keyword argument includes the SBCL runtime in the image to ensure that the image is a standalone executable. This is why the executable for even a simple hello-world program tends to be quite large (30 MB to 50 MB)! The `:toplevel` argument specifies the function to run when the core file is run.

Here are some example commands to get you started:

    $ cat hello.lisp
    (defun main ()
      (format t "hello, world~%"))
    (sb-ext:save-lisp-and-die "hello" :executable t :toplevel #'main)
    $ sbcl --load hello.lisp
    $ ./hello
    hello, world

## Moving Unportable Code to Command Line Argument

If you would rather not have SBCL specific code in the Lisp source code file, then you could move the `sb-ext:save-lisp-and-die` call out of your source file to the SBCL command invocation. The source code now looks like this:

    (defun main ()
      (format t "hello, world~%"))

The shell commands now look like this:

    $ cat hello.lisp
    (defun main ()
      (format t "hello, world~%"))
    $ sbcl --load hello.lisp --eval "(sb-ext:save-lisp-and-die \"hello\" :executable t :toplevel #'main)"
    $ ./hello
    hello, world

## Using Buildapp

By the way, there is also Buildapp that provides a layer of abstraction for building executables from Lisp programs. It works with SBCL and CCL. It requires the toplevel function to be called with an argument though. Therefore the source code needs to be modified to the following:

    (defun main (argv)
      (declare (ignore argv))
      (format t "hello, world~%"))

Then Buildapp can be invoked like this:

    $ cat hello.lisp
    (defun main (argv)
      (declare (ignore argv))
      (format t "hello, world~%"))
    $ buildapp --load hello.lisp --entry main --output hello
    ;; loading file #P"/Users/susam/hello.lisp"
    $ ./hello
    hello, world