asdfをはじめよう(Getting started with ASDF)を訳したった

(拙い翻訳で)すまんな。

ASDF日本語の関連情報(その他にもあったら教えて欲しいなって)

#9LISP How to use ASDF
http://beta-reduction.blogspot.jp/2010/05/9lisp-how-to-use-asdf.html

Common Lisp users jp ASDF
http://cl.cddddr.org/index.cgi?ASDF

原文

"Getting started with ASDF"
Mario S. Mommer

Last modified: April 05, 2006.
http://common-lisp.net/~mmommer/asdf-howto.shtml



*** ここから翻訳 ***


Introduction

この文書の目的 (Purpose of this document)

この文書の狙いは、ASDF(Another System Definition Facility)を使うための短い導入をすることです。深遠なトリックやtips、ASDFそれ自身やシステム定義ツール一般のデザインについては議論しません。

The aim of this document is to give a brief introduction to the use of ASDF, Another System Definition Facility. It is not about the arcane tricks and tips, and is not about the design of ASDF itself nor about system definition tools in general.

システム定義ファイルとは、ソースファイル間の依存関係の記述に過ぎません。それによって、ソースファイルは正しい順番でコンパイルされ、ロードされます。A.lispとB.lispというファイルがあったとして、もしB.lispが、A.lispで使われた定義とコードのどちらか(あるいはどちらも)を含んでいたならば、A.lispはB.lispに依存しています。
*1

A system definition file is nothing else than a description of dependencies between files of source code in such a way that they can be compiled and loaded in the right order. A file A.lisp depends on a file B.lisp if the latter contains definitions and/or code that is used by A.lisp.
*2

この問題を解決することは、ほとんどのケースにおいてとても簡単です。そのため、ごく小さなスクリプトをハックする分には大丈夫です。しかしながら、正しいツールを学ぶことは、将来、大きな時間の節約になるでしょう。この小さなチュートリアルで、我々はシンプルな事例と、よく知られたツールであるASDFの一般的な使い方に集中します。このツールのより進んだ特徴については、 ASDF manual に任せることにしましょう。

Solving this problem is in the vast majority of cases fairly trivial, so hacking up some minimal script will usually work. Learning the right tool, however, will save you a lot of time down the road. In this minitutorial we will concentrate on the simple cases and on the general usage of a fairly well known tool, ASDF. We leave the more advanced features of this tool to the ASDF manual2.

ASDFはどんな問題を解決しますか? (What problem does ASDF solve?)

あなたがインターネッツ、あるいは他の何かから、ソフトウェアのソースコードをダウンロードした時、あなたは普通、不定形のバッチファイルではなく、特定の方法で相互に依存しあうコンポーネントからなるシステムを手にしているはずです。その帰結として、もしあなたがそのソフトウェアを(ライブラリとか、アプリケーションとするために)ビルドしたいとき、あなたはおそらくそのコンポーネントを順番に、ひょっとしたらいくつかのものには特別な注意をしながら、順番にビルドしていくことになるでしょう。開発者がそういうことについてすべて面倒をみてくれていて、ビルドプロセスを進めるのにたったひとつコマンドを入力すればいいだけなら、あなたとても幸福ですね?

When you download the source code of some software from the Internet, or get it from some other source, you usually do not get an amorphous bunch of files, but instead get a system of components that depend on each other in some particular way. The consequence of this is that, if you want to build the software (be it a library, or be it an application), you will probably have to build these components, and the components of these components in order, perhaps giving some special treatment to some of them. You would, of course, be very grateful if the developer had prepared everything, and you could trigger the build process by a single command.

あなたがもし少ないコンポーネントからなるプロジェクトで働いている開発者ならば、1つのコンポーネントを変更したら、それが、影響を受けるコンポーネントだけを再コンパイルして再ロードしてくれるような、コンポーネントの依存関係を整理してくれる仕組みが欲しいと思っているかもしれません。

If you are a developer working in a project with a few components, you will probably want some mechanism that keeps track of the dependencies between these components, so that if you change one component, triggering a rebuild only recompiles and reloads the components which are affected.

