目次 / 第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 と同じですね。

  1. hoge.elc が存在するか?
  2. hoge.el が存在するか?
  3. hoge が存在するか?

1, 2, 3 のどれにも当てはまらなければ、次のディレクトリが検査されます。

全てのディレクトリで当てはまらなければ、以下のエラーが発生します。

Cannot open load file: hoge

load-path を構成するディレクトリ

デフォルトの設定では、以下の順番に構成されているはずです。

  1. <PREFIX>/share/emacs/<EMACS-VERSION>/site-lisp 以下全てのディレクトリ
  2. <PREFIX>/share/emacs/site-lisp 以下全てのディレクトリ
  3. <PREFIX>/share/emacs/<EMACS-VERSION>/lisp 以下全てのディレクトリ

Emacs-22.3 を /usr/local 以下にインストールした場合は、このようになります。

  1. /usr/local/share/emacs/22.3/site-lisp 以下全てのディレクトリ
  2. /usr/local/share/emacs/site-lisp 以下全てのディレクトリ
  3. /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 を評価します。

  1. <PREFIX>/share/emacs/<EMACS-VERSION>/site-lisp/subdirs.el
  2. <PREFIX>/share/emacs/site-lisp/subdirs.el
  3. <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 の先頭に以下の順番で追加されます。

  1. ~/share/elisp<emacs-major-version> 以下全てのディレクトリ
  2. ~/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回終わり。

目次 / 第1回 第2回 第3回 第4回 第5回 第6回 第7回 第8回 第9回