Common Lisp, Using ASDF Install With SBCL

So I, like any self respecting geek trying to learn Common Lisp started to read the cliki, which is a wiki that supports Common Lisp projects. Nifty right? Right. It's full of stuff, and between it and Common-Lisp.net, you can be pretty sure that if it exists in the common Lisp world it'll appear on one of those two sites. And for every cool lisp thing, rather than usable instructions for installing the software it would just say "use asdf install and have fun." Which is good if you know what asdf is or what it's supposed to, and how to use it.

But, there's a decent chance that you're like me, and were completely clueless.

Turns out asdf-install is the common lisp equivalent of the CPAN shell or Ruby gems, or the Debian project's dpkg, with some lisp-centric variations. This post provides an overview and a "quick start guide" in case you want to get started. The directions I provide are in line with "the way I like to keep my file system organized (e.g. ~/) and center around the Arch Linux and SBCL system that I use. However, this should hold true (more or less) for any distribution of Linux with SBCL and possibly to other lisps. Feel free to add your own modifications in comments or in the lisp page on wikish.


Begin by getting to a CL REPL. If you have emacs and "slime" installed get to a REPL using "M-x slime" otherwise just type sbcl at a system prompt. Installing slime, emacs, and sbcl are beyond the scope of this post, but in general use the packages designed for your platform and you should be good. MacPorts for OS X users and the package managers for most prevalent Linux-based operating systems should have what you need.

At the REPL do the following:

(require 'asdf)
(require 'asdf-install)

(asdf-install:install '[package-name])

Remember to replace the [package-name] with the dependency or package that you want to install. asdf will ask you if you want to install the package system wide, or in a user-specific user directory. I tend to install things in the user-specific directories because it gives me a bit more control over things. The user specific directory is located in ~/.sbcl if you want to poke around the files yourself. Done. That's pretty straight forward. Lets get to the awesome parts.

Make a ~/lisp directory. I keep mine stored in a git repository. I've also kept my .sbcl directory inside ~/lisp and then created a symbolic link so that the computer is none the wiser. Issue the following commands to accomplish this:

cd ~/
mkdir -p ~/lisp/systems
mv .sbcl ~/lisp/
ln -s ~/lisp/.sbcl

Adjust the path as necessary. Additionally You will also want to create a ~/.sbclrc file with some code for asdf to initialize itself when SBCL runs. Do the following:

cd ~/
touch ~/lisp/.sbclrc
ln -s ~/lisp/.sbclrc

In your .sbclrc file you'll probably want something like the following:

(require 'asdf)

(pushnew #p"/usr/share/common-lisp/systems/" asdf:*central-registry* :test #'equal)
(push #p"/usr/share/common-lisp/systems/" asdf:*central-registry*)

(pushnew #P"/home/[username]/lisp/systems/" asdf:*central-registry* :test #'equal)
(push #P"/home/[username]/lisp/systems/" asdf:*central-registry*)

This tells SBCL and asdf where all of the required lisp code is located. Alter path's as needed. We've not talked very much about the ~/lisp/ directory yet. Basically it's a directory that serves as a playground for all things lisp related. Each "project" or package should have it's own directory, which will contain lisp code and an .asd file. To make a package accessible via asdf on your system create a symbolic link for these .asd files in your ~/lisp/system folder. Done.

So let's set up a basic "hello world" package that we'll call "reject," just for grins. File one, ~/lisp/reject/reject.asd:

(defsystem "reject"
  :description "a reject program
  :version "0.1"
  :author "tycho garen"
  :licence "ISC License"
  :depends-on ("cl-ppcre")
  :components ((:file "reject")
               (:file "package")))

The dependency on cl-ppcre isn't required, but that's how it would work if you needed a regex engine for a reject hello world application. File two, ~/lisp/reject/package.lisp:

(defpackage reject (:use :common-lisp))

File three, ~/lisp/reject/reject.lisp:

(in-package :reject)

(defun hello-world () ()
(print "Hello World, tycho"))

(hello-world)

Once those fils are saved, issue the following commands to create the needed symbolic link:

cd ~/lisp/system/
ln -s ~/lisp/reject/reject.asd

Now, from the REPL issue the following expression to load the package:

(asdf:operate 'asdf:load-op 'reject)

And then the following expression to test that it works:

(hello-world)

And you're set to go. As to how you'd write or package up something that might actually have value? That's a problem I'm still wrapping my head around. But that can all happen later.

If I've overlooked something or you think my understanding of something here isn't incredibly clear, do be in touch. I hope this helps!

comments powered by Disqus