在Debian上使用SLIME在Common Lisp中加载外部包

时间:2012-05-11 00:30:34

标签: debian common-lisp packages slime sbcl

我正在使用SBCL 1.0.56进行Debian挤压,使用cl-swank / slime 1:20120420-2(Debian版本号)。这些都是当前的 不稳定版本。

我在加载第三方CL软件包时遇到了问题。该 在Debian上使用CL的文档(实际上是更一般的CL Linux上的使用文档是粗略的,矛盾的,和 已经过时了,所以我会总结一下我所知道的。我就在这里。

Debian在中安装二进制包(例如,cl-split-sequence) /usr/share/common-lisp/source。在分裂序列的情况下,这是 /usr/share/common-lisp/source/cl-split-sequence

.asd文件(此处 /usr/share/common-lisp/source/cl-split-sequence/split-sequence.asd), 据我所知,它给出了CL实现的说明 关于版本和依赖关系,看起来像

;;; -*- Lisp -*- mode
(defpackage #:split-sequence-system (:use #:cl #:asdf))
(in-package :split-sequence-system)

(defsystem :split-sequence
    :version "20011114.1"
    :components ((:file "split-sequence")))

现在,当运行粘液时,在REPL处输入以下两行 工作没有问题

(require :split-sequence)
(split-sequence:SPLIT-SEQUENCE  #\, "foo,bar")

(require :split-sequence)调用(我认为)内置副本 SBCL内的ASDF,大概是split-sequence.asd。这个 可能是特定于SBCL的,请参阅Common Lisp in Debian Manual Chapter 3 -Libraries。 值得注意的是,这个页面,有用和详细 我遇到的任何事情都经常提到CLC(Common Lisp Controller),但似乎Debian正在逐渐远离这一点。看到 Redesign of Common Lisp Controller, 我不完全明白。无论如何,没有记录在案 使用CLC的命令对我有用。但是,CLC仍然可用 在Debian上。此外,用户邮件列表已经死亡 - 请参阅The Clc-users Archives

第一次调用(require :split-sequence)时,它被编译, 和(在我的系统上,可能是Debian特定的)生成的fasl是 放在

~/.cache/common-lisp/sbcl-1.0.56.0.debian-linux-x86/usr/share/common-lisp/source/cl-split-sequence/split-sequence.fasl

即。该文件放在缓存在镜像的文件系统中 原始来源的位置。显而易见的问题是,如何 系统知道在哪里寻找包裹?这是我不是的一件事 肯定。看起来应该给出搜索路径 /etc/common-lisp/source-registry.conf.d,是ASDF的一部分 Debian包,但最接近的是 01-common-lisp-controller.conf,这只是

(:directory  #p"/usr/share/common-lisp/systems/")

也许这在某个地方是硬连线的,但我想知道。

无论如何,一旦这个ASDF文件在缓存中,就不会再次编译, 但除非有人这样​​做,否则REPL在粘液启动后不会看到它 再次require

现在,如果我把行

(require :split-sequence)
(split-sequence:SPLIT-SEQUENCE  #\, "foo,bar")

在一个文件中,说seq.lisp,并用C-c C-k将其加载到REPL中,我得到 错误和回溯,以

开头
The name "SPLIT-SEQUENCE" does not designate any package.
   [Condition of type SB-KERNEL:SIMPLE-PACKAGE-ERROR]

所以我得出结论,包没有正确加载。我试过像

这样的变化
(asdf:oos 'asdf:load-op :split-sequence)

(asdf:load-system :split-sequence)

但没有骰子。奇怪的是,假设我们只有行

(require :split-sequence)

在文件中 - 为了清楚起见,请调用此require.lisp。然后加载 require.lisp不会出错,然后输入

(split-sequence:SPLIT-SEQUENCE  #\, "foo,bar")

在REPL工作!但是,如果没有加载require.lisp,请键入 前一行在REPL中不起作用。

因此,总之,如何成功地加载一个包 脚本?我也对上面提到的问题很感兴趣 ASDF如何找到/usr/share/common-lisp/source/位置,但是 这是一个侧面问题。

2 个答案:

答案 0 :(得分:4)

C-c C-k 编译源文件,然后加载编译后的文件。

Lisp源文件包含定义和调用。文件编译器遍历文件并为其创建代码。但它没有执行它。

如果您的文件包含对REQUIRE的调用,则在编译期间不会执行该调用。如果稍后加载已编译的文件,它将被执行。如果文件中的下一个Lisp表单正在使用一些在调用REQUIRE之后可用的包,那么在编译期间它就不存在了,因为REQUIRE尚未执行 - 因此编译时读取时出错。

基本上有两种解决方案:

  • 在使用所需功能编译特定文件之前执行所有必需的REQUIRE操作。
  • 在编译期间执行REQUIRE语句。这就是EVAL-WHEN :COMPILE-TOPLEVEL告诉编译在编译期间执行子表单的地方。

#+:sbcl(foo)表示只有:SBCL是列表CL:*FEATURES*中的符号时,才会读取(foo)。它被使用,以便编译器仅在SBCL时才能看到此代码。

Common Lisp代码的编译需要更加谨慎,因为:

  • 可以在文件编译期间执行Lisp代码,从而改变文件编译器的行为。

  • 源代码中使用的包(它们是符号的名称空间)需要为文件编译器的读者所知。

答案 1 :(得分:1)

我发现了以下帖子Zach Beane's Blog - Making a small Common Lisp project,其中包含指向http://common-lisp.net/~loliveira/ediware/ediware.lisp的链接

复制该文件顶部的代码有效。因此,在此文件的slime中运行C-c C-k会加载split-sequence,并运行代码int (split-sequence:SPLIT-SEQUENCE #\, "foo,bar"))

#+:sbcl
(eval-when (:compile-toplevel :load-toplevel :execute)
  (require :asdf))

(eval-when (:compile-toplevel :load-toplevel :execute)
  (asdf:oos 'asdf:load-op :split-sequence))

(defpackage #:seq
  (:use #:cl #:split-sequence))
(in-package #:seq)

(print (split-sequence:SPLIT-SEQUENCE  #\, "foo,bar"))

然而,我不知道这些神奇的咒语是做什么的。有人愿意解释,或许在另一个答案?我把它放在一个答案中,因为它是问题的答案,但它并不完整,因为我不明白为什么它有效。我很乐意接受对这个剧本的解释。