What confused me a lot is that nobody seems to give an example on how to build a binary out of a Lisp program/make it runnable from command-line.
Also most tutorials/books I found don't guide you on how to build an application/structure your code – which is rather confusing for a beginner. You have to spend a lot of time and try and error to get things working using Quicklisp. I got often the impression, that since Lisp is so old, everyone using it knows how to do things and forgot to document for newcomers their knowledge.
That's from 2016 and it covers a LOT of practical Lisp lore. Basically Edi wrote down much of his knowledge how to write Lisp code. Not only from hobby projects - Edi also has extensive knowledge from commercial projects.
The commercial, and expensive, Lisps also have extensive facilities and documentation how to deliver applications. LispWorks for example supports delivery as standalone programs, applications with GUI, shared libraries and delivery for iOS and Android apps. Edi Weitz for example wrote a bunch of applications for Windows with LispWorks.
The reason nobody can give you an example for how to make a binary is because there are many many different ways of doing that. To name just a few:
* in ABCL you would generate a jar file, just like with java or clojure
* in SBCL you could dump a core file, there are some tools that can package that up in a command line binary
* if you use a bytecode compiler(like clisp), you'd use that the same way like python or ruby, you'd put your script in a text file, with a #! line at the top and run it like any other shell script.
* if you use a Lisp->C compiler, you'd generate C code and then compile that with GCC or Visual Studio or whatever
* if you use image based programming, you'd just load your code in the lisp image and just use lisp itself as your command line, your "binary" would then be just a normal lisp function.
* If you're deploying a service, you might want to package it in a docker image or even a VM image or have some build and deploy script depending on your environment or needs.
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.
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` 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 which 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 --script hello.lisp
$ ./hello
hello, world
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
By the way, there is also Buildapp[1] 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:
(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
Also most tutorials/books I found don't guide you on how to build an application/structure your code – which is rather confusing for a beginner. You have to spend a lot of time and try and error to get things working using Quicklisp. I got often the impression, that since Lisp is so old, everyone using it knows how to do things and forgot to document for newcomers their knowledge.