LISPUSER

CLISP 拡張モジュール開発ガイトLisp isn't a language, it's a building material.

(Top Page) (Lisp Memo)

拡張モジュール概要

拡張モジュールとは?

CLISP では、Lisp のみでは難しい(シビアな性能が要求される処理や、既存の C のライブラリを使いたい場合)状況に対応するために いくつかの手段が提供されています。

  • 拡張モジュール
  • Foreign Function Interface (FFI)

拡張モジュールは、C で Lisp 機能を作成し、CLISP にリンクすることによって拡張を実現するものです。 FFI は実行時に共有ライブラリをロードして使用する機能です。なんだか似たようなものに聞こえるかもしれませんが、 この二つの機能の違いについては、次の節で紹介します。

1.2. FFI と拡張モジュール

この二つの機能は、 CLISP Impnotes の Trade-offs: FFI vs. C modules の節でつぎのように比較されています:

  • 速度: 拡張モジュールのほうが有利 (FFI にはオーバーヘッドがある。また、C モジュールだとたとえば 32bit 演算が高速に行えるなどのメリットもある)
  • 移植性: 拡張モジュールのほうが有利 (FFI はすべてのプラットフォームで使えるわけではない)
  • コードサイズ: FFI のほうが有利 (タイプ数は FFI のほうが少なくすむ。なにしろ CLISP セッションを中断せずに試せるし。これはラピッドプロトタイピングには重要)
  • UI: C のほうが有利 (FFI では Lisp 流儀のスタイルに合わせようとすると、ラッパー関数を書くことになる。C なら直接かける。)
  • 学習曲線: 不明 (C に慣れているならモジュール関連機能を使うのは容易だが、FFI の高水準なインターフェースのほうが使いやすいと思うかも…?)
  • 安全性: 不明 (どっちのやり方でも簡単に自分の足を撃ち抜ける)

ビルド時に dynamic-modules を有効にすると、sys::dynload-modules 関数で、動的に拡張モジュール (ただし、拡張モジュールの動的ロードを有効にすると、最適化が一部 OFF になります) をロードする事ができます。

1.3. 拡張モジュールを作るには

拡張モジュール用の C ソースと Lisp の世界を橋渡しするために、modprep という Lisp で書かれたプリプロセッサを活用します。 たとえば、C の関数を定義しただけでは Lisp から使う事はできません。 ただ関数を定義するのではなく modprep が用意してくれたマクロ DEFUN つかって関数を定義する、という魔法を使う必要があります。

/* (defun hello-world () (write-line "hello, world!!")) 相当C のコード */
DEFUN(USER:HELLO-WORLD, )
{
    printf("hello, world!!\n");
    VALUES1(NIL);
}

 /* (defun hello-world-2 ()                                */
 /*   (loop repeat 10 do (write-line "hello, world!!")))   */
 /* 相当C のコード                                         */
DEFUN(USER:HELLO-WORLD-2, n)
{
    int i = 0, n = I_to_uint(popSTACK());
    while (i++ < n) {
        printf("hello, world!!\n");
    }
    VALUES1(NIL);
}

このコードを modprep にかけると、Lisp へ関数定義を登録するコードを含めた C のコードを生成してくれます。 それをコンパイルして共有オブジェクトファイルにすると CLISP のモジュールができあがります。

作成の流れ

必要なもの

準備するものリスト。

CLISP

GCC などの C コンパイラ

modprep 概要

autotool (autoconf)

3. モジュールを作ってみよう

3.1. ターゲットのライブラリを決める

3.2. インターフェースを決める

3.3. 動作をテストする

4. 公開しよう

4.1. 自分のページやサイトなどで公開

4.2. 標準配布物に寄贈してみる