最後に、あなたは多分、コンポーネントの依存関係とビルドとロードのプロセスをどーにかしてくれる一貫したシステムが欲しいんじゃないでしょうか。
そうすれば、みんながソフトウェアをインストールしたり使ったりする時間を省いてくれますからね。

Finally, you probably want a consistent way of dealing with the dependencies between components and of building and loading software systems, simply because it saves everyone time when installing software and using software.

ASDFは大雑把に言って、ソフトウェアコンポーネントの依存関係を定義し、結果として起こるビルドプロセスの細かいことを規定する、拡張可能なシステムです。そして、ASDFはとても広く使われているので、あなたのシステムについて、多くの人が理解できるだろう、と期待できます。

ASDF is, roughly speaking, an extensible facility for defining the dependencies between software components, and specifying eventual details of the build process. It is also in fairly wide use, so that you can assume that your system definition will be understood by many others.

同じ事が、ファンも多ければアンチも多い mk:defsystem についても言えますが、我々はASDFにのみ集中します。どこからかはじめなければいけないからです。どんなものでも、2つの実際の違いはパワーユーザーにしか分かりません。

The same can be said about mk:defsystem, which has fans as well as detractors. We will only concentrate here on ASDF, since we have to start somewhere. In any case, the actual differences between these two only become apparent for the power user.

法律の問題 (Legal matters)

Creative Commons License
This work is licensed under a Creative Commons Attribution 2.5 License.

ASDFでシステムを定義する (Defining systems with ASDF)

ASDFのシステム定義は .asd という拡張子のついたファイルに収められます。話を明確にするために、ある、何かでしゃばらない名前の、そう、 cow というプロジェクトのためにシステム定義を書きたいものとしましょう。

An ASDF system definition is stored in a file with the extension .asd. To make the discussion clearer, we are going to pretend that we want to write the system definition facility for our software project, called, unassumingly, cow.

システム定義ファイルは cow.asd にするべきでしょう。そして、少なくとも大体の場合で、あなたのソースコードがあるのと同じディレクトリに置くべきです。emacsを使っているなら、 cow.asd のはじめの行には次のように書くでしょう。

The system definition file should be called cow.asd, and, at least in the usual scenarios, should reside in the same directory as your source code. If you use emacs, you might want to put the following as the first line in cow.asd.

;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10 -*-

これで適切なシンタックスサポートをオンにできます。コレが必要なのは、emacsはデフォルトでは .asd ファイルに関して必要なことを知らないからです。

This makes sure that the proper syntax support is turned on, which is necessary because by default emacs knows nothing about .asd files.

この後、 cow.asd は次のようなコードで始まることになります ( 前後にコメントを伴って……言うまでもないですね )

After that, cow.asd should start with the following code (preceded or followed perhaps by comments; goes almost without saying)

(defpackage #:cow-asd
  (:use :cl :asdf))

(in-package :cow-asd)

次に書くべきは、いくつかの(オプショナルな)特別な情報を伴った defsystem フォームです。

The next thing is to write a defsystem form, together with some (optional) extra information.

