GNU Emacs 32.0.50 (9008bf64c3) のマニュアルを PLaMo 翻訳で機械翻訳したものです。誤訳を含むことがあります。原文: https://www.gnu.org/software/emacs/manual/html_node/elisp/Module-Initialization.html ・ emacs-doc.conao3.com

E.7.1 モジュール初期化コード

モジュールの冒頭で、ヘッダーファイル emacs-module.h をインクルードし、GPL互換性シンボルを定義してください:

#include <emacs-module.h>

int plugin_is_GPL_compatible;

emacs-module.h ファイルは、Emacs のインストールの一環としてシステムのインクルードツリーに配置されます。あるいは、Emacs のソースツリー内で確認することもできます。

次に、モジュールの初期化関数を記述します。

関数: int emacs_module_init (struct emacs_runtime *runtime)

Emacsはモジュールをロードする際にこの関数を呼び出します。モジュールが emacs_module_init という名前の関数をエクスポートしていない場合、そのモジュールをロードしようとするとエラーが通知されます。初期化関数は、初期化が成功した場合は 0 を、それ以外の場合は 0 以外の値を返す必要があります。後者の場合、Emacsはエラーを通知し、モジュールのロードは失敗します。初期化中にユーザーが C-g を押した場合、Emacsは初期化関数の戻り値を無視して終了します(終了を参照)。(必要に応じて、初期化関数内でユーザーの終了を検知できます。should_quitを参照してください。)

引数 runtime は、2つの公開フィールドを含むCの struct へのポインタです。一方は構造体のサイズをバイト単位で示す size であり、もう一方は、モジュール初期化関数がEmacs環境オブジェクトおよびそのインターフェースにアクセスできるようにする関数へのポインタを示す get_environment です。

初期化関数は、モジュールに必要な初期化処理を行う必要があります。さらに、以下の処理を行うことも可能です。

互換性の確認

モジュールは、runtime 構造体の size メンバと、モジュールにコンパイルされた値とを比較することで、そのモジュールを読み込む Emacs 実行ファイルが当該モジュールと互換性があることを検証できます:

int
emacs_module_init (struct emacs_runtime *runtime)
{
  if (runtime->size < sizeof (*runtime))
    return 1;
}

モジュールに渡されたランタイムオブジェクトのサイズが想定よりも小さい場合、そのモジュールが、ロードを試みているバージョンよりも新しい(後続の)Emacsバージョン向けにコンパイルされたことを意味します。つまり、そのモジュールがEmacsのバイナリと互換性がない可能性があります。

さらに、モジュールは、モジュールのAPIがモジュールの想定する仕様と互換性があるかを確認できます。以下のサンプルコードは、これが前述のemacs_module_init関数の一部であることを前提としています。

  emacs_env *env = runtime->get_environment (runtime);
  if (env->size < sizeof (*env))
    return 2;

これは、runtime構造体で指定されたポインタを用いてget_environment関数を呼び出し、APIの環境へのポインタを取得します。このCのstructには、構造体のサイズをバイト単位で保持するsizeフィールドも備わっています。

最後に、次のように、Emacsから渡される環境のサイズを既知のサイズと比較することで、旧バージョンのEmacsでも動作するモジュールを記述できます。

  emacs_env *env = runtime->get_environment (runtime);
  if (env->size >= sizeof (struct emacs_env_26))
    emacs_version = 26;  /* Emacs 26 or later.  */
  else if (env->size >= sizeof (struct emacs_env_25))
    emacs_version = 25;
  else
    return 2; /* Unknown or unsupported version.  */

これが機能するのは、後続のEmacsバージョンでは常に環境にメンバーが追加され、決して削除されないため、新しいEmacsのリリースに伴いサイズが増大する一方だからです。Emacsのバージョンが分かれば、モジュールのAPIのうちそのバージョンに存在していた部分のみを利用できます。というのも、それらの部分は後続のバージョンでも同一だからです。

emacs-module.h はプリプロセッサマクロ EMACS_MAJOR_VERSION を定義します。これは、ヘッダーがサポートする Emacs の最新メジャーバージョンを表す整数リテラルに展開されます。バージョン情報 を参照してください。なお、EMACS_MAJOR_VERSION の値はコンパイル時定数であり、現在動作しておりモジュールをロードした Emacs のバージョンを表すものではないことに注意してください。モジュールをさまざまなバージョンの emacs-module.h およびさまざまなバージョンの Emacs と互換性を持たせたい場合は、EMACS_MAJOR_VERSION に基づく条件付きコンパイルを使用できます。

モジュールは、初期化関数内で完全に処理を完結させ、かつLispオブジェクトに一切アクセスせず、環境構造を通じて利用可能なEmacs関数も一切使用しない場合を除き、常に互換性検証を行うことを推奨します。

モジュール関数をLispシンボルにバインドする

これにより、モジュール関数に名前が付与され、Lispコードからその名前で呼び出せるようになります。具体的な方法については、後述のモジュール関数の記述で説明します。