Lispのパッケージ管理入門.Quicklisp,ASDF,Roswellの違いなど

Lispを始めたばかりで,まだ規模の大きいプログラムを書いていないため,パッケージ管理やらライブラリの依存関係解決などわからないことだらけで,QuicklispASDFCIMRoswell等,色々調べました.包括的かつ初心者に優しいリソースがなく,最初は苦労しました.解説がどれも各ツールの使い方に特化していて,他のツールの関係や,どのツールが必要で,どの機能が重複しているかなどの解説がなかったからです.色々読んでいるうちに朧げながら全体像が掴めてきました.ここでは私の朧げな解釈を下に,それぞれのツールの大まかな機能と役割について説明したいと思います.間違いなどありましたら,@waterloo_jpまでお願いします.(CIMは実際に使ってないので解説してません.ゴメンナサイ)

Quicklisp, ASDF, Roswell 違いは何?

他人の書いたパッケージを利用する場合,1.インストールし,2.プログラムをロードする必要があります.インストールをしてくれるのがQuicklisp,依存関係を解決しロードしてくれるのがASDFと理解して良いと思います.

それではRoswellは何かと言うと,Quicklispのようなインストーラです.Quicklispとの違いは,ライブラリだけでなくLisp処理系のインストールもできる点です.RoswellでインストールされたLisp処理系を使うと,Roswellでインストールしたライブラリを何の設定もなしにrequireでロードできます.したがって,RoswellさえあればQuicklispは必要ありません.また,Roswellでインストールした処理系とライブラリは,単一のディレクトリ以下に配置されるので,既存の開発環境と共存できます.

Roswellは処理系やライブラリのインストールだけでなく,作成したプログラムをコンパイルし,バイナリファイルにパッケージングもしてくれます.したがって,Roswellがあれば,開発からデプロイメントまで一貫して行うことができます.

以下,それぞれのツールについて説明します.

ASDF

ASDFは,ローカルに存在するライブラリを,依存関係に基づいてロードします.実際には,ロードする前にコンパイルまで行ってくれます.依存関係を定義するファイルは.asdファイルで,通常プロジェクトトップに置かれます.

Lisp標準のrequire関数で外部ファイルをロードする際,ほとんどの処理系がASDFを用いてファイルをロードするため,ASDF自体はLisp標準規格に含まれませんが,処理系と共に予めインストールされていることが多いです.

ASDFをCの開発ツールに喩えるとmakeとリンカとローダを合わせたようなものです.Makefileには各ターゲットに必要なリソースを並べて,ターゲットの生成方法を記述しますが,.asdファイルも同様にコンパイルに必要な依存パッケージをファイル毎に列挙します.makeは依存関係に応じて順にターゲットを生成していきますが,ASDFもLisp処理系を用いて順番にコンパイルしていきます.リンカはオブジェクトファイルをリンクして一つにまとめあげ,ローダは複数のオブジェクトコードをロードしますが,ASDFもコンパイル済みのファイルを依存関係に応じて探し出しロードしてくれます.makeが依存ファイルをダウンロード・インストールしてくれないように,ASDFにもインストーラー機能はありません.それは後述のQuicklispかRoswellを使います.

Javaの開発ツールで喩えるなら,Mavenのcompilerプラグインと,仮想マシンのクラスパス解決機能をまとめ合わせたものがASDFです.しかし,依存関係に応じてパッケージをダウンロード・インストールするMaven installプラグインの機能はありません.

ASDFリソース

Quicklisp

Quicklispは依存しているライブラリをウェブ上のリポジトリからダウンロード・インストールしてくれるツールです.さらにQuicklisp内部からASDFを呼び出しライブラリのロードも行えるので,ユーザ側からはQuicklispの使い方を学べばインストールもロードも完結します.しかしながら,自分が作ったプログラムで依存関係を定義するには.asdファイルを用意しなければならないので,最終的にはASDFの使い方を学ぶ必要があるでしょう.

Quicklispはインストールすべきライブラリの決定にASDF用の依存関係定義ファイル(.asdファイル)を用います.別言語用の似たようなツールと言えば,Javaプロジェクトで使われるMavenのinstallプラグインや,Node.jsのnpmなどが挙げられるでしょう.

QuicklispはASDFと違い処理系に梱包されていません.したがって自分でインストールする必要があります.インストールは簡単で,本家からquiclisp.lispファイルをダウンロードし,(load "quicklisp.lisp")(quicklisp-quickstart:install)(ql:add-to-init-file)の3式を順に評価するだけです.しかし,Quicklispには色々と問題もあるようです. 深町(@nitro_idiot)さんやkeen(@blackenedgold)さんが問題点とその解決法を説明しています.

後述するRoswellが,ライブラリのインストーラーとしての機能を完全に代替してくれる上,開発に必要な様々な機能を提供してくれるので,QuicklispはインストールせずRoswellでライブラリ管理を1本化するのがこれからのベストプラクティスだと思います.

Quicklispリソース

Roswell

RoswellはQuicklispのようなライブラリのインストーラーであると同時に,Lisp処理系のインストーラーでもあります.Roswellを使う場合,Lisp処理系もRoswellを使ってインストールします.