(defsystem cow
  :name "cow"
  :version "0.0.0"
  :maintainer "T. God"
  :author "Desmon Table"
  :licence "BSD sans advertising clause (see file COPYING for details)"
  :description "Cow"
  :long-description "Lisp implementation of our favorite ruminant"

予想しているだろう通り、最初の行は必須です。

As you might have guessed, only the first line is mandatory.

基本形 (The base case)

もっとも単純なケースでは、あなたはごく少ないファイルが入ったディレクトリを1つだけ持っていることになるでしょう。そして、さらに疑いようもなく単純なケースというのは、ファイルの依存関係が線形な時です。この場合、あなたははじめにロードされるファイルがはじめに、次にロードされるファイルが2番めに……といったリストを作れます。

In the simplest case you have a directory with a few files. And the absolutely simplest case is when the dependency of your files is linear. That is, you can make a list of the files such that the first one should be loaded first, the second second, etc.

そういうケースの場合、defsystemフォームはこんな感じになります。

In such a case, the defsystem form can look like this.

(defsystem cow
  ;;; (Optional items omitted)
  :serial t ;; the dependencies are linear.
  :components ((:file "defpackage")
               (:file "legs")
               (:file "tail")
               (:file "head")))
複雑な場合 (A more complex example)

我々は、すでに述べたのと同じファイルを持っているものと思います。しかし、依存関係をより精確に定義したいと思っているでしょう。すべてのファイルが依存する、 defpackage.lisp と呼ばれるファイルがありますそして何か不思議な理由で、 tail.lisp が leg.lisp に依存しています。そんなプロジェクトの defsystem フォームは次のようになります。

Suppose that we have the same files as before, but would like to specify the dependencies more accurately. There is a file called defpackage.lisp, from which everything else depends. And we have that, for some mysterious reason, tail.lisp depends on legs.lisp. The defsystem form for this project could look as follows.

  ;;; (Optional items omitted)
  :components ((:file "tail"
                      :depends-on ("package" "legs"))
               (:file "legs"
                      :depends-on ("package"))
               (:file "head"
                      :depends-on ("package"))
               (:file "package")))

このケースでは、 cow.asd をソースファイルと同じフォルダに置いています。もしもあなたが我々の幸福な cow システムを試したいなら、関連した節へと直接飛んでください。

In this case you would keep the file cow.asd in the same directory as the source files. If you want to try out our nice cow system, you can jump directly to the pertinent section.

モジュールのあるシステム (A system with modules)

我々は次のような、もっと入り組んだ構造を持っていることでしょう。 head.lisp とか legs.lisp があります.また我々は、サブシステムとしていくつかのファイルを含む respiratory (訳注:呼吸器) というサブシステムをもっており、breathing というサブディレクトリに入っています(cow.asdがあるディレクトリのサブディレクトリです)。同様に、 circulation(訳注:循環器;恋愛は関係ない)というサブシステムもあります。
defsystemフォームは多かれ少なかれこんな感じになります。

Suppose that we have the following, more involved structure. We have a head.lisp, and legs.lisp. But we also have a subsystem called respiratory, which consists of a few more files, and lives in its own subdirectory called breathing (this is a subdirectory of the directory where cow.asd lives). Similarly, we have another subsystem called circulation. The defsystem form could look more or less like this.

(defsystem cow
  :components ((:file "head" :depends-on ("package"))
               (:file "tail" :depends-on ("package"
                                           circulation))
               (:file "package")
               (:module circulation
                        :components ((:file "water"
                                            :depends-on
                                            "package")
                                     (:file "assorted-solids"
                                            :depends-on
                                            "package")
                                     (:file "package")))
               (:module respiratory
                        :pathname "breathing"
                        :components (...))))

circulation モジュールにあるファイルとは circulation サブディレクトリにあるすべてのファイルです。そのため、circulation モジュール package.lisp は、それより上のレベルにある同名のそれとは違うものです。

Note that the files in the module circulation all live in the subdirectory circulation. Thus the file package.lisp in the module circulation is a different one than that a level higher.

モジュールはコンポーネントとしてファイルとモジュールの両方を持てます。さらにそのモジュールもコンポーネントとしてファイルとモジュールを持てます。依存性は所与のコンポーネント集合の中でのみ定義されることは、特筆すべきことです。ですから、 tail.lisp はサブモジュールのコンポーネントである assorted-solids には依存できません。

A module can have as components both files and other modules, which in turn can have files and modules as components. It is important to note that dependencies can only be defined inside a given set of components. So, the file tail.lisp cannot depend on the file assorted-solids, which is a component of a submodule.


他のシステムに依存する (A system that depends on other systems)

他のシステムに依存しているシステムもいつもの場合と同じですが、 :depends-on オプションが違っています。こうなります。

A system that depends on other systems will look exactly like a regular one, except for an additional :depends-on option. It looks like this.

(defsystem cow
  ;;; ...
  :components (...)
  :depends-on ("other-system"))

