Next: , Previous: Speed of Byte-Code, Up: Byte Compilation


15.2 コンパイル関数

関数byte-compileで、 個々の関数定義やマクロ定義をバイトコンパイルできます。 byte-compile-fileで1つのファイル全体をコンパイルしたり、 byte-recompile-directorybatch-byte-compileで 複数個のファイルをコンパイルできます。

バイトコンパイラは、 各ファイルに対するエラーメッセージや警告メッセージを ‘*Compile-Log*’と呼ばれるバッファに出力します。 読者のプログラムに関してここに報告されたことがらは、 問題点を指摘しますが、必ずしもエラーとは限りません。

バイトコンパイルする可能性のあるファイルにマクロ呼び出しを書くときには 注意してください。 マクロ呼び出しはコンパイル時に展開されるので、 正しくコンパイルするためにはマクロは定義済みである必要があります。 詳しくは、See Compiling Macros

通常、ファイルをコンパイルしてもファイルの内容を評価したり、 ファイルをロードしません。 しかし、ファイルのトップレベルに書いたrequireは実行します。 コンパイル時に必要なマクロ定義が存在することを保証する1つの方法は、 それらを定義するファイルを要求(require)することです (see Named Features)。 コンパイルしたプログラムを実行するときに マクロ定義ファイルのロードを防ぐには、 requireの呼び出しの周りにeval-when-compileを書きます (see Eval During Compile)。

— Function: byte-compile symbol

この関数は、symbolの関数定義をバイトコンパイルし、 以前の定義をコンパイルしたもので置き換える。 symbolの関数定義は、関数の実際のコードであること。 つまり、コンパイラは、別のシンボルへの間接参照を辿らない。 byte-compileは、symbolのコンパイル済みの新たな定義を返す。

symbolの定義がバイトコード関数オブジェクトであると、 byte-compileはなにもせずにnilを返す。 Lispはどんなシンボルに対しても関数定義を1つだけ記録するので、 それがすでにコンパイル済みであると、 コンパイルまえのコードはどこにもないのである。 したがって、『同じ定義をコンパイルし直す』方法はない。

          (defun factorial (integer)
            "Compute factorial of INTEGER."
            (if (= 1 integer) 1
              (* integer (factorial (1- integer)))))
           factorial
          
          (byte-compile 'factorial)
          
          #[(integer)
            "^H\301U\203^H^@\301\207\302^H\303^HS!\"\207"
            [integer 1 * factorial]
            4 "Compute factorial of INTEGER."]

結果は、バイトコード関数オブジェクトである。 この文字列には実際のバイトコードが入っている。 その各文字は、命令や命令のオペランドである。 ベクトルには、特別な命令に符号化される特定の基本関数を除いて、 関数が使うすべての定数、変数名、関数名が入っている。

— コマンド: compile-defun

このコマンドはポイントを含むdefunを読み取り、 それをコンパイルして、結果を評価する。 実際に関数定義であるdefunでこのコマンドを使うと、 その関数をコンパイルしたものをインストールすることになる。

— コマンド: byte-compile-file filename

この関数は、filenameという名前のLispコードのファイルを コンパイルしバイトコードのファイルにする。 出力ファイルの名前は、接頭辞‘.el’を‘.elc’に換えて作る。 filenameが‘.el’で終っていないときには、 filenameの末尾に‘.elc’を付加する。

入力ファイルから一度に1つずつフォームを読みながらコンパイルを行う。 それが関数定義やマクロ定義であると、 コンパイルした関数定義やマクロ定義を書き出す。 他のフォームは一塊にして、各塊をコンパイルして書き出し、 ファイルを読むとコンパイルしたコードが実行されるようにする。 入力ファイルを読むときにすべてのコメントを捨てる。

このコマンドはtを返す。 対話的に呼び出すとファイル名を問い合わせる。

          % ls -l push*
          -rw-r--r--  1 lewis     791 Oct  5 20:31 push.el
          
          (byte-compile-file "~/emacs/push.el")
                t
          
          % ls -l push*
          -rw-r--r--  1 lewis     791 Oct  5 20:31 push.el
          -rw-rw-rw-  1 lewis     638 Oct  8 20:25 push.elc
— コマンド: byte-recompile-directory directory flag

この関数は、directoryにある再コンパイルが必要な 個々の‘.el’ファイルを再コンパイルする。 ファイルを再コンパイルする必要があるのは、 ‘.elc’ファイルが存在しても‘.el’ファイルより古い場合である。

.el’ファイルに対応する‘.elc’ファイルが存在しない場合には、 flagが動作を指示する。 それがnilであると、そのようなファイルは無視する。 nil以外であると、そのような各ファイルをコンパイルするかどうか ユーザーに問い合わせる。

このコマンドの戻り値は予測できない。

— Function: batch-byte-compile

この関数は、コマンド行に指定したファイル群に対して byte-compile-fileを実行する。 この関数はEmacsをバッチモードで実行しているときにだけ使うこと。 完了するとEmacsを終了するからである。 1つのファイルでエラーが発生しても、後続のファイルの処理には影響しないが、 エラーを起こしたファイルに対する出力ファイルは生成せず、 Emacsのプロセスは0以外の状態コードで終了する。

          % emacs -batch -f batch-byte-compile *.el
— Function: byte-code code-string data-vector max-stack

この関数はバイトコードを実際に解釈実行する。 バイトコンパイルした関数は、実際には、 byte-codeを呼び出すような本体として定義される。 この関数を読者自身で呼び出さないこと。 この関数の正しい呼び出しを生成する方法はバイトコンパイラだけが知っている。

Emacs 18版では、バイトコードは関数byte-codeをつねに呼び出すことで 実行していた。 現在では、バイトコード関数オブジェクトの一部としてバイトコードを実行するのが 普通であり、byte-codeを明示的に呼び出すことは稀である。