Lambdaカクテル

ソフトウェア開発者です.玉石混淆です.

Common LISP環境構築メモ(SBCL, Quicklisp, ASDF2, SLIME)

備忘録として.

Common LISPは実用的とよく言われるが触ったことがなかったので,学習してみようと思った. 今回は環境構築をやる.

追記

  • 2017/04/07 Roswellについて追記

目次

処理系インストール

処理系がなければお話にならないので,インストールした.

CLには様々な処理系が存在するようだが,ここはデファクトスタンダードを選びたい. ひとまずSBCL(Steel Bank Common Lisp system)という処理系を採用する.以下記事によれば多く使われているようだし,なにより無料だ. 今時の感覚では言語は無料で入手できるという感じだが,もちろんそれは最近になってからの話だ.無料でソフトウェアが使えることは幸せなことだ.

qiita.com

brewが使えるようなのでインストールした.

$ brew info sbcl
sbcl: stable 1.3.16 (bottled), HEAD
Steel Bank Common Lisp system
http://www.sbcl.org/
Not installed
From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/sbcl.rb
==> Options
--with-internal-xref
        Include XREF information for SBCL internals (increases core size by 5-6MB)
--without-core-compression
        Build SBCL without support for compressed cores and without a dependency on zlib
--without-ldb
        Don't include low-level debugger
--without-sources
        Don't install SBCL sources
--without-threads
        Build SBCL without support for native threads
--HEAD
        Install HEAD version

インストールする.

$ brew install sbcl
==> Downloading https://homebrew.bintray.com/bottles/sbcl-1.3.16.sierra.bottle.tar.gz
######################################################################## 100.0%
==> Pouring sbcl-1.3.16.sierra.bottle.tar.gz
🍺  /usr/local/Cellar/sbcl/1.3.16: 1,324 files, 73.6MB

Hello, World

さっそくHello, Worldしてみる.

$ sbcl
This is SBCL 1.3.16, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.

SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses.  See the CREDITS and COPYING files in the
distribution for more information.
* (format t "Hello, Common LISP World!")
Hello, Common LISP World!
NIL
*

さっそくformat関数を使った.けっこう複雑そうな関数だ.

インストールしてから思ったのだが,*env系の処理系管理ツールなどはあるのだろうか. 調べてみると,最近ではRoswellというのがCLにおける処理系管理ツールらしい.あとで調べておこう.

blog.8arrow.org

Quicklisp(ライブラリマネージャ)

処理系がインストールできたので,ライブラリマネージャーを導入する.perlにおけるcpanmのようなやつだ. 今回は以下の記事を参考にした.

modern-cl.blogspot.jp

連載になっていて,これらの記事に従えば環境構築ができるようだ.ここからしばらくこのサイトに従って導入を行っていく.

CLのライブラリ管理手法は幾つもあり,それぞれ欠点や利点があるようだが,Quicklispが最もモダンな環境だという印象を受けた.

ダウンロード

前掲の記事通りに進める.まずはQuicklispをダウンロードする.

指示に従いhttp://beta.quicklisp.org/quicklisp.lispに行くと,いきなりlispファイルが降ってきた.これを処理系のどこかのディレクトリに配置すればいいのだろうか.困った.(後で分かったことだが,これはただのインストーラだということが分かった.)

Quicklispの公式サイトを紐解く.

To install Quicklisp, download quicklisp.lisp and load it.

ふーん・・・CLはそういう世界観なのか・・・ひとまずホームディレクトリにclディレクトリを作成して,その中に保存することにした.PGP署名と鍵も提供されていたので,ついでに検証する.接続もSSLで,結構しっかりしている印象だ.

$ mkdir ~/cl/
$ cd ~/cl/
$ wget https://beta.quicklisp.org/quicklisp.lisp        # main script
$ wget https://beta.quicklisp.org/quicklisp.lisp.asc # detached signature
$ wget https://beta.quicklisp.org/release-key.txt     # signing key
$ gpg --version
gpg (GnuPG/MacGPG2) 2.0.30
libgcrypt 1.7.0
...
$ gpg --with-fingerprint release-key.txt
# (鍵の指紋が公式サイトに記載されているものと同一であることを*必ず*確認する)
pub  4096R/028B5FF7 2014-01-19
      Key fingerprint = D7A3 489D DEFE 32B7 D0E7  CC61 3079 65AB 028B 5FF7
