Vine Linux 5.x, 6.0で Steel Bank Common Lisp (以下 sbcl) を使ってみる。
sbcl のコンパイルには Common Lisp, 特に sbcl 自身もしくは cmucl, あるいは OpenMCL や clisp などが必要。 Vine 5.0 では clisp を一旦インストールしておいて、それを使ってコンパイルできる。 ただし、一度まともに動く sbcl がインストールできたなら、それを使ってコンパイルする方が速い。本家に置いてあるバイナリを一度インストールするのも一つの手。 Vine 4.2 の頃は 本家のバイナリは, glibc が NPTL をサポートしていないと言われて実行できなかったが、5.0 以降では大丈夫。
コンパイルの際には sbcl 1.0.34 からはデフォルトで thread が有効になっているが、それ以前のバージョンではそうではないので、たとえば Web Server の hunchentoot などが使えない。その場合はソースを展開したディレクトリで
base-target-features.lisp-expr
の :sb-thread のコメントをはずしてからコンパイル。
なお sbcl-1.0.47 で clsql を使う場合は、clsql-5.3.0 以降でないと load できない。
いろいろなライブラリを良く使うようになると, それをロードするのにも時間がかかるので, ロードしたイメージを core ファイルに保存しておいて, それを利用する方がいちいちライブラリを読み込む手間も省けて便利である。 作った core を, たとえば main.core という名前で ~/.sbcl というディレクトリに 保存したとすると,
sbcl --noinform --core ~/.sbcl/main.coreのようにして sbcl を起動すると, そのコアを読み込んで起動する。
sbcl で core ファイルを作るには,
(save-lisp-and-die
(merge-pathnames ".sbcl/main.core" (user-homedir-pathname))
:purify t)
のように save-lisp-and-die を使う。(sbcl 特有)
私はLISPUSERというサイトにあったものを参考にした (というかほぼ丸写しに近い) 次のスクリプトを使っている。
sbcl-core.sh
補足。cliki にも書かれているように、uffi の代わりに cffi-uffi-compat を使う方が良いみたい。
ついでの補足だが、clsql の asdf パッケージをそのまま asdf-install でインストールしようとすると、ライブラリがないなどといろいろ文句を言われるので、これだけは手でインストールした。つまり .sbcl/site/ 以下に clsql の asdf パッケージを展開して、その中にある asd ファイルの内、実際に使う
clsql.asd
clsql-cffi.asd
clsql-uffi.asd
clsql-sqlite3.asd
.sbcl/system/ 以下にシンボリックリンクした。
個人の sbcl の設定は主に .sbclrc を利用する。
Vine Linux は 5.0 から、システムの文字コードが utf-8 になった。 4.2 の頃までは euc-jp だったので、utf-8 で書いたファイルを load するときには
(load "nantoka.lisp" :external-format :utf-8)みたいにしないといけなかった。また、slime で C-c C-kで バッファのファイルをコンパイルしてロードするときも読んでくれない。 そこで、
.sbclrcに
(setf sb-impl::*default-external-format* :utf-8) (setf sb-alien::*default-c-string-external-format* :utf-8)と書いておくと、一々指定せずにすむようになる。
asdf によるパッケージを利用するために,
最初に(require :asdf)と書く。
sbcl をバージョンアップしたりすると, コンパイルしなおさないといけないが, 次のように書いておくと, 起動時に必要なら再コンパイルしてくれる。 sbcl は活発に開発されているので、かなり便利。
(defmethod asdf:perform :around ((o asdf:load-op) (c asdf:cl-source-file))
(handler-case (call-next-method o c)
(#+sbcl sb-ext:invalid-fasl
#+allegro excl::file-incompatible-fasl-error
#+lispworks conditions:fasl-error
#+cmu ext:invalid-fasl
#-(or sbcl allegro lispworks cmu) error ()
(asdf:perform (make-instance 'asdf:compile-op) c)
(call-next-method))))
sbcl 1.0.22 から起動オプションに --script が加わり、例えば
#!/usr/bin/sbcl --script (write-line "Hello, World!")と書くことで、sbcl をスクリプトに利用することができるようになった。 それ以前のバージョンでは以下のような設定が必要になる。
unix で良く使われる一行目が #! で始まるスクリプトで sbcl を
利用する際, sbcl はそのままではうまく処理してくれない。
しかし, .sbclrc
に次のように書いておけばしてくれるようになる。
(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 script)
(quit)))
これで, 例えば,
#!/usr/bin/sbcl --noinform (write-line "Hello, World!")という内容のファイルを hello.lisp という名前で保存しておけば,
$ ./hello.lisp Hello, World!と表示される。
プロンプトのカスタマイズ例。ネットで見つけたもの。 自分がどのパッケージにいるかわかるようになる。
(defvar *last-package* nil)
(defvar *cached-prompt* nil)
(defun package-prompt (stream)
(unless (eq *last-package* *package*)
(setf *cached-prompt*
(concatenate 'string (or (first (package-nicknames *package*))
(package-name *package*))
"> "))
(setf *last-package* *package*))
(terpri)
(princ *cached-prompt* stream))
(setf sb-int:*repl-prompt-fun* #'package-prompt)