autoloadと4種類のロード

EmacsのLispパッケージのロード方法について、あまり周知されてないので書きます。まちがったことを書いてたらごめんね。日本語での説明は@ayatakesiさんの`【途中】emacs 24.5のelisp日本語マニュアル`より引用します[^1]。

## TL;DR

 * `package.el`とかEl-Getを使ってるなら、`init.el` から、ほとんどの `(require 'hoge)` は消しちゃっても動くと思うよ
 * あなたがLispパッケージ作者なら、依存関係はオートロードを期待せずに`(require 'hoge)`は列挙しないとだめだよ

## 0. `load-path`

`load-path`は、EmacsがLispファイルを読み込むディレクトリ一覧の変数です。もし`package.el`やEl-Getのようなパッケージ管理ツールだけを利用する場合は、**この変数を操作する必要はありません**。

管理ツールを利用せず手動でLispパッケージをダウンロードして個別のディレクトリをロード対象に追加したければ、`(add-to-list 'load-path "/path/to/php-mode")`のように書きます。もしダウンロードしたLispパッケージを一箇所のディレクトリにまとめてあるのであれば、以下のように記述すると、まとめて`load-path`に追加できます。

以下は、`~/.emacs.d/lisp`ディレクトリに複数のパッケージをダウンロードして配置する例です。

```init.el
(let ((default-directory (locate-user-emacs-file "./lisp")))
  (add-to-list 'load-path default-directory)
  (normal-top-level-add-subdirs-to-load-path))
```

蛇足ですが、`normal-top-level-add-subdirs-to-load-path`は`(let ((default-directory ...)) ...)`で括ることで挙動が変化します。これはEmacs Lispの変数がダイナミックスコープ(動的束縛)である如実な特徴です。

## 1. `(require 'feature)`

これはもっともよく目にしますが、`init.el`に書く必要は**ほとんど**ありません。後述しますが、`(package-initialize)`などを実行する前に必要なファイルは必要です。

これは、Lispファイルを**フィーチャ**(feature, 機能)の単位で管理して、「一回だけ」読み込むようにするものです。

>     Function: require feature &optional filename noerror
>
> この関数はカレントEmacsセッションにおいて、featureが存在するかどうかを、(`(featurep feature)`を使用して。以下を参照)をチェックします。引数*feature*はシンボルでなければなりません。
>
> そのフィーチャが存在しない場合、`require`は`load`により*filename*をロードします。*filename*が与えられなかった場合は、シンボル*feature*の名前がロードするファイル名のベースとして使用されます。しかしこの場合、`require`は*feature*を探すためにサフィックス‘.el’および‘.elc’の追加を強制します(圧縮ファイルのサフィックスに拡張されるかもしれません)。名前がただの*feature*というファイルは使用されません。(変数`load-suffixes`は要求されるLispサフィックスを正確に指定します。)
>
> *noerror*が非`nil`の場合は、ファイルの実際のロードにおけるエラーを抑止します。この場合、そのファイルのロードが失敗すると、`require`は`nil`をリターンします。通常では、`require`は*feature*をリターンします。
>
> ファイルのロードは成功したが*feature*をプロバイドしていない場合、`require`は‘Required feature feature was not provided’のようにエラーをシグナルします。

*[15.7 Features](https://ayatakesi.github.io/emacs/24.5/elisp.html#Named-Features) (2018年3月26日閲覧) より引用。*

`(require 'hoge)`した場合、`load-path`に含まれるディレクトリの**どこか**に`hoge.elc`, `hoge.el`(動的モジュールが有効な環境では `hoge.so`など)があれば、それを読み込み、なかったらエラーが発生します。

「機能があったら読み込んで、なくてもエラーにしない」場合は、`(require 'hoge nil t)`にします。あなたがLispパッケージ作者なら、必須ではないパッケージの読み込みにも利用できます。

一般的なLispパッケージでは、ファイルの冒頭に`(require)`を記述します。依存パッケージのうち特定の関数でしか利用せず、その関数を起動するまでは必要ないようなフィーチャは、後述する`autoload`で書くと良いでしょう。

## 2. `(load "file")`

ファイル名のフルパス`"/path/to/hoge.el"`を渡した場合は直接そのファイルを、ファイル名だけを`"hoge"`のように指定した場合は、`load-path`から`hoge.el`や`hoge.elc`を探し出します。

低レベルな関数なので、直接利用すべき場面は、あまりありません。一般的なパッケージの読み込みには`(load)`ではなく`(require)`を利用します。

## 3. `(autoload 'func "file")`

**オートロード**は関数名(または、キーマップとマクロ)の名前と定義ファイルの名前の対応を登録して、必要になったとき(関数の実行時)までファイルの読み込みを**遅延させる**機能です。

この機能は、基本的にはパッケージ管理ツールが自動で読み込んでくれる`*-autoloads.el`の中に記述されます。パッケージ管理ツールを利用する場合は`init.el`などに**手作業で定義する必要はありません**。

オートロードは便利ですが、**(自動生成されるものを除いて)**関数ひとつひとつを手作業で登録する必要があるので管理が煩雑になります。読み込み時間が体感できるほど巨大なパッケージを除いて、素直に`(require)`を書くのが良いでしょう。

## 4. `*-autoloads.el`

このファイルはパッケージ管理ツールがインストール時に自動生成して、Emacs起動時に自動で読み込むファイルです。

典型的には以下のような定義が含まれます。

* 関数の実行前に必要な変数定義
* 関数(コマンド・メジャーモード・マイナーモード)・マクロの`autoload`
* `auto-mode-alist` ([ファイル名とメジャーモードの関連付け](https://qiita.com/tadsan/items/a21c268021b46b8a6b33))

例として`php-mode.elc`がロードされと159KBの読み込みが発生しますが、`php-mode-autoloads.el`は4KB程度で済むのでEmacs初期化完了までの負荷が軽減されるといった仕組みです。

あなたがLispパッケージ作者ならば、関数定義や変数定義の上の行に`;;;###autoload`と書いてやるだけで、パッケージ管理ツールが適切に自動生成してくれます。

パッケージ管理ツールを使用しない場合は`update-file-autoloads`などを利用することで手動生成することもできます… が、ちょっとめんどくさいのでオススメ度はあまり高くありません。

## つまりどうすればいいの

`package.el`はべんり。

## 脚注

[^1]: この翻訳は作業中のため、リンク切れになる可能性があります。