uid                            Quicklisp Release Signing Key <release@quicklisp.org>
sub  4096R/E456CAE9 2014-01-19
$ gpg --import release-key.txt
$ gpg --verify quicklisp.lisp.asc
gpg: assuming signed data in 'quicklisp.lisp'
gpg: Signature made 木  1/29 06:13:26 2015 JST using RSA key ID 028B5FF7
gpg: Good signature from "Quicklisp Release Signing Key <release@quicklisp.org>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: D7A3 489D DEFE 32B7 D0E7  CC61 3079 65AB 028B 5FF7

指紋も公式サイトのものと合致し,署名も有効なものだと確認できた.鍵を信用していないことによる警告が表示されているが,今回は署名が有効であれば良しとする*1

蛇足

これは完全に余談だが,せっかくなので話しておく.先日訳あってプリンタのドライバをメーカのサイトから拾ってきてインストールした.ところがそのドライバがHTTPで雑に配布されていて,これには面食らった.弱小メーカというわけでもなく,名だたる有名某国産メーカのサイトが,攻撃が容易なHTTPでドライバを配っている.そんなんでいいのか.ドライバはシステムの根幹に関わるし,しかもプリンタは印刷物を預かる存在だ.偽のドライバをインストールさせて情報を盗もうと思えばたやすいだろう.改めてセキュリティについて思いを馳せたのであった.

セットアップ

インストールが完了したので,Quicklispがライブラリを保管するディレクトリをQuicklisp自身に作成させる.

今回は~/.quicklispにライブラリを保管する.つまりプロジェクトごとではなくユーザごとの保管だ.

先ほど作成したcl ディレクトリでSBCLを起動し前掲の記事通りの操作を行う.ただし,パスは変更している(clディレクトリにquicklisp.lispを保存し,今clディレクトリに居るので,ライブラリの保管先である.quicklisp/~/.quicklisp/と書き換えている).

* (load "quicklisp.lisp")

  ==== quicklisp quickstart 2015-01-28 loaded ====

    To continue with installation, evaluate: (quicklisp-quickstart:install)

    For installation options, evaluate: (quicklisp-quickstart:help)

T
* (quicklisp-quickstart:install :path "~/.quicklisp/")

; Fetching #<URL "http://beta.quicklisp.org/client/quicklisp.sexp">
; 0.82KB
==================================================
838 bytes in 0.00 seconds (818.36KB/sec)
; Fetching #<URL "http://beta.quicklisp.org/client/2017-03-06/quicklisp.tar">
; 250.00KB
==================================================
256,000 bytes in 0.46 seconds (549.45KB/sec)
; Fetching #<URL "http://beta.quicklisp.org/client/2015-09-24/setup.lisp">
; 4.94KB
==================================================
5,054 bytes in 0.00 seconds (4935.55KB/sec)
; Fetching #<URL "http://beta.quicklisp.org/asdf/2.26/asdf.lisp">
; 194.07KB
==================================================
198,729 bytes in 0.34 seconds (579.32KB/sec)
; Fetching #<URL "http://beta.quicklisp.org/dist/quicklisp.txt">
; 0.40KB
==================================================
408 bytes in 0.00 seconds (199.22KB/sec)
Installing dist "quicklisp" version "2017-04-03".
; Fetching #<URL "http://beta.quicklisp.org/dist/quicklisp/2017-04-03/releases.txt">
; 358.24KB
==================================================
366,838 bytes in 0.91 seconds (395.41KB/sec)
; Fetching #<URL "http://beta.quicklisp.org/dist/quicklisp/2017-04-03/systems.txt">
; 253.71KB
==================================================
259,794 bytes in 0.42 seconds (601.20KB/sec)

  ==== quicklisp installed ====

    To load a system, use: (ql:quickload "system-name")

    To find systems, use: (ql:system-apropos "term")

    To load Quicklisp every time you start Lisp, use: (ql:add-to-init-file)

    For more information, see http://www.quicklisp.org/beta/

NIL
* (ql:add-to-init-file)
I will append the following lines to #P"/Users/qwilas/.sbclrc":

  ;;; The following lines added by ql:add-to-init-file:
  #-quicklisp
  (let ((quicklisp-init (merge-pathnames ".quicklisp/setup.lisp"
                                         (user-homedir-pathname))))
    (when (probe-file quicklisp-init)
      (load quicklisp-init)))

