November 12th 2004 #
random, November 12th 2004
Dave Roberts talks about lisp deployment problems. (Actually, he talks about RAD stuff too, but I'll ignore that.)
He seems to see the runtime/core issue as the primary one. While it is true that unlike for C and C++ there is no platform standard CL, I don't see how that leads to the same pit with Java. Unlike for Common Lisp I'm unaware of any Public Domain or MIT/BSD-licenced Java runtime. For comparison, you can bundle CMUCL or SBCL runtime and core with your application no matter what licence you're using, which in turn means that your lisp-ignorant users can download the package and install it "just like that". The build-process of the lisp itself is a non-issue vrt. application deployment.
A trivial example of packing a lisp application "as a normal executable" under a make: make install facade follows. Adapting it to point-and-click installation, code that uses libraries, or binary distributions is left as an exercise, since that isn't the point. The point is that although deployment takes a bit of work, it really isn't all that hard.(*) Of course, it would be nice to automate the drudge-work of such packaging. SB-BUNDLE anyone?
The package will contain the lisp sources, and an SBCL core and runtime. The sources are compiled and loaded into core, which is dumped. The new core and the runtime as installed where-ever, and a shell-trampoline is generated that will launch them.
hello.lisp
(defun hello-world () (write-line "Hello, world!"))
build.lisp
(load (compile-file "hello.lisp"))
(setf *invoke-debugger-hook*
(lambda (condition hook)
(declare (ignore hook))
(format *error-output* "Error: ~A~%" condition)
(quit :unix-status 1 :recklessly-p t)))
(save-lisp-and-die "hello.core"
:toplevel (lambda () (hello-world) (quit)))
install.sh
#!/bin/sh
ROOT=$1
LIBDIR=$ROOT/lib/hello-world/
BINDIR=$ROOT/bin/
mkdir -p $LIBDIR
mkdir -p $BINDIR
RUNTIME=$LIBDIR/hello-world.bin
CORE=$LIBDIR/hello-world.core
cp sbcl $RUNTIME
cp hello.core $CORE
TRAMP=$BINDIR/hello-world
echo "#!/bin/sh" > $TRAMP
echo "exec $RUNTIME --core $CORE --noinform \
--userinit /dev/null --sysinit /dev/null" >> $TRAMP
chmod a+x $TRAMP $RUNTIME
Makefile
INSTALL_ROOT=/usr/local/ all: hello.core hello.core: hello.lisp build.lisp ./sbcl --core ./sbcl.core \ --userinit /dev/null --sysinit /dev/null \ --load build.lisp .PHONY: install install: sh install.sh $(INSTALL_ROOT)
(*) Caveat: SBCL's linkage-table code hasn't been ported to OS X yet, so this won't work there for applications using foreign code. Information on linkage-table internals -- what is it, and why you should port it -- here. In the meanwhile SBCL using Macfiends should load only the non-foreign bits into the custom core, and arrange for the trampoline to load the alien interface code and foreign objects.