random-state.net

Nikodemus Siivola

<< next | top | previous >>

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.