システム定義ファイルをどう使うか (How to use system definition files)

ソフトウェアがあるのと関連したディレクトリの中に、システム定義ファイルはあります。しかし、ソフトウェアをビルドしてロードするのにそのディレクトリをワーキングディレクトリにする必要はありません。システム定義ファイルへのシンボリックリンクを、 asdf が探すディレクトリに置いておきさえすればよいのです。

System definition files live in the directory where the corresponding piece of software lives. However, you do not need to have that directory as your working directory to be able to build and load said software. You only need to put a symbolic link to the system definition file in a directory where ASDF searches.

普通のセットアップは次のようになります。まず、 asdf をロードする必要があります。幾つかの実装では、 asdf はすでにロードされています。
それ以外では、書いてあるとおりです。

The usual setup is as follows. To begin with, you need to have ASDF loaded. In some implementations ASDF is already loadad. In others, it is just a matter of writing

  (require 'asdf)

一方、幾つかの実装では、あなたははじめに、 asdf をインストールする必要があります。ここからファイルを取得できるので、適当な場所に置いてください。例えば、 foo という名前でログインしているなら、 /home/foo/lisp/utils/ にです。コンパイルしたいかもしれません。

whereas in others you might need to install it yourself first. You can get it, in a single file, from here, and put it somewhere reasonable. For instance, if your login name was foo, in the directory /home/foo/lisp/utils/. You may also want to compile that file.

そして、Common Lisp処理系の初期化ファイルのどこかに(CMUCLなら、ホームディレクトリにある .cmucl-init.lisp )、次のような感じの一節を書きます。

Now, somewhere in the init file of your Common Lisp implementation (for CMUCL it would be .cmucl-init.lisp in your home directory) a variation of the following passage should appear.

(load "/home/foo/lisp/utils/asdf")

(setf asdf:*central-registry*
   ;; Default directories, usually just the ``current directory''
  '(*default-pathname-defaults*

    ;; Additional places where ASDF can find
    ;; system definition files
    #p"/home/foo/lisp/systems/"
    #p"/usr/share/common-lisp/systems/"))

cow システムをビルドし、ロードするためのコマンドは、次のようなものです。

The command to build and load system cow is

(asdf:operate 'asdf:load-op 'cow)

cow.asd がカレントワーキングディレクトリにあるならば、ビルドとロードのプロセスはそこで始まります。そうでないならば、 asdf は中央レジストリにあるディレクトリから cow.asd という名前のシステム定義ファイル、またはそれへのシンボリックリンクを見つけ出します。後者が見つかった場合、
オリジナルのファイルへのリンクをたどり、そのディレクトリでビルドプロセスを走らせます。ファイル自体が見つかれば、見つけたディレクトリでビルドプロセスを走らせます。

If the file cow.asd happens to be in the current working directory, the build and load process will start there. If not, ASDF will search through the directories in the central registry, and look for a system definition file named cow.asd, or for a symbolic link to one. If it finds the latter, it will follow the link to the original file, and run the build process in the corresponding directory. If it finds the file, it will run the build process in the directory where it finds it.

ですから、もしあなたが /home/foo/lisp/systems/ に cow システム定義ファイルのシンボリックリンクをんな感じで置いたとして……

So, if you make a symbolic link in /home/foo/lisp/systems/ to the cow system definition file, by executing (for example)

$ cd <where-your-system-defs-are>
$ ln -s /home/foo/code/cow/cow.asd

……cow ソフトウェアのビルドとロードは、そのファイルが置いてあるディレクトリに行くことなく、次のようなコマンドで可能になります。

Then you can build and load the cow software without having to be in the directory where this software lives simply by issuing the command

(asdf:operate 'asdf:load-op 'cow)

*1: LISPにおいては、事態は少し複雑になります。しかし、我々はもっともよくあるケースに限ることにしましょう。そのためには、この定義で十分です

*2: In lisp, things can get a little more complicated. We limit ourselves here to the most common cases, and for them this definition is good enough.