Common Lisp: How to get (in-package ...) to work from within Emacs Slime

1.8k views Asked by At

64-bit Windows 7
Clozure Common Lisp Version 1.9 WindowsX8632
Emacs 24.3.1
Slime changelog date 2014-06-17

I have an example .lisp file which starts out as follows:

(ql:quickload 'qt)
(in-package "QT")

The rest of the program shows a dialog box. When I run this from the command line, wx86cl -load helloqt.lisp it seems to work fine. When I run this from Emacs Slime (C-x C-k) it says there is no package "QT". However if I first evaluate the first line individually (C-x C-e) then I can compile the whole thing and it works, modulo the normal issues of trying to run a QT thread from within Slime on Windows.

How do I make it so I can compile/run the file from emacs without having to manually evaluate the first line first?

Also, why doesn't (in-package ...) change the current package in the Slime session? I have to change it manually if I want to interact with the package contents.

2

There are 2 answers

0
Svante On BEST ANSWER

When you compile the file as a whole, it is first read as a whole. At that time, none of it has yet been evaluated, so the package QT is not defined yet.

You can either use eval-when to evaluate something at an earlier time, or use a system definition facility (ASDF is predominant nowadays) to load your system in the right order.

Eval-when:

(eval-when (:compile-toplevel :load-toplevel :execute)
  (ql:quickload '#:qt))

(in-package #:qt)

Note that you usually should not muck around in library packages but define your own, fresh package to hold your code:

(eval-when (:compile-toplevel :load-toplevel :execute)
  (ql:quickload '#:qt))

(defpackage #:qt-example
  (:use #:qt))

(in-package #:qt-example)

;; your code here

(In case you are wondering, defpackage, defun, defclass etc. are specially designed macros that expand to a form inside such an eval-when.)

This is sometimes OK for little one-off scripts. For systems of any noteworthy size, especially as soon as they have more than one source file, use ASDF:

;;;; qt-example.asd

(in-package #:cl-user)

(asdf:defsystem #:qt-experiments
  :description "Some experiments with QT."
  :serial t
  :components ((:file "package")
               (:file "qt-example"))
  :depends-on (#:qt))

;;;; package.lisp

(defpackage #:qt-example
  (:use #:qt))

;;;; qt-example.lisp

(in-package #:qt-example)

ASDF comes with most open-source Common Lisp implementations. You might need to set up the ASDF registry. I like to have one or two base directories for all my local projects, so that I can just put the following into ~/.config/common-lisp/source-registry.conf:

(:source-registry
  (:tree (:home "devel"))
  (:tree (:home "src"))
  :inherit-configuration)

Then ASDF finds all systems defined below those directories. In SLIME, you can just use ,load-system or ,open-system from the REPL with the system name to load it, resp. open all files in it, optionally loading it.

When compiling a single toplevel form (using C-c C-c) from a file, SLIME looks backward from there for an in-package form to find out what package it should assume. Conventionally, you should only have a single in-package form per file, at its top.

A commonly useful shortcut is C-c ~ in Lisp source files, which switches the REPL to the directory of the file and the effective package at point.

0
ealfonso On

A little hard to find, but there is slime-repl-set-package:

(defun slime-connected-hook-switch-to-stumpwm-package ()
  (slime-repl-set-package "STUMPWM"))

(add-hook #'slime-editing-mode-hook
          #'slime-connected-hook-switch-to-stumpwm-package)