Building Common Lisp Executables
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