この用途に合うかは分かりませんが、HEADでは(address bv offset)形式でバイトベクタの途中のアドレスを渡せるようにしてみました。

なんと！

というわけで、SagittariusでもDynamic bindingだけでnccc呼び出しを実装することができた。

( library ( sagittarius-yuni compat ffi primitives ) ( export yuniffi-nccc-call yuniffi-module-load yuniffi-module-lookup ) ( import ( yuni scheme ) ( sagittarius ffi )) ( define ( yuniffi-nccc-call func in in-offset in-size out out-offset out-size ) ( func ( address in ( * 8 in-offset )) in-size ( address out ( * 8 out-offset )) out-size )) ( define ( yuniffi-module-load path ) ( open-shared-library path )) ( define ( yuniffi-module-lookup handle str ) ( define ptr ( lookup-shared-library handle str )) ( pointer->c-function ptr ' void str '( void* int void* int ))) )

ただ結局専用構文でなくpointer→c-functionを使ってしまった。専用構文だとDLL側のシンボルが自動的にquoteされてしまうので、yuniffi-module-lookupのように、DLLのハンドルとシンボル名を取って手続きを返すような手続きの実装ができない。

Scheme処理系のFFI機能を比較してみて 前々々回: http://d.hatena.ne.jp/mjt/20150213/p1 nmosh / Gauche / Racket

前々回: http://d.hatena.ne.jp/mjt/20150316/p1 chibi-scheme / Larceny

前回: http://d.hatena.ne.jp/mjt/20150319/p1 Guile / Vicare

今回は、nmosh / Gauche / Racket / chibi-scheme / Larceny / Guile / Vicare / Sagittariusで共通のFFI手続きを3種実装した: (yuniffi-module-lookup ハンドル 文字列) => nccc関数オブジェクト (yuniffi-module-load 文字列) => ハンドル (yuniffi-nccc-call 関数オブジェクト 入力スタック 入力スタックオフセット 入力スタックサイズ 出力スタック 出力スタックオフセット 出力スタックサイズ) これで、yuniFFIが定める呼び出し規約NCCCに準拠するC APIであれば、"DLLをロード→DLLからシンボルをlookup→呼び出し" の一連の処理を処理系独立に記述することができるようになった。

この3手続きの機能は、nmosh / Gauche / chibi-schemeのstatic bindingなFFIを基準に行った。これはyuniffi-module-lookupでクロージャを確保する必要が無いようにするのが目的だったが、動的bindingなScheme処理系、つまり残り全部では結局クロージャを確保することになってしまった。

動的bindingなScheme処理系の機能性はほぼ同一で、複雑なyuniffi-nccc-call手続きを特に問題なく実装することができるが、DLLや.soに指定するパスの解釈がまちまちであり、このポイントもライブラリで吸収しなければならないことがわかった。

RacketとGuileは、拡張子を省略させ、プログラムを環境間で使い回せるように配慮している。これは、WindowsとELF系OSとMacOSでローダブルモジュールの拡張子が異なることによる(Windows = .dll, ELF系 = .so, Mac = .dyld)

Larceny、VicareとSagittariusは、dlopenのセマンティクスを基本的にそのまま採用する。このため、LD_LIBRARY_PATH等が尊重され、拡張子はスクリプト側で正しく与える必要がある。

現状のnmoshでは、ローダブルモジュールの拡張子はOS標準のものを用いず.mplgを使用している。これは、Windowsでは標準では.dllはエクスプローラで見えないので取り回しが悪い(= のでユーザに入れ替えてもらったりといったオペレーションで不便)という酷い理由による。 でも実際イベント会場でデバッグログ入りの.mplgに入れ替えてデバッグというのは何度も起きているのでこういう配慮はどうしても必要になる