Quicklispを使ってインストールしたライブラリは全ての処理系から共有されますが,Roswellを使ってインストールしたライブラリは,RoswellでインストールしたLisp処理系からしか使用されません(もちろんパスを設定して読み込めばどの処理系からも使えますが).したがって,これまで使っていたLisp処理系とは独立に開発環境を構築でき,共存させることができます.

Roswellは背後でQuicklispを使用していますが,ユーザ側からはそれを意識することは一切ありません.したがって,Roswellさえインストールすれば,パスやリポジトリの設定をせずにライブラリのインストールから管理まで全て行えます.

Roswellのもう一つの強みは,アプリケーションを作成した際,処理系と依存ライブラリをパッケージ化し,コマンドラインから起動できるバイナリを簡単に生成できる点です.したがって,Roswellを使えば,開発段階のライブラリ収集から,デプロイメントまで一貫して行えます.自分の開発環境にQuicklispのインストールが不要なだけでなく,プロダクトの配布時に相手にQuicklispのインストールを依頼する必要もありません.

ここでは,パッケージ管理ツールとしてのRoswellについて書くのが目的なので,バイナリパッケージの作り方やコマンドスクリプトの作成方法は別の機会に譲り,Roswellでの開発環境のセットアップ方法のみ説明します.

Roswellのインストール

Lispプログラミングを始める時,通常,WindowsユーザはLispInBoxをインストールしたり,Unix系OSならばディストリビューションのパッケージマネージャを使ってLisp処理系をインストールするでしょう.Roswell流の開発では,Roswellを使ってLisp処理系をインストールします.ということで,まずはRoswellを用意しましょう.

Roswellは様々なOSに移植できるようC言語で書かれています(一部Lisp).したがってOSに合ったバイナリをダウンロード・インストールするか,Roswellのソースをダウンロードしインストールする必要があります.各OS毎のインストール方法はこちらを参照してください.

例えばOSXではHomebrewでインストールできます.HomebrewはMacPortsと共存可能なのでMacPortsユーザもHomebrewを使ってインストールできます(/usr/local/Cellar/roswell以下にインストールされる).インストール後は,

$ ros setup

を実行すると,Lisp処理系がダウンロードされインストールされます.Roswell で管理される処理系とライブラリは全て ~/.roswell 以下にインストールされます.もし,これまでインストールしたライブラリや処理系を全て削除して再インストールしたい場合は,~/.roswell を削除し,再度 ros setup を実行します.

デフォルトでインストールされた処理系のバージョンは,

$ ros run -- --version

で確認できます.インストール可能な処理系の一覧は以下で取得できます.

$ ros list versions
candidates for ros list versions [impl] are:

abcl-bin
allegro
asdf
ccl-bin
clasp
clisp
cmu-bin
ecl
quicklisp
sbcl-bin
sbcl
slime
sly

例えば,Clozure CL をインストールしたい場合は,以下を実行します.

$ ros install ccl-bin

インストールしたい処理系のバージョンも指定したい場合,以下のように指定します.

$ ros install sbcl/1.4.4

ローカルにインストール済みの処理系リストは以下で得られます.

$ ros list installed

デフォルトで使用する処理系は以下のコマンドで指定できます.

$ ros use sbcl/1.4.4

ros config を実行してもインストール済みの処理系と ros run で起動されるデフォルトの処理系を知ることができます.

$ ros config
sbcl.version=1.4.6
ccl-bin.version=1.11.5
slime.version=2018.03.28
setup.time=3731917397
sbcl-bin.version=1.4.4
default.lisp=ccl-bin

Possible subcommands:
set
show

処理系の管理方法はこちらを参照してください.

Roswellの処理系を使う

Roswellを用いてパッケージ管理する場合,処理系はRoswellでインストールしたものを使います.以下のコマンドでデフォルトの処理系が起動し,REPLが使えます.

$ ros run

Emacsエディタを使って開発するには,Roswell を使って最新の slime をインストールします.slime は ~/.roswell/lisp/slime 以下にインストールされます.

$ ros install slime

~/.emacs.d/init.el ファイルに slime 起動スクリプトと Roswell の起動設定を以下のように追加します.

;;; Slime for common lisp
(load (expand-file-name "~/.roswell/helper.el"))  ; slime 起動スクリプト
(setq slime-lisp-implementations
      `((ros ("ros" "run"))                       ; ros run の起動設定
        (sbcl ("/opt/local/bin/sbcl"))
        (abcl ("/opt/local/bin/abcl"))
        (clisp ("/opt/local/bin/clisp"))))

M-x slimeros を起動し.M-- M-x slimeで別の処理系を選択できます. さらに詳しい設定方法はこちらを参照してください.

ライブラリのインストール

Roswellでライブラリをダウンロード,インストールするのは簡単です.Quicklispに登録されているライブラリは,芋づる式に依存ライブラリをダウンロードしインストールしてくれます.例えば,clackをインストールしたければ,

$ ros install clack

だけです.あとはプログラムから(require 'clack)でロード完了です.

Roswellリソース

追記: 自分が開発するプロジェクトをRowswell環境下でビルド・ロードする手順については「Roswell環境下でのローカル・プロジェクト管理入門」に解説しました.