目次 / 第1回 第2回 第3回 第4回 第5回 第6回 第7回 第8回 第9回
本項は、ネット上から *.el をダウンロードして、いろいろ試したくなってきたあたりで読むと良いと思います。load-path の仕組みを理解しましょう。
load-path とは何か?
UNIX や Windows 等に存在する「環境変数 PATH」の Emacs 版です。
例えば ls を実行すると、「環境変数 PATH」に登録された最初のディレクトリから ls が検索され、最初にヒットした ls が使われますよね?
また、どのディレクトリにも ls が存在しなければ、
command not found: ls
などといったエラーが発生します。
Emacs では例えば ~/.emacs に以下のようなコードを書くと load-path が参照されます。
(require 'hoge)
load-path は Emacs Lisp の変数です。どんな値が入っているのかは第3回 の方法で調べられます。
load-path には複数のディレクトリが登録されているはずです。
まず先頭のディレクトリについて、以下の順で検査が行われます。第2回 の .emacs と同じですね。
- hoge.elc が存在するか?
- hoge.el が存在するか?
- hoge が存在するか?
1, 2, 3 のどれにも当てはまらなければ、次のディレクトリが検査されます。
全てのディレクトリで当てはまらなければ、以下のエラーが発生します。
Cannot open load file: hoge
load-path を構成するディレクトリ
デフォルトの設定では、以下の順番に構成されているはずです。
<PREFIX>/share/emacs/<EMACS-VERSION>/site-lisp
以下全てのディレクトリ<PREFIX>/share/emacs/site-lisp
以下全てのディレクトリ<PREFIX>/share/emacs/<EMACS-VERSION>/lisp
以下全てのディレクトリ
Emacs-22.3 を /usr/local 以下にインストールした場合は、このようになります。
/usr/local/share/emacs/22.3/site-lisp
以下全てのディレクトリ/usr/local/share/emacs/site-lisp
以下全てのディレクトリ/usr/local/share/emacs/22.3/lisp
以下全てのディレクトリ
1 は当該バージョンの Emacs だけに参照させたい *.el を置くディレクトリです。デフォルトでは subdirs.el というファイルだけが置かれています。(subdirs.el は後で説明するので、覚えておいて下さい。)
2 は全てのバージョンの Emacs から参照させたい *.el を置くディレクトリです。ここにも、デフォルトでは subdirs.el というファイルだけが置かれています。
3 は当該バージョンの Emacs に付属する、全ての *.el が置かれているディレクトリです。
load-path が構築される仕組み
<PREFIX>/share/emacs/site-lisp
以下に適当な名前のディレクトリを作って、Emacs を再起動してみて下さい。追加したディレクトリが load-path に追加されていますよね。なぜでしょう?
Emacs は起動時に以下の 3 つの subdirs.el を評価します。
<PREFIX>/share/emacs/<EMACS-VERSION>/site-lisp/subdirs.el
<PREFIX>/share/emacs/site-lisp/subdirs.el
<PREFIX>/share/emacs/<EMACS-VERSION>/lisp/subdirs.el
1 と 2 の subdirs.el の内容は同じで、以下のように記載されているはずです。
(if (fboundp 'normal-top-level-add-subdirs-to-load-path)
(normal-top-level-add-subdirs-to-load-path))
この Emacs Lisp 式の意味は「normal-top-level-add-subdirs-to-load-path という関数が存在すれば、normal-top-level-add-subdirs-to-load-path を実行する」になります。
normal-top-level-add-subdirs-to-load-path() はディレクトリを再帰的に探索し、見つかったディレクトリを load-path に追加する関数です。ただし、以下のディレクトリは load-path に追加しません。
- “.” で始まるディレクトリ
- “RCS” “CVS” “rcs” “cvs” という名前のディレクトリ
- “.nosearch” というファイルが存在するディレクトリ
3 の subdirs.el には Emacs-22.3 の場合、以下のように記載されているはずです。
(normal-top-level-add-to-load-path
'("url" "textmodes" "progmodes" "play" "obsolete" "net" "mh-e" "mail" "language"
"international" "gnus" "eshell" "erc" "emulation" "emacs-lisp" "calendar" "calc"))
まあ、だいたい意味は分かりますよね。(説明するのが面倒になってきました..。^^;)
load-path にユーザ指定のディレクトリを追加する方法
root 権限を持っていない等の理由から、前述の site-lisp 以下に *.el をコピーできない場合もあるでしょう。その場合は、load-path にディレクトリを追加します。
例えば、"~/share/elisp" を追加したい場合は以下を ~/.emacs に設定して下さい。
(add-to-list 'load-path "~/share/elisp")
この例では load-path の先頭に “~/share/elisp” が追加されます。
ユーザ指定のディレクトリ以下全てを load-path に追加する方法
上の方法だと、~/share/elisp 以下にディレクトリを追加するたびに add-to-list() を追加する必要があり、少々面倒です。そこで前述の normal-top-level-add-subdirs-to-load-path を利用します。
先にコードを晒します。
(defconst my-elisp-directory "~/share/elisp" "The directory for my elisp file.")
(dolist (dir (let ((dir (expand-file-name my-elisp-directory)))
(list dir (format "%s%d" dir emacs-major-version))))
(when (and (stringp dir) (file-directory-p dir))
(let ((default-directory dir))
(add-to-list 'load-path default-directory)
(normal-top-level-add-subdirs-to-load-path))))
このコードを ~/.emacs に設定すると、load-path の先頭に以下の順番で追加されます。
~/share/elisp<emacs-major-version>
以下全てのディレクトリ~/share/elisp
以下全てのディレクトリ
使用している Emacs のバージョンが 22.3 の場合、<emacs-major-version>
は 22 になります。変数 my-elisp-directory は適宜変更して下さい。
require 以外の *.el 読み込み方法
require は、ファイル中に (provide ‘hoge) などと書かれている *.el を読み込む関数です。そうすることで、require 済みかを以下の方法で判別できます。
(if (featurep 'hoge)
...)
また、(require ‘hoge) は何度実行しても、hoge.el は一度しか読み込まれません。
require と似たものに load があります。featurep() による検査は行えません。load すると、安直に hoge.el が load されます。
(load "hoge")
少し特殊なものに autoload があります。この式が評価された時点では hoge.el は読み込まれません。hogehoge という関数が実行された直後に hoge.el が読み込まれ、その後 hogehoge() が実行されます。
(autoload 'hogehoge "hoge" nil t)
他、load-file という関数もあります。M-x load-file を実行し、読み込みたいファイルを指定すると、そのファイルが load されます。つまり、load-path とは直接関係ありません。
関連する関数
load-path に関連する関数をご紹介します。それぞれ M-x で呼び出せます。
- locate-library
- 指定した *.el の場所をフルパスで出力する。
- list-load-path-shadows
- *.el の名前が同じであるため、load されない *.el を表示する。
第6回終わり。