Setting up a decent Lisp environment (w/SBCL)

A Lisp logo
  1. Set up a Lisp environment
  2. SBCL quirks
  3. Use Quickproject
  4. Efficient command line Lisp scripting
  5. Connecting to a Remote Lisp via Swank
  6. Launching an SBCL core dump as a daemon
  7. Lisp Links
  8. Lisp Articles
  9. Set up a Lisp environment

    Quicklisp

    Now days I'm more or less following Zach Beane's blog article and Quicklisp beta page.

    If this is a new machine, install sbcl from the package manager (sudo apt-get insall sbcl), then download the current source and build the latest version, install it to /usr/local/. Start with a fresh .sbclrc file:

    Get quicklisp set up

    mkdir quicklisp && cd quicklisp
    curl -O http://beta.quicklisp.org/quicklisp.lisp

    Start up sbcl and load quicklisp. Then do

    (quicklisp-quickstart:install)
    (ql:add-to-init-file)

    Use it to load some packages:

    (ql:quickload "cl-ppcre") 
    (ql:quickload "cl-who") 
    (ql:quickload "vecto") 
    (ql:quickload "uffi") 
    (ql:quickload "ieee-floats") 
    (ql:quickload "hunchentoot") 
    (ql:quickload "drakma")

    Add the following line:

    (:tree (:home "src/lisp"))

    to this file:

    mkdir -p ~/.config/common-lisp/source-registry.conf.d
    nano ~/.config/common-lisp/source-registry.conf.d/projects.conf

    And run this in sbcl:

    (asdf:initialize-source-registry)

    Note: when a package export list gets screwed up the best way to fix it is call delete-package.

    Slime

    Load Slime from quicklisp:

    (ql:quickload "quicklisp-slime-helper")

    It tells you what to add to .emacs:

    (load (expand-file-name "~/quicklisp/slime-helper.el"))
    (require 'slime)
    (setq inhibit-splash-screen t)
    (setq inferior-lisp-program "/usr/local/bin/sbcl")
    (slime-setup '(slime-fancy slime-tramp slime-asdf))
    (slime-require :swank-listener-hooks)
    

    Finish .sbclrc with the following

    ;;; If a fasl was stale, try to recompile and load (once).
    (defmethod asdf:perform :around ((o asdf:load-op)
                                      (c asdf:cl-source-file))
       (handler-case (call-next-method o c)
        ;; If a fasl was stale, try to recompile and load (once). ;
         (sb-ext:invalid-fasl ()
           (asdf:perform (make-instance 'asdf:compile-op) c)
           (call-next-method))))
    
    ;;; Use this to enable shebang style scripts like this:
    ;;; 
    ;; #!/usr/bin/sbcl --noinform
    ;; (write-line :Hello, World:)
    ;; 
    ;;; If the first user-processable command-line argument is a filename,
    ;;; disable the debugger, load the file handling shebang-line and quit.
     (let ((script (and (second *posix-argv*)
                        (probe-file (second *posix-argv*)))))
       (when script
        ;; Handle shebang-line              ;
         (set-dispatch-macro-character ## #!
                                       (lambda (stream char arg)
                                         (declare (ignore char arg))
                                         (read-line stream)))
        ;; Disable debugger                 ;
         (setf *invoke-debugger-hook*
               (lambda (condition hook)
                 (declare (ignore hook))
    	    ;; Uncomment to get backtraces on errors ;
    	    ;; (sb-debug:backtrace 20)      ;
                 (format *error-output* :Error: ~A~%: condition)
                 (quit)))
        ;; Load the script file and quit    ;
         (load script)
         (quit)))

    Try the new sbcl. Then start emacs and try slime. Everything should work.

    Notes:

    • Might also need fortran for cl-blapack. sudo aptitude search fortran to find the latest version.
    • sudo aptitude install libblas-dev liblapack-dev
    • If using a 64-bit Linux, this might be a backport, so set up the link in /usr/lib/ by hand:
    • cd /usr/lib
      sudo ln -s i386-linux-gnu/libgfortran.so.3 .
    • Now I can load org.middleangle.cl-blapack which is needed for lisp-matrix (along with ffa, etc).
    • (ql:quickload "org.middleangle.cl-blapack")
      (ql:quickload "lisp-matrix" 
    • If buildling a hunchentoot project on this machine, make sure the reference to swank is accurate:
    • (load (merge-pathnames
         "quicklisp/dists/quicklisp/software/slime-20110829-cvs/swank-loader.lisp"
        (user-homedir-pathname)))

    SBCL quirks

    For a long time if I ran into name conflicts between packages I had the option to select which one to proceed with. I update SBCL every other release or so. Within the last three or four months the option to select the source to use for a name seems to have disappeared, and instead an error is generated:

      error: 
        (during compile-time-too processing)
        USE-PACKAGE # causes name-conflicts in #
        between the following symbols:
          CL-EXTRA:DATE, FINANCE::DATE
        --> EVAL-WHEN 
        ==>

    Yes, I miss it too. It seems there are some hairy issues with packages, hash tables, and threads. IIRC, they are supposed to be resolved at some point. use UNINTERN. (Mario Mommer)

    (unintern 'symbol :package)

    It's already resolved. The problem here is that SBCL no longer invokes debugger during compilation errors, but just records them. (Stas Boukarev)

    For the time being, use C-M-x rather than C-c C-c [lisp-eval-defun] on the DEFPACKAGE form. (Tobias Rittweiler)

    Use Quickproject

    Zach Beane's Quickproject makes it trivial to create a asdf project template with .asd, .lisp and README files in a project-named directory which is created.

    (ql:quickload "quickproject")
    (quickproject:make-project #p"src/lisp/project-name/" :depends-on '(cl cl-ppcre) 

    Efficient command line Lisp scripting

    I got this from Teemu Likonen off the sbcl-help list. The idea is to build a special sbcl core which is stripped of startup junk and use it run your scripts. You can pre-load commonly used libraries into the binary so it doesn't waste time loading them. Here is a simple one:

    sbcl --noinform
    * (require :asdf)
    * (require :local-time)
    * (sb-ext:save-lisp-and-die "sbcl-script" :executable t)
    

    Then write scripts as follows (assuming the core is located /usr/local/bin/sbcl-script:

    #!/usr/local/bin/sbcl-script --script
      (format t "Local time is now ~a~%" (local-time:now))
    

    Connecting to a Remote Lisp via Swank

    Connecting to a local lisp which has swank running is easy: in emacs start "M-x slime-connect". The same thing can be done to connect to a remote lisp via ssh. In one xterm start an ssh session:

    ssh -L4007:127.0.0.1:4005 $inervo

    But don't use it directly. In another local xterm start emacs and remote connect using:

    M-x slime-connect RET 4007

    This maps the local port 4007 to the remote port 4005. Now from a local emacs, launch slime with

    Launching an SBCL core dump as a daemon

    After saving a core dump that is self-starting (i.e. built so it launches the desired start-up function) you can launch it as a daemon using something like this script:

    #!/bin/sh
    # Define environment variables needed by cron
    HOME=/home/jcunningham
    DIR=${HOME}/jcunningham/website
    PATH=${HOME}/bin:${HOME}/usr/local/bin:${HOME}/usr/bin:/usr/local/bin:/usr/bin:
    MAILTO=jcunningham@achilles.olympus.net
    
    cd $DIR
    
    # launch with nohup ./http.sh &
    
    RUNNING=`/bin/ps -A | /bin/grep parceletti.core`
    if [[ ! $RUNNING ]]; then 
    #   $DIR/parceletti.core 1>> $DIR/http.out 2>> $DIR/http.err
     nohup $DIR/parceletti.core &
    fi

    Lisp Articles

    (Sort of a to-do read list.)

    1. Advanced Functional Programming in Lisp