[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

14. ロード

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Loading"
"texi/elisp21/ロード"へのコメント(無し)

Lispコードのファイルをロードするとは、 その内容をLispオブジェクトの形でLisp環境に取り込むことです。 Emacsは、ファイルを探してオープンし、テキストを読み取り、 各フォームを評価し、そしてファイルをクローズします。

ロード関数は、関数eval-current-bufferがバッファ内の すべての式を評価するように、ファイル内のすべての式を評価します。 異なる点は、ロード関数は、Emacsバッファ内のテキストではなく ディスク上のファイル内のテキストを読み取って評価することです。

ロードするファイルには、Lisp式のソースコードかバイトコンパイル済みコードが 入っている必要があります。 ファイルの各フォームをトップレベルのフォーム(top-level form)と 呼びます。 ロード可能なファイル内のフォーム向けの特別な書式はありません。 ファイル内のどんなフォームでも、バッファに直接打ち込んで評価できます。 (もちろん、ほとんどのコードはこのようにして試したはず。) ほとんどの場合、フォームは関数定義や変数定義です。

Lispコードを収めたファイルをしばしばライブラリ(library)と呼びます。 したがって、『rmailライブラリ』は、rmailモード用のコードを収めたファイルです。 同様に、『Lispライブラリディレクトリ』は、 Lispコードを収めたファイルのディレクトリです。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

14.1 プログラムからのロード方法

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=How%20Programs%20Do%20Loading"
"texi/elisp21/プログラムからのロード方法"へのコメント(無し)

Emacs Lispには、ロードのためのインターフェイスがいくつかあります。 たとえば、autoloadは、 ファイルで定義された関数向けに場所を確保するオブジェクトを作成します。 自動ロードする関数を呼び出すと、 ファイルの実際の定義を得るためにファイルをロードします(see 節 14.4 自動ロード)。 requireは、ファイルをすでにロードしていなければロードします (see 節 14.6 機能)。 これらの機構はすべて、最終的には、関数loadを呼び出して動作します。

Function: load filename &optional missing-ok nomessage nosuffix must-suffix
この関数は、Lispコードのファイルを探してオープンし、 その中のフォームすべてを評価してから、ファイルをクローズする。

ファイルを探すために、 loadはまず`filename.elc'という名前のファイル、 つまり、filenameに`.elc'を付加した名前のファイルを探す。 そのようなファイルが存在すれば、それをロードする。 そのような名前のファイルがなければ、 loadは`filename.el'という名前のファイルを探す。 そのファイルが存在すれば、それをロードする。 いずれの名前のファイルもみつからなければ、 最終的に、loadは、なにも付加しないfilenameという名前のファイルを 探し、存在すればそれをロードする。 (関数loadfilenameを探す手順は賢くない。 (load "foo.el")を評価すると、 `foo.el.el'という名前のファイルを探してしまう。)

省略可能な引数nosuffixnil以外であれば、 `.elc'と`.el'の接尾辞を試さない。 この場合、目的のファイルの正確な名前を指定する必要がある。 正確なファイル名を指定し、かつ、nosuffixtを使えば、 `foo.el.el'のようなファイル名を探してしまうことを防げる。

省略可能な引数must-suffixnil以外であれば、 loadは、ディレクトリ名を明示していない限り、 ファイル名は`.el'か`.elc'で終るものと仮定する。 filenameにディレクトリ名が明示してなく、かつ、 接尾辞も指定してなければ、loadは接尾辞を必ず付加する。

filenameが`foo'や`baz/foo.bar'のように 相対ファイル名であると、loadは変数load-pathを使って ファイルを探す。 filenameload-pathに指定した各ディレクトリを付加し、 最初にみつかったファイルをロードする。 デフォルトディレクトリを表すnilload-pathに 指定されている場合に限り、カレントディレクトリを試す。 loadは、まず最初のディレクトリで3つの可能な接尾辞を試し、 続いて2番目のディレクトリで3つの可能な接尾辞を試し、 というように行う。 see 節 14.2 ライブラリの探索

`foo.elc'が`foo.el'より古いという旨の警告を受け取った場合には、 `foo.el'の再コンパイルを考えるべきである。 see 節 15. バイトコンパイル

(コンパイルしていない)ソースファイルをロードするときには、 Emacsがファイルを訪問する場合と同様に、 loadは文字集合を変換する。 see 節 32.10 コーディングシステム

nomessagenilであると、 ロード中にはエコー領域に `Loading foo...'や`Loading foo...done'のメッセージを表示する。

ファイルをロード中に処理できないエラーに出会うと、ロードを終了する。 autoloadによるロードの場合には、 ロード中に行われた関数定義はすべてもとに戻す。

loadがロードすべきファイルをみつけられないと、 普通、(`Cannot open load file filename'を伴った) エラーfile-errorを通知する。 missing-oknil以外であれば、 loadnilを返すだけである。

変数load-read-functionを使って、 式を読み取るためにreadのかわりにloadが使う関数を指定できる。 下記参照。

ファイルを正しくロードできるとloadtを返す。

コマンド: load-file filename
このコマンドはファイルfilenameをロードする。 filenameが相対ファイル名であると、 現在のデフォルトディレクトリを仮定する。 load-pathを使わず、接尾辞も付加しない。 ロードするファイル名を正確に指定したい場合にこのコマンドを使う。

コマンド: load-library library
このコマンドは、libraryという名前のライブラリをロードする。 loadと等価であるが、引数を対話的に読み取る点が異なる。

Variable: load-in-progress
Emacsがファイルをロード処理中であると、 この変数はnil以外であり、さもなければnilである。

Variable: load-read-function
この変数は、loadeval-regionが、 readのかわりに使う、式を読み取る関数を指定する。 その関数はreadと同様に引数を1つとること。

通常、この変数の値はnilであり、 これらの関数がreadを使うことを意味する。

注意: この変数を使うかわりに、eval-regionの引数read-functionとして 関数を渡す新しい別の機能を使ったほうが見通しがよい。 see 節 8.4 評価(eval)

Emacs構築時のloadの使い方についての情報は、 See 節 C.1 Emacsの構築方法



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

14.2 ライブラリの探索

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Library%20Search"
"texi/elisp21/ライブラリの探索"へのコメント(無し)

EmacsがLispライブラリをロードするときには、 変数load-pathで指定したディレクトリ群でライブラリを探します。

User Option: load-path
この変数の値は、loadでファイルをロードするときに探索する ディレクトリのリストである。 各要素は、(ディレクトリ名である)文字列か (カレント作業ディレクトリを表す)nilである。

load-pathの値は、環境変数EMACSLOADPATHがあれば、 それで初期化します。 さもなければ、デフォルト値は、 Emacsを構築したときに`emacs/src/paths.h'で指定したものです。 そして、リスト内のディレクトリのサブディレクトリをリストに追加して 拡張します。

EMACSLOADPATHの構文はPATHと同じです。 `:'(オペレーティングシステムによっては`;')で ディレクトリ名を区切ります。 デフォルトのカレントディレクトリには`.'を使います。 cshの`.login'ファイルで環境変数EMACSLOADPATHを 指定する例はつぎのとおりです。

 
setenv EMACSLOADPATH .:/user/bil/emacs:/usr/local/share/emacs/20.3/lisp

shを使っている場合はつぎのようにします。

 
export EMACSLOADPATH
EMACSLOADPATH=.:/user/bil/emacs:/usr/local/share/emacs/20.3/lisp

`.emacs'ファイルで、 デフォルトのload-pathの先頭に複数のディレクトリを追加するには、 つぎのようなコードを書きます。

 
(setq load-path
      (append (list nil "/user/bil/emacs"
                    "/usr/local/lisplib"
                    "~/emacs")
              load-path))

この例では、Lispコードを、まずカレント作業ディレクトリで探索し、 続いて、`/user/bil/emacs'ディレクトリ、 `/usr/local/lisplib'ディレクトリ、`~/emacs'ディレクトリ、 さらに、標準のディレクトリで探索します。

Emacsのダンプには、load-pathの特別な値を使います。 ダンプ終了時にload-pathの値が未変更(つまり、同じ特別な値)であれば、 ダンプ版Emacsは起動時に、上に述べたように、普通のload-pathの値を 使います。 しかし、ダンプ終了時にload-pathの値が別の値であれば、 ダンプ版Emacsの実行でもその(別の)値を使います。

したがって、`site-init.el'や`site-load.el'で 少数のライブラリをロードするために 一時的にload-pathを変更したい場合には、 loadの呼び出しをletで囲んで load-pathをローカルに束縛するべきです。

システムにインストールしたEmacsを実行中は、 load-pathのデフォルト値には、2つの特別なディレクトリ (とそれらのサブディレクトリ)が含まれます。

 
"/usr/local/share/emacs/version/site-lisp"

 
"/usr/local/share/emacs/site-lisp"

です。 前者は、Emacsの特定の版向けにローカルにインストールしたパッケージ用です。 後者は、Emacsの任意の版向けにローカルにインストールしたパッケージ用です。

Emacsのある版向けのパッケージが別の版ではトラブルを引き起こす理由は いくつかあります。 Emacsの互換性のない変更のために更新を必要とするパッケージもあります。 予告なしに変更される可能性のある明文化していない Emacsの内部データに依存するものもあります。 Emacsの新しい版では、パッケージの特定の版と一体になっているものもあり、 その版だけで使うべきです。

Emacsは、起動すると、ディレクトリのサブディレクトリを捜し出して、 それらをload-pathに追加します。 直下のサブディレクトリも複数レベル下のサブディレクトリも load-pathに追加します。

しかし、サブディレクトリすべてを含むわけではありません。 英数字で始まらない名前のサブディレクトリは除外します。 `RCS'という名前のサブディレクトリも除外します。 また、`.nosearch'という名前のファイルを置いた サブディレクトリも除外します。 これらの方法を用いれば、`site-lisp'ディレクトリ下の 特定のサブディレクトリの探索を防げます。

Emacsを構築したディレクトリでEmacsを起動すると、 つまり、正式にインストールしてない実行形式を起動すると、 load-pathには、普通、2つのディレクトリを追加します。 主構築ディレクトリのサブディレクトリ、lispsite-lispです。 (どちらも、絶対ファイル名で表される。)

コマンド: locate-library library &optional nosuffix path interactive-call
このコマンドは、ライブラリlibraryの正確なファイル名を探す。 loadと同様にライブラリを探索する。 引数nosuffixの意味はloadと同じであり、 指定した名前libraryに接尾辞`.elc'や`.el'を付加しない。

pathnil以外であると、 それはload-pathのかわりに使うディレクトリのリストである。

locate-libraryをプログラムから呼び出した場合、 文字列でファイル名を返す。 ユーザーがlocate-libraryを対話的に実行した場合、 引数interactive-calltであり、これは locate-libraryに対してファイル名をエコー領域に表示するように指示する。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

14.3 非ASCII文字のロード

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Loading%20Non-ASCII"
"texi/elisp21/非ASCII文字のロード"へのコメント(無し)

Emacs Lispプログラムが非ASCII文字の文字列定数を含む場合、 Emacs内部では、それらはユニバイト文字列かマルチバイト文字列で表現できます (see 節 32.1 テキスト表現)。 どちらの表現形式を用いるかは、 どのようにファイルをEmacsに読み込んだかに依存します。 マルチバイト表現へ復号化して読んだ場合には、 Lispプログラムのテキストはマルチバイトテキストになり、 その文字列定数はマルチバイト文字列になります。 (たとえば)Lantin-1文字を含むファイルを復号化せずに読むと、 プログラムテキストはユニバイトテキストになり、 その文字列定数はユニバイト文字列になります。 See 節 32.10 コーディングシステム

結果をより予測可能にするために、 オプション`--unibyte'を指定して起動した場合であっても、 Lispファイルをロードするときには、 Emacsはつねにマルチバイト表現に復号化します。 つまり、非ASCII文字の文字列定数はマルチバイト文字列に変換します。 唯一の例外は、特定のファイルで無変換を指定した場合だけです。

Emacsをこのように設計したのは、 Emacsの起動方法によらずに、 Lispプログラムが予測可能な結果をもたらすようにするためです。 さらに、こうすることで、ユニバイト動作のEmacsであっても、 マルチバイトテキストを使うことに依存したプログラムが動作します。 もちろん、そのようなプログラムは、 default-enable-multibyte-charactersを検査して適切に表現を変換して、 ユーザーがユニバイトテキストとマルチバイトテキストのどちらを 好んでいるか調べるように設計すべきです。

Emacs Lispのほとんどのプログラムでは、 非ASCII文字列はマルチバイト文字列であるということに 気づかないでしょう。 というのは、それらをユニバイトバッファに挿入すると 自動的にユニバイトに変換するからです。 しかしながら、これで違いがでるならば、 Lispファイルの先頭行のコメントに`-*-unibyte: t;-*-'と書くことで、 特定のLispファイルをユニバイトと解釈するように強制できます。 このように指定すると、マルチバイト動作のEmacsであっても、 そのファイルを無条件にユニバイトと解釈します。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

14.4 自動ロード

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Autoload"
"texi/elisp21/自動ロード"へのコメント(無し)

自動ロード(autoload)機能により、 関数やマクロを定義しているファイルをロードしていなくても、 関数やマクロをLispに登録できます。 関数を初めて呼び出すと、 適切なファイルを読み込んで実際の定義と関連する他のコードを インストールしてから、すでにロードしてあったかのように実際の定義を実行します。

関数を自動的にロードするように設定する方法は2つあります。 autoloadを呼び出すか、あるいは、 ソース内の実際の定義のまえに特別な『マジック』コメントを書きます。 autoloadは自動ロードを行う低レベルの基本関数です。 任意のLispプログラムでいつでもautoloadを呼び出せます。 マジックコメントは、Emacsで使うパッケージ向けに 関数を自動的にロードするように設定するとても便利な方法です。 これらのコメントそのものはなにもしませんが、 コマンドupdate-file-autoloadsに対する指針として働きます。 このコマンドは、autoloadの呼び出しを作成し、 Emacs構築時にそれらを実行するように設定します。

Function: autoload function filename &optional docstring interactive type
この関数は、functionという名前の関数(やマクロ)を filenameから自動的にロードするように定義する。 文字列filenameは、functionの実際の定義を取得するために ロードするファイルを指定する。

filenameにディレクトリ名や接尾辞.el.elcがなければ、 autoloadはこれらの接尾辞の1つを必ず付加し、 接尾辞を付けないfilenameという名前のファイルはロードしない。

引数docstringは、関数に対する説明文字列である。 通常、これは関数定義そのものの説明文字列と同一であること。 autoloadの呼び出しにおいて説明文字列を指定しておくことで、 関数の実際の定義をロードしなくても説明文を見ることが可能になる。

interactivenil以外ならば、 functionを対話的に呼び出せることを意味する。 つまり、関数の実際の定義をロードしなくても M-xの補完が動作するのである。 完全な対話指定を指定しない。 ユーザーがfunctionを実際に呼び出すまでは必要なく、 呼び出し時点で実際の定義をロードするからである。

普通の関数と同様に、マクロやキーマップも自動的にロードできる。 functionが実際にはマクロならば、typeにはmacroを指定する。 functionが実際にはキーマップならば、 typeにはkeymapを指定する。 Emacsのさまざまな部分では、 実際の定義をロードせずにこの情報を知る必要がある。

自動ロードと指定したキーマップは、 プレフィックスキーのバインディングがシンボルfunctionであるときに、 キーを探す過程で自動的にロードする。 キーマップのこれ以外の参照方法では、自動的にロードしない。 特に、変数名がシンボルfunctionと同じであっても、 Lispプログラムで変数の値からキーマップを取得して define-keyを呼び出す場合には、自動的にロードしない。

functionが自動ロードオブジェクトではない 空でない関数定義を有する場合には、 autoloadはなにもせずにnilを返す。 functionの関数セルが空であったり、 すでに自動ロードオブジェクトである場合には、 つぎのような自動ロードオブジェクトとして関数セルを定義する。

 
(autoload filename docstring interactive type)

たとえばつぎのとおり。

 
(symbol-function 'run-prolog)
     => (autoload "prolog" 169681 t nil)

この場合、"prolog"はロードすべきファイルの名前であり、 169681はファイル`emacs/etc/DOC-version' (see 節 23.1 説明文の基本)内の説明文字列を指す。 tは関数が対話的であることを示し、 nilはマクロでもキーマップでもないことを示す。

自動ロード対象のファイルでは、通常、他の定義や 複数の機能を提供したり必要としたりします。 (その内容の評価中のエラーなどで)ファイルを完全にロードできないと、 ロード中に行った関数定義やprovideの呼び出しをもとに戻します。 そのファイルから自動ロードする任意の関数をつぎに呼び出そうとしたときに、 そのファイルを再度ロードすることを保証するためです。 こうしておかないと、 自動ロードをアボートしたファイルで関数が定義されても、 そのファイルのうしろの部分で定義される その関数に必要なサブルーティンが必ずしもロードされないために その関数が動作しない可能性があるからです。

自動ロード対象のファイルで必要なLisp関数やマクロの定義に失敗すると、 "Autoloading failed to define function function-name"を 伴ったエラーを通知します。

自動ロードを指定するマジックコメントは、 `;;;###autoload'だけを書いた行であり、 自動ロード対象のソースファイル上で実際の関数定義の直前に必要です。 コマンドM-x update-file-autoloadsは、 対応するautoload呼び出しを`loaddefs.el'に書き込みます。 Emacs構築時には`loaddefs.el'をロードするので、 autoloadを呼び出します。 M-x update-directory-autoloadsはもっと強力で、 カレントディレクトリのすべてのファイルに対する自動ロード情報を更新します。

同じマジックコメントは、任意の種類のフォームを`loaddefs.el'に コピーできます。 マジックコメントに続くフォームが関数定義でない場合、 そのフォームをそのままコピーします。 構築時にはフォームを実行しても、 ファイルのロード時にはそのフォームを実行しないように マジックコメントを使うこともできます。 そうするには、マジックコメントと同じ行にそのフォームを書きます。 するとそれはコメントなので、ソースファイルをロードするときにはなにもしません。 一方、M-x update-file-autoloadsはそのフォームを`loaddefs.el'に コピーするので、Emacs構築時には実行されるのです。

つぎの例は、マジックコメントを使ってdoctorを自動ロードする方法です。

 
;;;###autoload
(defun doctor ()
  "Switch to *doctor* buffer and start giving psychotherapy."
  (interactive)
  (switch-to-buffer "*doctor*")
  (doctor-mode))

こうすると、`loaddefs.el'ではつぎのようになります。

 
(autoload 'doctor "doctor"
  "\
Switch to *doctor* buffer and start giving psychotherapy."
  t)

ダブルクォートの直後にバックスラッシュや改行を書く慣習は、 `loaddefs.el'などの あらかじめロードするLispファイルの中だけで使うものです。 これは、make-docfileに対して、 説明文字列を`etc/DOC'ファイルに書くように指示します。 See 節 C.1 Emacsの構築方法



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

14.5 ロードの繰り返し

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Repeated%20Loading"
"texi/elisp21/ロードの繰り返し"へのコメント(無し)

1つのEmacsセッションにおいて、あるファイルを複数回ロードできます。 たとえば、バッファ内の関数定義を編集して、 関数定義を書き直してインストールし直したあとで、 もとの版に戻したいこともあるでしょう。 これには、もとのファイルを再ロードすればよいのです。

ファイルをロードしたり再ロードするとき、 関数loadload-libraryは、 コンパイルしていないファイルではなく、 バイトコンパイル済みのファイルを自動的にロードすることに注意してください。 ファイルを書き直して保存してから再インストールする場合、 新しい版をバイトコンパイルする必要があります。 さもないと、Emacsは、新しいコンパイルしていないファイルではなく、 バイトコンパイル済みの古いファイルをロードしてしまいます。 そのような場合、ファイルをロードすると、 `(compiled; note, source is newer)'とメッセージを表示して、 再コンパイルするように忠告してきます。

Lispライブラリファイルにフォームを書くときには、 ファイルを複数回ロードする可能性があることを忘れないでください。 たとえば、ライブラリを再ロードするたびに 各変数を再初期化すべきかどうか考えましょう。 defvarは、初期化済みの変数の値を変更しません。 (see 節 10.5 グローバル変数を定義する。)

連想リストに要素を追加するもっとも簡単な方法はつぎのとおりです。

 
(setq minor-mode-alist
      (cons '(leif-mode " Leif") minor-mode-alist))

しかし、これでは、ライブラリを再ロードすると、 複数の要素を追加してしまいます。 これを避けるにはつぎのようにします。

 
(or (assq 'leif-mode minor-mode-alist)
    (setq minor-mode-alist
          (cons '(leif-mode " Leif") minor-mode-alist)))

リストに要素を1回だけ追加するには、 add-to-list(see 節 10.8 変数値の変更)も使えます。

ライブラリをすでにロードしたかどうか明示的に調べたいこともあるでしょう。 ライブラリ内で以前ロードされたかどうか検査する方法の1つは、 つぎのとおりです。

 
(defvar foo-was-loaded nil)

(unless foo-was-loaded
  execute-first-time-only
  (setq foo-was-loaded t))

ライブラリで名前付き機能を提供するためにprovideを使っていれば、 ファイルの始めのほうでfeaturepを使って、 provideを以前呼び出したかどうか検査できます。 See 節 14.6 機能



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

14.6 機能

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Named%20Features"
"texi/elisp21/機能"へのコメント(無し)

providerequireは、 ファイルを自動的にロードするためのautoloadの代替手段です。 それらは指定した機能(features)という考え方で動作します。 自動ロードは特定の関数を呼び出すことで起動しますが、 機能はその名前でプログラムが最初に要求したときにロードします。

機能名は、関数や変数などの集合を表すシンボルです。 それらを定義するファイルでは、その機能を提供(provide)します。 それらを使う別のプログラムでは、 その機能を要求(require)することで、 それらが定義されることを確実にします。 こうすると、未ロードであれば定義しているファイルをロードします。

機能を要求するには、機能名を引数にしてrequireを呼び出します。 requireは、グローバル変数featuresを調べて、 目的の機能がすでに提供されているかどうか調べます。 提供されていなければ、適当なファイルから機能をロードします。 このファイルでは、トップレベルでprovideを呼び出して、 featuresに機能を追加するべきです。 そうしないと、requireはエラーを通知します。

たとえば、`emacs/lisp/prolog.el' には、 つぎのコードのようなrun-prologの定義が入っています。

 
(defun run-prolog ()
  "Run an inferior Prolog process, with I/O via buffer *prolog*."
  (interactive)
  (require 'comint)
  (switch-to-buffer (make-comint "prolog" prolog-program-name))
  (inferior-prolog-mode))

(require 'comint)は、ファイル`comint.el'が未ロードであると、 そのファイルをロードします。 これにより、make-comintが定義済みであることを保証します。 普通、機能には、その機能を提供するファイル名からとった名前を付けますから、 requireにファイル名を指定する必要はありません。

`comint.el'ファイルには、つぎのトップレベルの式が入っています。

 
(provide 'comint)

これにより、グローバル変数featuresのリストに comintが追加されるので、 これ以降に(require 'comint)を実行しても、 なにもしないでよいことになります。

ファイルのトップレベルでrequireを使うと、 そのファイルをロードする場合と同様に、 そのファイルをバイトコンパイルするとき(see 節 15. バイトコンパイル)にも requireには効果があります。 要求したパッケージに、 バイトコンパイラが知っている必要があるマクロが入っている場合です。

トップレベルのrequireの呼び出しは、 バイトコンパイル中に評価されますが、 provideの呼び出しは評価しません。 したがって、つぎの例のように、 同じ機能に対するprovideに続けてrequireを書くことで、 バイトコンパイルするまえに定義のファイルをロードすることを確実にできます。

 
(provide 'my-feature)  ; バイトコンパイラは無視し、
                       ;   loadは評価する
(require 'my-feature)  ; バイトコンパイラは評価する

コンパイラはprovideを無視し、 続くrequireの処理では当該ファイルをロードします。 ファイルのロード時にはprovideの呼び出しを実行するので、 そのあとのrequireの呼び出しは、 ファイルをロードするときにはなにもしません。

Function: provide feature
この関数は、機能featureをロードし終えたこと、あるいは、 ロード中であることを現在のEmacsセッション内で宣言する。 つまり、featureに関連した機能が他のLispプログラムから利用できることを 意味する。

provideの呼び出しの直接の効果は、 featureがリストfeaturesに入っていなければ、 featureをリストfeaturesの先頭に入れることである。 引数featureはシンボルであること。 providefeatureを返す。

 
features
     => (bar bish)

(provide 'foo)
     => foo
features
     => (foo bar bish)

自動ロードによってファイルをロードしているとき、 その内容を評価することでエラーになってロードを中止すると、 ロード中に行われた関数定義やprovideの呼び出しはもとに戻す。 see 節 14.4 自動ロード

Function: require feature &optional filename
この関数は((featurep feature)を使って) 現在のEmacsセッション内にfeatureが存在するかどうか調べる。 引数featureはシンボルであること。

機能が存在していなければ、requireは、 loadを使ってfilenameをロードする。 filenameを指定しないと、シンボルfeatureの名前を ロードすべきファイル名の基にする。 しかしながら、この場合には、requireは、 接尾辞を必ず付加してfeatureを探す。 featureだけの名前のファイルは探さない。

featureを提供するファイルのロードに失敗すると、 requireはエラー `Required feature feature was not provided'を通知する。

Function: featurep feature
この関数は、現在のEmacsセッションでfeatureが提供されていれば (つまり、featurefeaturesのメンバであれば) tを返す。

Variable: features
この変数の値は、 現在のEmacsセッションにロード済みの機能を表すシンボルのリストである。 各シンボルは、provideを呼び出すことでこのリストに追加される。 リストfeatures内の要素の順番は関係ない。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

14.7 アンロード

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Unloading"
"texi/elisp21/アンロード"へのコメント(無し)

ライブラリでロードした関数や変数を捨てさって 他のLispオブジェクト向けにメモリを回収することができます。 そうするには関数unload-featureを使います。

コマンド: unload-feature feature &optional force
このコマンドは、featureを提供するライブラリをアンロードする。 つまり、当該ライブラリにおいて、defundefaliasdefsubstdefmacrodefconstdefvardefcustomで定義した関数、マクロ、変数すべてを未定義にする。 そうして、これらのシンボルに以前設定してあった自動ロードの設定を復元する。 (ロード時に、これらをシンボルの属性autoloadに保存している。)

以前の定義に復元するまえに、unload-featureremove-hookを 実行して、ライブラリ内の関数を特定のフックから取り除く。 これらのフックは、`-hook'や`-hooks'で終る名前の変数、および、 loadhist-special-hooksに入っているものである。 これは、重要なフックにおいて存在しない関数を参照することで Emacsが動作不能になるのを防ぐ。

これらの処置でも誤動作防止には不十分であるときには、 ライブラリで明示的なアンロードフックを定義できる。 feature-unload-hookを定義してあると、 以前の定義を復元するまえに、 フックを削除する通常の動作のかわりに このフックをノーマルフックとして実行する。 アンロードフックでは、 ライブラリをいったんアンロードすると動作不能になるような ライブラリで変更したグローバルな状態をすべてアンドゥすべきである。

通常、unload-featureは、他のライブラリが依存している ライブラリのアンロードは拒否する。 (ライブラリabrequire(要求)していると、 ライブラリaはライブラリbに依存している。) 省略可能な引数forcenil以外であると、 依存関係を無視し、任意のライブラリをアンロードできる。

関数unload-featureはLispで書いてあり、 その動作はload-historyに基づきます。

Variable: load-history
この変数の値は、ライブラリ名をそのライブラリが定義する関数や変数の名前、 そのライブラリが提供する機能、そのライブラリが要求する機能に対応付ける 連想リストである。

各要素はリストであり、1つ1つが1つのライブラリを記述する。 リストのCARは文字列であり、ライブラリ名である。 リストの残りは、以下の種類のオブジェクトから成る。

load-historyの値には、CARがnilであるような 1つの要素があってもよい。 この要素は、ファイルを訪問してないバッファ内でeval-bufferによって 作られた定義であることを示す。

コマンドeval-regionload-historyを更新しますが、 訪問先ファイルに対応する要素に、定義されるシンボルを追加するのであって、 要素を置き換えるのではありません。

あらかじめロード済みのライブラリは、load-historyに寄与しません。

Variable: loadhist-special-hooks
この変数は、ライブラリ内で定義された関数を削除するために ライブラリをアンロードするまえに走査するフックのリストを保持する。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

14.8 ロード時のフック

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Hooks%20for%20Loading"
"texi/elisp21/ロード時のフック"へのコメント(無し)

eval-after-loadを呼び出すと、 特定のライブラリをロードする/してあるときに実行するコードを指定できます。

Function: eval-after-load library form
この関数は、ライブラリlibraryをロードする/してあるときに、 ライブラリlibraryのロードの最後にformを評価するように設定する。 libraryをすでにロードしてあると、 この関数はformをただちに評価する。

ライブラリ名libraryloadの引数に正確に一致する必要がある。 load-pathを探索してインストールするライブラリを探したときに 正しい結果を得るために、libraryにはディレクトリ名を含めないこと。

formでエラーが発生してもロード処理をもとに戻さないが、 formの残りは実行しない。

一般に、よく設計されたLispプログラムはこの機能を使うべきではありません。 Lispライブラリを見通しよくモジュール化して扱うには、 (1)ライブラリの(外部から使うことを意図した)変数を調べて設定し、 (2)ライブラリの関数を呼び出すことです。 (1)を行いたければ、すぐにしてかまいません。 ライブラリをロードするまで待つ必要はありません。 (2)を行うには、ライブラリをロードする必要があります (requireで行うことが好ましい)。

広く使われるプログラムに対する設計基準に合わなくても、 個人のカスタマイズでeval-after-loadを使うのはかまいません。

Variable: after-load-alist
特定のライブラリをロードする/してあるときに評価する式の連想リスト。 各要素はつぎのとおり。

 
(filename forms...)

関数loadは、eval-after-loadを実現するために after-load-alistを調べる。


[ << ] [ >> ]           [表紙] [目次] [索引] [検索] [上端 / 下端]