Home News Notes Projects Themes | Feed ATOD

Setting up a Common Lisp environment

lisp.png

Setting up a Common Lisp environment is not easy for beginners. In this note1, we will take a logical and progressive approach:

  1. SBCL -> Common Lisp implementation.
  2. Emacs + Sly -> Common Lisp IDE.
  3. ASDF -> build system.
  4. Quicklisp -> package manager.
  5. Quickproject -> easy creation of Common Lisp projects as ASDF systems.
  6. Buildapp -> easy compilation for your Lisp projects.
  7. StumpWM -> full-blown Common Lisp window manager that will lispify your desktop experience.

You can already stop after step 2 and be productive in Lisp, or study the many great Lisp books out there.

SBCL

I use SBCL as my Common Lisp implementation of choice. Source code and binaries can be found here.

I usually prefer to install the latest version instead of relying on my distro's current version (although I use Debian Sid). Relevant quote from StumpWM's GitHub page (a Common Lisp window manager that we will install below):

Please do not install SBCL using your distributions package manager, especially Ubuntu. If you do so it is likely that you'll run into problems when building StumpWM due to using obsolete versions of the dependencies.

As of [2026-03-08 Sun], we will download SBCL v2.6.2. I prefer to install SBCL in ~/bin and to create a symlink (~/bin is in my PATH). From the directory in which you downloaded the tarball:

tar xavf sbcl-2.6.2-x86-64-linux-binary.tar.bz2
cd sbcl-2.6.2-x86-64-linux
mkdir ~/bin/sbcl-2.6.2
INSTALL_ROOT=/home/alc/bin/sbcl-2.6.2 sh install.sh
ln -s ~/bin/sbcl-2.6.2/bin/sbcl ~/bin/sbcl

Adapt this to your own needs, of course. Test the install:

sbcl --version
SBCL 2.6.2

Sly

With just SBCL and Emacs as an IDE, you can already start hacking in Common Lisp.

I personally use Sly, but SLIME is another option. Here's how I install it in Emacs with use-package – you will find this code in my Emacs configuration here:

