Next: , Previous: , Up: ASDFのオブジェクトモデル   [Contents][Index]


7.2 コンポーネント

componentオブジェクトが表すのは、1つのソースファイルか、複数のソースファイルのまとまりか、あるいはそれらから変換されるもの(faslなど)です。

componentの組み込みのサブクラスとして重要なのはsystemsource-filemoduleです。systemはコンポーネント階層のトップレベルにある特別なコンポーネントであり、find-systemによって発見することができます。source-fileは1つのソースファイルに対応します。moduleは中間的なコンポーネントであり、他のコンポーネント(source-fileやさらなるmoduleであっても良い)のまとまりを表します。(→ コンポーネントの組み込みのサブクラス

システム指示子(system designator)はシステムそのものか、システムを表す文字列、シンボルです。(コンポーネント名の仕様と同じく、シンボルは小文字に変換されます。)

コンポーネント指示子(component designator)は基点となるコンポーネントに対する相対的な指示子であり、コンポーネントそのものか、文字列、シンボルか、あるいはコンポーネント指示子のリストです。

関数: find-system system-designator &optional (error-p t)

find-systemはシステム指示子を引数に取り、システムを返します。システムが見つからなかった場合、デフォルトではエラーmissing-componentを通知しますが、error-pnilの場合は単にnilを返します。

システム定義ファイルを見つけてメモリ上のシステムをアップデートするために、find-systemはリスト*system-definition-search-functions*に含まれる関数をそれぞれfuncallします。それらの関数はシステム名を引数に取り、(システム定義ファイルの)パス名かシステムオブジェクト(system-source-directoryでパス名に変換される)を返すべきであり、返ったパス名はメモリ上に登録されるでしょう。こうして見つかったシステム定義ファイルがロードされるのは、次の条件のいずれかを満たす場合です:

.asdファイルからシステム定義がロードされる際の暗黙のカレントパッケージはasdf-userであり、asdf-userasdfuiopuiop/common-lispuseしています。27 .asdファイル内で新しい変数・関数・クラスを定義するなど、単純なシステム定義にとどまらないことをする場合は、defpackagein-packageで別のパッケージを作り、asdf-userとは干渉しないようにするべきです。ただ、フォームを追加する目的が、(開発・デバッグのために)cl:loadで手動で.asdファイルをロードできるようにすることなのであれば28、そうするよりもasdf:load-asdを使うことを推奨します。なお、SLIMEを使っている場合は、slime-asdf拡張をロードすれば、.asdファイルの編集時にasdf:load-asdが適切に適用されるようになります。

デフォルトでは*system-definition-search-functions*は3つの関数からなるリストです。最初の関数は、*central-registry*の要素を評価して得られた各ディレクトリから、ファイル名がシステム名であり、拡張子が.asdであるファイルを探し、最初に見つかったパス名を返します。ただし、探索対象のシステムがそのファイル内で実際に定義されているかどうかはチェックしません。2つ目の関数は同様のことをsource-registryで指定されたディレクトリに対して行いますが、実際にファイルシステムを探すのは1回のみであり、結果はキャッシュされます。29 3つ目の関数はpackage-inferred-system拡張で使われます。詳細はpackage-inferred-system拡張を参照してください。

システムの探索関数の仕様からもわかるように、システムfoofoo.asdという名のファイルに定義するべきであり、また、ファイルはセントラルレジストリかソースレジストリに指定されたディレクトリに置くようにするべきです。

1つのファイル内で複数のシステムを定義するのが便利なケースも良くあるでしょうが、ASDFはシステム名に基づいてシステム定義ファイルを探すことしかできません。この理由により、ASDF 3からはシステム定義を探すアルゴリズムが拡張され、ファイルfoo.asdには、システムfooに加えてfoo/barfoo/bazfoo/quuxといった名のシステムも定義できるようになりました。/で区切られたシステム名の最初の部分をシステムのプライマリネーム(primary name)と呼び、対応するシステムをプライマリシステム(primary system)と呼びます。ASDF 3は、名前にスラッシュを含むシステムを探すように指示されると、関数asdf:primary-system-nameによってプライマリネームを抽出し、まずはプライマリシステムを探してロードしようとします。そして、見つかった場合は、そのファイルにターゲットのシステムが定義されているかどうか、もしくはpackage-inferred-systemが定義されているかどうか調べます。30 foo.asdに、この命名ルールに従わないシステム(例えばfoo-testなど)が定義されている場合、ASDFはシステム定義の場所を自動的に見つけることができないので、事前に(asdf:find-system "foo")を実行するなどして、明示的にプライマリシステムの定義をロードしておかなければなりません。我々はそのような命名の慣習をやめることを強く推奨しますが、今のところ、後方互換性のためにサポートされてはいます。

関数: primary-system-name name

nameがスラッシュ/によって区切られている場合、primary-system-nameはプライマリネーム、つまり最初の部分を返します。

関数: locate-system name

一般的には、この関数を直接呼び出すべきではありません。この関数がAPIの一部としてエクスポートされているのは、独自の*system-definition-search-functions*を使いたいプログラマのためです。

locate-systemはシステム名の指示子を引数に取り、システム定義をどこからロードすれば良いか調べようとします。

[訳者補足]

この関数そのものはシステム定義をロードすることはない――と原文には書かれています。しかし現在のバージョンでは、プライマリネームが絡んでいるケースで、例えば(asdf:locate-system :baz/test)などとすると、bazbaz/testのシステム定義がロードされることがあるようです。いずれにせよ、システム定義のロードにはfind-systemを、システムそのもののロードにはload-systemを使うべきです。

[訳者補足終わり]

この関数は6つの値を返します: foundpfound-systempathnamepreviousprevious-timeprevious-primaryfoundpはシステムが見つかれば(未登録であれ、登録済みであれ)真です。found-systemnilでない場合、システムオブジェクトです。(そのシステムは登録されているかもしれないし、されていないかもしれません。) pathnamenilでない場合、システム定義ファイルのパス名であり、このパス名はfound-systempreviousのシステムと対応しているでしょう。previousnilでない場合、前回ロードされた同名のシステムオブジェクトです。(なお、ここでロードされているのはシステム定義であって、システムそのものではないことに注意しましょう。)previous-timenilでない場合、previousの定義が前回ロードされた際のシステム定義ファイルのタイムスタンプです。previous-primarynilでない場合、システムpreviousのプライマリシステムです。

例えば、ソースレジストリに登録されたパス/current/path/to/foo.asdにシステム定義ファイルがあるとしましょう。しかし、システムfooは前回は/previous/path/to/foo.asdからロードされたとします。このとき、locate-systemは次の値を返すでしょう:

  1. foundptです。
  2. found-systemnilです。
  3. pathname#p"/current/path/to/foo.asd"です。
  4. previoussystemオブジェクトであり、そのsystem-source-fileスロットは#p"/previous/path/to/foo.asd"です。
  5. previous-timeは前回#p"/previous/path/to/foo.asd"がロードされたときのタイムスタンプです。
  6. previous-primarypreviousと同じオブジェクトです。
関数: find-component base path

baseコンポーネント(あるいは指示子)とpathを引数に取り、baseを基点としてpathで指示されるコンポーネントを見つけます。

pathがコンポーネントオブジェクトの場合は、baseに関係なく、そのままpathが返ります。

pathが文字列かシンボル(coerce-nameで文字列に変換される)の場合、baseはシステムかモジュールを指していなくてはなりません。この場合、返り値はpathの指すbaseの子コンポーネントです。

pathconsセルの場合、find-componentbasepathcarから再帰的に子コンポーネントを辿り、末端のコンポーネントを返します。

basenilの場合、(find-component path nil)と同等になります。

baseが文字列かシンボル(coerce-nameで文字列に変換される)の場合、basefind-systemの返すシステムであるとみなされます。

baseconsセルの場合、base(find-component (car base) (cdr base))の返すコンポーネントであるとみなされます。


Footnotes

(27)

バージョン2.27~3.0.3では、uiopの代わりにuiop/packageのみがuseされていました。バージョン3.1.2以前に対応したコードを書くためには、uiopuseしたパッケージを自ら定義するか、あるいはuiop:というパッケージ接頭辞をいちいち付ける必要があります。

(28)

[訳注] 例えば冒頭に(cl:in-package :asdf-user)を追加する、など。

(29)

[訳注] clear-source-registryでキャッシュのリセットができます。

(30)

ASDF 2.26以前はプライマリネームの機能をサポートしていませんでした。従って、それらのバージョンでは、システムfoo/barfoo.asdに定義されている場合は、(asdf:find-system "foo")を実行するなどして、事前にそのファイルを明示的にロードしなければなりません。我々はASDF 2をサポートしていませんので、ASDF 3にアップグレードすることを推奨します。