LISPUSER
CLISP 拡張モジュール開発ガイトLisp isn't a language, it's a building material.Table of Contents
拡張モジュール概要
拡張モジュールとは?
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 のモジュールができあがります。
作成の流れ
必要なもの
準備するものリスト。