When you decide to make an application standalone using the two step process it is possible that you may encounter the following situation: the build process completes without a problem but running the program lands you in the debugger with a message about Quicklisp not being found.
Why is Quicklisp a requirement to run a standalone application?
Some libraries can use a variety of sub-libraries, of which they only need one,
to provide their service. The libraries are optimized to load only the
dependency which is actually used and none of the others. An example of such a
cl-dbi which can use MySQL, PostgreSQL and SQLite as backends but only
loads the driver for the active database.
One method to implement this dependency optimization is to load the sub-library at runtime using Quicklisp. This forces you to include Quicklisp in your binary which defeats the whole point of the two step build process.
To date I have used three libraries that uses Quicklisp at runtime:
cl-dbi. All three use
#+/#-quicklisp to select
between Quicklisp and ASDF as systems loader. In principle this should allow
the creation of binaries which don’t contain Quicklisp but it doesn’t work
because the libraries are only ever compiled when Quicklisp is available.
The solution1 for using these libraries without Quicklisp in the binary is to provide the referenced Quicklisp function as an empty stub. The stub must only be included when building the binary.
To implement the solution, add a file ql-patch.lisp to your project
;;file name: ql-patch.lisp (defpackage quicklisp-client (:use :cl) (:nicknames :ql) (:export :quickload) (:documentation "Quicklisp look-alike fake package.")) (in-package :quicklisp-client) (defun quickload (&rest args) "This is a load-bearing hack." t)
and update the ‘Buildapp settings’ section in your makefile2 to load ql-patch.lisp before loading your system.
# Buildapp settings B_FLAGS = --output $(OUTDIR)/$(TARGET) B_FLAGS += --manifest-file $(MANIFEST) B_FLAGS += --load ql-patch.lisp # <<< Insert this line B_FLAGS += --load-system $(QL_SYSTEM) B_FLAGS += --entry app:main
The patch does nothing, how does it work?
Each of the three libraries mentioned before contain code of the form
#+quicklisp (ql:quickload ...) #-quicklisp (asdf:load-system ...)
With the two step build process everything is compiled during the manifest
creation stage when Quicklisp is still available. This causes the
(ql:quickload) call to be included in the compiled code.
During the binary creation stage Quicklisp is not present and the previously
compiled code is loaded using ASDF. The
(ql:quickload) call does not yet
cause an error because it is used inside a function and will only be executed
When the time comes to load the dependency the
(ql:quickload) call is
executed irrespective of whether the target system is already present or not.
The stub function’s purpose is purely to prevent an ‘undefined function’ error. It should not do anything else because the required library should be loaded already.
This scheme requires that all the libraries that the
intends to load be present already. The easiest method to accomplish this is to
include them in the application’s system definition in the