Practical Common Lisp (邦訳『実践Common Lisp』) を改めて読み直し中。第2章でLISPファイルのコンパイルについて書かれていたところがあったので、いくつかの処理系で試してみることに。
準備
まず以下のような簡単なプログラムを作り、hello.lispとしてファイルに保存します。
(defun hello-world () (format t "Hello, world!"))
これを実行するときには
CL-USER> (load "hello.lisp") T CL-USER> (hello-world) Hello, world! NIL
のように、REPLで読み込んでから実行します。また、処理速度*1が必要な場合には、
CL-USER> (load (compile-file "hello.lisp"))
というように、あらかじめコンパイルしてから読み込んで実行することもできます。このとき、hello.lispと同じディレクトリにはコンパイル済みのファイル(Fast Loadファイル)ができますが、このファイルの中身は処理系に依存したバイトコードらしく、僕が試した限りでは、SBCLはhello.fasl、ABCLはhello.abcl、ClozureCLはhello.dx64fslと、拡張子も異なりました。
SBCL
それぞれのファイルの中をバイナリダンプで見てみることにします。SBCLは冒頭部分にshebangが書いてあります。
$ hexdump -C hello.fasl | head -n 4 00000000 23 21 2f 75 73 72 2f 6c 6f 63 61 6c 2f 62 69 6e |#!/usr/local/bin| 00000010 2f 73 62 63 6c 20 2d 2d 73 63 72 69 70 74 0a 23 |/sbcl --script.#| 00000020 20 46 41 53 4c 0a 20 20 63 6f 6d 70 69 6c 65 64 | FASL. compiled| 00000030 20 66 72 6f 6d 20 22 2f 55 73 65 72 73 2f 6d 61 | from "/Users/ma|
shebangがあるので、パーミッションを実行形式に変えてやればコマンドラインから実行することができます。ただし、上記のhello.lispのままだと関数定義しかしていませんので何も表示されません。以下のように関数を呼びだす一文を追加します。
(defun hello-world () (format t "Hello, world!")) (hello-world)
それをSBCLで(compile-file "hello.lisp")して、次にコマンドラインでchmodすると、ちゃんと実行できました。
$ chmod 755 hello.fasl $ hello.fasl Hello, world!
ABCL
さて、ABCLが書き出したhello.abclはどうなっているかと言うと、
$ hexdump -C hello.abcl | head -n 4 00000000 50 4b 03 04 14 00 08 00 08 00 12 53 4c 42 00 00 |PK.........SLB..| 00000010 00 00 00 00 00 00 00 00 00 00 07 00 00 00 68 65 |..............he| 00000020 6c 6c 6f 2e 5f 6d 8f 41 4f 84 30 10 85 ef fc 8a |llo._m.AO.0.....| 00000030 49 7b 58 4b 52 ba e2 49 36 7b 20 6c 51 62 a1 4a |I{XKR..I6{ lQb.J|
冒頭にPKの2文字があるため、zipアーカイブ形式なのだろうと見当が付きます。実際、
$ unzip hello.abcl Archive: hello.abcl inflating: hello._ inflating: hello_1.cls inflating: hello_2.cls
のように解凍することができました。.clsファイルの冒頭を確認すると「ca fe ba be」とあるので、Javaのクラスファイルなのでしょう。
$ hexdump -C hello_1.cls | head -n 4 00000000 ca fe ba be 00 00 00 31 00 3b 01 00 0b 48 45 4c |.......1.;...HEL| 00000010 4c 4f 2d 57 4f 52 4c 44 08 00 01 01 00 10 43 4f |LO-WORLD......CO| 00000020 4d 4d 4f 4e 2d 4c 49 53 50 2d 55 53 45 52 08 00 |MMON-LISP-USER..| 00000030 03 01 00 17 6f 72 67 2f 61 72 6d 65 64 62 65 61 |....org/armedbea|
ただ、実行可能なJARファイルではなさそうです。(JARもZIP圧縮されているファイルなので、jar xvf hello.abclとすれば解凍はできます)
$ java -jar hello.abcl Invalid or corrupt jarfile hello.abcl
ClozureCL
ClozureCLのhello.dx64fslも見てみましたが、こちらは意味が分かりませんでした。処理系独自のバイトコードなんでしょうかね。
$ hexdump -C hello.dx64fsl | head -n 4 00000000 ff 00 00 01 00 00 00 0c 00 00 01 eb ff 5f 00 00 |............._..| 00000010 00 00 18 87 17 0a 00 53 2f c5 8a 68 65 6c 6c 6f |.......S/..hello| 00000020 2e 6c 69 73 70 46 a2 36 84 8f 1c 2c 82 42 c1 83 |.lispF.6...,.B..| 00000030 43 43 4c 8f 46 49 4e 44 2d 43 4c 41 53 53 2d 43 |CCL.FIND-CLASS-C|
おわりに
以上、SBCL、ABCL、ClozureCLと、どれも全く異なるFASLファイルを書き出しましたが、コマンドライン・プログラムを作るのであればSBCLが楽チンそうなのが分かりました。もちろん、他の処理系でも実行形式ファイルを作ることは可能です。例えばABCLならTowards ABCL Standalone Executablesなどが参考になります。