(use-package sly
  ;; Sylvester the Cat's Common Lisp IDE.
  ;; https://github.com/joaotavora/sly
  :ensure t
  :config
  (setq inferior-lisp-program "sbcl"
        org-babel-lisp-eval-fn #'sly-eval))

You can also using the package manager directly:

M-x package-install RET sly RET

However, don't forget to set your default Lisp by evaluating this expression:

(setq inferior-lisp-program "sbcl")

Launch it with M-x sly and start exploring! Sly will run SBCL for you and connect to the Lisp image. To quit, you can type , and choose the sayoonara command.

ASDF

Another System Definition Facility. ASDF is bundled with SBCL.

In this section we will simply register our ASDF systems. You can use any directory you want for this; I'll use ~/src/ below. These instructions are documented here, as of [2026-03-08 Sun].

  1. Create the configuration directory for ASDF.

    mkdir ~/.config/common-lisp/source-registry.conf.d/
    
  2. Create a .conf file – I use my-asdf.conf. In this file, add a line like this one:

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

    You should find this file in my dotfiles.

    This will tell ASDF to recursively scan this directory looking for .asd files. Of course choose your own dir 🙂

  3. We will test things by creating a typical ASDF system in the directory you used above:

    mkdir my-asdf-test
    

    Then create these 2 files:

    ;; my-asdf-test.asd (system definition)
    
    (asdf:defsystem #:my-asdf-test
      :serial t
      :components ((:file "my-asdf-test")))
    
    ;; my-asdf-test.lisp (package + a small function)
    
    (defpackage #:my-asdf-test
      (:use #:cl))
    
    (in-package :my-asdf-test)
    
    (defun main ()
      (write-line "Hello, world"))
    
  4. Here's a Sly session that shows that ASDF can detect the system:

    CL-USER> (asdf:load-system :my-asdf-test)
    ; compiling file "/home/alc/src/my-asdf-test/my-asdf-test.lisp" (written 08 MAR 2026 05:20:57 PM):
    ; wrote /home/alc/.cache/common-lisp/sbcl-2.6.2-linux-x64/home/alc/src/my-asdf-test/my-asdf-test-tmpGHU3ALSV.fasl
    ; compilation finished in 0:00:00.008
    T
    CL-USER> (in-package :my-asdf-test)
    #<PACKAGE "MY-ASDF-TEST">
    MY-ASDF-TEST> (main)
    Hello, world
    "Hello, world"
    

Quicklisp

Quicklisp is a library manager for Common Lisp. If you need a dependency for your project, it's a good place to start.

Slow version

  1. Download the install script.

    wget https://beta.quicklisp.org/quicklisp.lisp
    
  2. Run SBCL and load the Lisp file.

    sbcl --load quicklisp.lisp
    
  3. Install Quicklisp. I prefer to install it in ~/.quicklisp, install it wherever you want.

    (quicklisp-quickstart:install :path ".quicklisp/")
    
  4. Notify SBCL about Quicklisp. Add this to your .sbclrc file:

    #-quicklisp
    (let ((quicklisp-init (merge-pathnames ".quicklisp/setup.lisp"
                                           (user-homedir-pathname))))
      (when (probe-file quicklisp-init)
        (load quicklisp-init)))
    

Fast version

curl -o /tmp/ql.lisp http://beta.quicklisp.org/quicklisp.lisp
sbcl --no-sysinit --no-userinit --load /tmp/ql.lisp \
     --eval '(quicklisp-quickstart:install :path "~/.quicklisp")' \
     --eval '(ql:add-to-init-file)' \
     --quit

Optional

Run Sly in Emacs and download a package. Here's a Sly session you can reproduce:

;
;  ( \
;   \ \
;   / /                |\\
;  / /     .-`````-.   / ^`-.
;  \ \    /         \_/  {|} `o
;   \ \  /   .---.   \\ _  ,--'
;    \ \/   /     \,  \( `^^^   Take this REPL, brother, and may it serve you well.
;     \   \/\      (\  )
;      \   ) \     ) \ \
;       ) /__ \__  ) (\ \___
;      (___)))__))(__))(__)))
;
; Dedicated output stream setup (port 45563)
; Redirecting all output to this MREPL
; SLY NIL (#<MREPL mrepl-1-1>)
CL-USER> (ql:quickload "alexandria")
To load "alexandria":
  Load 1 ASDF system:
    asdf
  Install 1 Quicklisp release:
    alexandria
; Fetching #<URL "http://beta.quicklisp.org/archive/alexandria/2024-10-12/alexandria-20241012-git.tgz">
; 55.94KB
==================================================
57,281 bytes in 0.02 seconds (2796.92KB/sec)
; Loading "alexandria"
[package alexandria]..............................
[package alexandria-2]
("alexandria")
CL-USER> (alexandria:clamp 150 0 100)
100 (7 bits, #x64, #o144, #b1100100)

(clamp clamps a number value into [min, max] range. See Alexandria's documentation.)

Since Quicklisp and ASDF work together, you can also load your own ASDF systems with ql:quickload instead of what we did above with asdf:load-system. Note that you can put your ASDF systems in ~/.quicklisp/local-projects.

Quickproject

Quickproject is pretty neat for creating a Common Lisp project from scratch. We will use it to create another small test project, but faster this time. The project we create here will also be compiled in the next section.

  1. Using Sly, create a project in the source directory you selected earlier:

    (ql:quickload :quickproject)
    (quickproject:make-project #p"~/src/my-quickproject-test/")
    
  2. In my-quickproject-test.lisp, add this main function after the in-package declaration:

    (defun main (argv)
      (format t "Hello, ~A~%" (second argv)))
    
  3. Load the project:

    (ql:quickload :my-quickproject-test)
    

If it loads, perfect – go to the next section 🙂

Compilation

Buildapp is pretty cool.

  1. Install it.

    (ql:quickload :buildapp)
    
  2. Build buildapp itself.

    (buildapp:build-buildapp)
    

    Important: the binary will be created in the current directory, so move it somewhere useful (I'll use ~/bin as it's in my PATH).

  3. We'll now build my-quickproject-test!

    ~/bin/buildapp --output my-quickproject-test \
                   --load-system my-quickproject-test \
                   --entry my-quickproject-test:main
    
  4. Run the program with an argument:

    ❯ ./my-quickproject-test "World"
    Hello, World
    

StumpWM

StumpWM is a fantastic window manager written and configurable in Common Lisp. We will build it from source.

You can also check this page on ArchWiki.

  1. Clone the StumpWM repository:

    git clone https://github.com/stumpwm/stumpwm
    
  2. Install the dependencies in SBCL/Sly:

    (ql:quickload '("clx" "cl-ppcre" "alexandria"))
    
  3. Compile it:

    ./autogen.sh
    ./configure
    make
    
  4. I prefer to link to the executable instead of using make install:

    ln -s ~/src/stumpwm/stumpwm ~/bin/stumpwm
    
  5. I start StumpWM with:

    WM=stumpwm startx
    

    Here's the corresponding ~/.xinitrc file; adapt it to your own needs (I also use i3):

    #!/bin/sh
    
    WM="${WM:-i3}"
    
    case "$WM" in
      stumpwm)
        xrandr --dpi 96
        export SBCL_HOME=/home/alc/bin/sbcl-2.6.2/lib/sbcl
        exec "$HOME/bin/stumpwm"
        ;;
      i3)
        xrandr --dpi 96
        exec i3
        ;;
      *)
        echo "Unknown WM: $WM"
        exit 1
        ;;
    esac
    

    Notice the SBCL_HOME export, it's important! The cause is here.

  6. Run WM=stumpwm startx: it should work.

Optional: Slynk

You can connect to the Lisp image used by StumpWM from Sly and interact with the window manager live using a Slynk server (no need to restart your window manager, you're in the Lisp world).

Check my config here, that's what I do.

  1. Add this to your StumpWM init.lisp:

    (in-package #:stumpwm)
    
    (ql:quickload '(:alexandria :slynk :local-time) :silent t)
    
    (defvar *slynk-server* nil)
    
    (defcommand slynk-start () ()
      (unless *slynk-server*
        (setf *slynk-server* (slynk:create-server :port 4006 :dont-close t)))
      (message "Slynk server started."))
    
    (defcommand slynk-stop () ()
      (when *slynk-server*
        (slynk:stop-server *slynk-server*)
        (setf *slynk-server* nil)
        (message "Slynk server stopped.")))
    
  2. From StumpWM, run the slynk-start command.
  3. Then from Emacs, run M-x sly-connect and connect to http://localhost:4006. You should be able to communicate with StumpWM! Try it:

    CL-USER> (stumpwm:message "hello")
    

    The message should appear on the screen. How cool is that?

Optional: ttf-fonts

If you want to use the ttf-fonts module from StumpWM's contrib repository, you will need clx-truetype, which is not in Quicklisp anymore. Here's how to fix that:

  1. Clone a version of it in ~/.quicklisp/local-projects.

    I used this one.

  2. Run (ql:quickload "clx-truetype") once so dependencies are fetched (you can also include this line of code in your config).
  3. It should work. I personally use Jetbrains Mono:

    (load-module "ttf-fonts")
    (xft:cache-fonts)
    (set-font (make-instance 'xft:font
                             :family "JetBrains Mono"
                             :subfamily "Regular"
                             :size 12
                             :antialias t))
    

Other tools

Also check:

Footnotes:

1

This article was originally written around 2020 and was updated in 2026.