Press Enter to continue.
; [ENTER]を押下する

#P"/Users/qwilas/.sbclrc"

これでSBCL起動時に自動的にQuicklispが使えるようになった.clディレクトリを削除してもかまわない.

$ cd ~/
$ rm -rf cl/

ライブラリを検索する

ql:system-aproposを使う.

* (ql:system-apropos "web")
#<SYSTEM bknr.modules / bknr-web-20140713-git / quicklisp 2017-04-03>
#<SYSTEM bknr.web / bknr-web-20140713-git / quicklisp 2017-04-03>
#<SYSTEM cl-soup / cl-webkit-20160208-git / quicklisp 2017-04-03>
#<SYSTEM cl-webdav / cl-webdav-0.2.1 / quicklisp 2017-04-03>
... ライブラリが表示される ...
*

ライブラリをインストールする

ql:quickloadを使う.試しにperl5互換の正規表現ライブラリ cl-ppcreをインストールする.

* (ql:quickload :cl-ppcre)
To load "cl-ppcre":
  Install 1 Quicklisp release:
    cl-ppcre
; Fetching #<URL "http://beta.quicklisp.org/archive/cl-ppcre/2015-09-23/cl-ppcre-2.0.11.tgz">
; 156.08KB
==================================================
159,829 bytes in 0.22 seconds (699.92KB/sec)
; Loading "cl-ppcre"
[package cl-ppcre]................................
................
(:CL-PPCRE)
*

同時にロードも行われる.試しに使ってみる.

* (ppcre:scan-to-strings "\\d+" "I have 10000 yen")

"10000"
#()
*

CLのエスケープ文字と正規表現のエスケープ文字が競合するため,バックスラッシュを二重に書かなければならないことが分かった.

ASDF2(ライブラリマネージャ)

ふざけた名前だが,これもライブラリマネージャだ.Quicklispは定期的に更新されるライブラリの名簿を使ってライブラリをインストールする. ASDF2はより自由で,Quicklispに登録されていない自作のローカルライブラリをインストールさせることができる.また大抵処理系に標準でインストールされているため,特段の操作は必要ない.

セットアップ

ASDF2がライブラリを保管する場所だけ決める必要がある.今回は~/.cl/systemsを使うことにした.

$ mkdir -p ~/.cl/systems

このディレクトリを使わせるべく設定ファイルに書き込む.設定は~/.config/common-lisp/source-registry.conf.d/01-add-local-lisp.confで行う. ディレクトリは必要に応じて作成する.

(:tree (:home ".cl/systems"))

SLIME

さて,今度はCLをEmacsで書けるようにする.SLIMEというIDE的なやつを用意する. 今回も前掲のサイトにおおむね従う.

modern-cl.blogspot.jp

今回は手動でelispをダウンロードせず,elispパッケージマネージャel-getパッケージの力を借りてインストールする. el-getをインストールしていないなら,便利なのでインストールすることをお勧めする.

tarao.hatenablog.com

(require 'el-get)
(el-get-bundle slime)

ここでエラーが出てしまった.

makeinfo slime.texi
slime.texi:6: warning: unrecognized encoding name `UTF-8'.
slime.texi:6: Unknown command `codequoteundirected'.
slime.texi:7: Unknown command `codequotebacktick'.

同じようなエラーが報告されていた.texinfoをきちんとインストールする必要があるようだ.https://github.com/xiaohanyu/oh-my-emacs/issues/85を参考に最新のtexinfoをインストールする.

$ brew install texinfo
$ brew link --force texinfo
$ echo 'export PATH="/usr/local/opt/texinfo/bin:$PATH"' >> ~/.zshrc
$ echo 'export PATH="/usr/local/opt/texinfo/bin:$PATH"' >> ~/.bashrc

emacsが開くプロセスのために環境変数を書き換えて,再度インストールする.

(setenv
 "PATH"
 (concat "/usr/local/opt/texinfo/bin" ":" (getenv "PATH")))

(el-get-bundle slime)

これでようやくインストールできた.

SLIMEの続きはまた次回に.

*1:鍵を信頼する手順として使えるのは,直接会う程度しかない