ASDF(Another System Definition Facility)とは、Common Lispで書かれたライブラリを管理するためのライブラリです。ライブラリの読み込みやコンパイルを統一された方法で行えるようになります。
ANSI Common Lispではモジュール化のための機能が不足しているので、ASDFがモジュール化のために使われることが多く、2011年現在、事実上の標準になっています。
2010年にASDF 2がリリースされ、それ以前のASDFとは大幅に仕様が変更されました。ここでは基本的にASDF 2について説明します。
ANSI Common Lispでは、ライブラリの読み込みや定義に関係する機能は、require、provide、*modules*の組み合わせしかありません。しかし、規格に曖昧な部分があり、移植性に問題があります。
そのため、require、provide、*modules*はANSI Common Lispでは推奨されませんが、規格には他にライブラリの管理についての仕組みがありませんので、ライブラリを管理する機能が実質的に存在しません。
他のライブラリに依存するライブラリは、先に依存するライブラリを読み込まないと、正常に動作しません。依存関係を把握して、他のライブラリを読み込むのは、面倒ですし、間違いを犯しやすい作業です。
また、Common Lispで書かれた、複数のファイルに分割されたライブラリを利用する場合、特定の手順が必要になる場合があります。例えば、他のファイルで定義されたマクロを使うコード(他のファイルに依存するコード)は、マクロ定義をあらかじめ読み込まないと正常にコンパイルできませんし、特定のパッケージを使うコードでは、先にパッケージを定義しておかなければなりません。
こういった、不足していた部分を補ったり、煩雑な処理を自動化するために作られたのがASDFです。ASDFを利用すると、ライブラリを読み込んだり、コンパイル作業を自動化して、統一されたAPIで処理できます。
Cでの開発におけるmake、Javaでの開発におけるApache Antにあたります。PerlのCPANやRubyのRubyGemsより一段下の仕組みで、CPANやRubyGemsのようなより高度な管理は、QuicklispやASDF-Install?を使います。
仕組みを理解するのに多少時間がかかりますが、それぞれのライブラリをそれぞれの方法で管理するよりは、ずっと時間を節約できます。
多くの処理系には最初からASDFが導入されています。
(require :asdf)
を評価すると、ASDFがすでに導入されている環境では、ASDFが読み込まれます。
もし、ASDFがインストールされていないために上の式が失敗する場合、asdf.lispをダウンロードして、適当な場所にコピー、移動し、loadで読み込んでください。asdf.lispを置く場所は、処理系のロードパスに含まれるディレクトリが適切でしょう。
インストールにかかる手間はこれだけです。起動時に自動的にASDFを読み込みたい場合、
;; 最初からASDFが導入されているか、処理系のロードパスに含まれる場所にインストールした場合 (require :asdf) ;; 処理系のロードパスに含まれない場所にインストールした場合 (load "インストールした場所/asdf.lisp")
というコードを、処理系の初期化ファイルに追加してください。
特に設定しなくても、標準の設定で使うことができますが、ライブラリを探す場所と、オブジェクトコードを保存する場所を設定できます。特に設定をしない場合、ライブラリはホームディレクトリ(以下~/)の.local/share/common-lisp/source/以下に置いてください。
基本的に、こちらの方法が一般的です。
ASDFはXDG Base Directory Specificationに準拠していて、設定ファイルを$XDG_CONFIG_HOME、あるいは$XDG_CONFIG_DIRS以下のcommon-lispディレクトリに置くことになっています。デフォルトでは全ユーザ共通の設定を/etc以下の、ユーザごとの設定を~/.config以下の、common-lispディレクトリにある設定ファイルが読み込まれます。
ライブラリを探すディレクトリを設定するファイル
「ライブラリを探すディレクトリを設定するファイル」を置くディレクトリ。ファイル名でソートした順に設定ファイルが読み込まれる。common-lisp/source-registry.confがある場合はそちらが優先される
コンパイルしてできたオブジェクトコードを保存するディレクトリを設定するファイル
「コンパイルしてできたオブジェクトコードを保存するディレクトリを設定するファイル」を置くディレクトリ。ファイル名でソートした順に設定ファイルが読み込まれる。common-lisp/asdf-output-translations.confがある場合はそちらが優先される
設定ファイルに書く内容は、S式のDSLになっています。詳しい仕様は、ASDF Manualの「7 Controlling where ASDF searches for systems」と「8 Controlling where ASDF saves compiled files」を参照してください。
例えば、~/lisp/以下からも、ライブラリを読み込むように設定する場合、~/.config/common-lisp/source-registry.confに、
(:source-registry (:tree (:home "lisp")) ; ~/lisp/に展開される :inherit-configuration)
と書き込んで保存します。
ASDFに対応したライブラリの開発中に便利な方法です。
例えば、一時的に/tmp/lib-foo/にあるライブラリを探して欲しい場合、
(asdf:initialize-source-registry '(:source-registry (:directory ("/tmp/lib-foo/")) :inherit-configuration))
のように、API経由でASDFの設定をすることができます。APIに渡すリストは、設定ファイルに書くものと同じです。
APIの定義はASDF Manualの「7.9 Configuration API」と「8.8 Output location API」を参照してください。
環境変数CL_SOURCE_REGISTRYとASDF_OUTPUT_TRANSLATIONSでも設定できます。詳しい内容はASDF Manualの「7.6 Shell-friendly syntax for configuration」と「8.5 Shell-friendly syntax for configuration」を参照してください。
;; 最初からASDFが導入されているか、処理系のロードパスに含まれる場所にインストールした場合 (require :asdf) ;; 処理系のロードパスに含まれない場所にインストールした場合 (load "インストールした場所/asdf.lisp")
のように、ASDFを読み込んだ状態で、
(asdf:load-system :foo)
というコードを評価するだけです。設定された場所からfooという名前のライブラリを探し、必要に応じてコンパイルした上で読み込まれます。
などの処理系では、requireが拡張されていて、ASDFの仕組みを利用してライブラリを利用できるようになっています。そのため、
(require :foo)
としても、ライブラリを読み込めます。
ライブラリを読み込むとき、必要に応じて自動的にコンパイルされるため、基本的に自分でコンパイルする必要はありませんが、最適化オプションを変えてコンパイルしたい場合などは、手動でコンパイルすることもできます。
(asdf:compile-system :foo)
注意:キーワード引数proclamationsは不具合のため、正常に動作しません。(ASDF Manualの13.2 Missing bits in implementationを参照してください)最適化オプションを変えたい場合は、declaimを使ってください。
また、依存しているライブラリを含めて、すべてを強制的にコンパイルしたい場合は、
(asdf:compile-system :foo :force t)
としてください。
(書きかけ)