TinyCCを使う(2)
ちょっと勘違いから手間取り、時間をとられてしまった。それはそれとして、TinyCCでオンメモリに展開したオブジェクトをFFIとしてコールすることができました。
まずFFICallTest class>>primFFICall:を以下のように定義した。module名は適当につける。
primFFICall: msg <cdecl: void 'foo' (char *) module: 'NonExist'> ^self externalCallFailed
次に以下の実験用のソースで'do-it'した。
| address | tc := TinyCCWrapper new. "TinyCCコンパイラの初期化" tccState := tc primNew. "コンパイル結果をオンメモリに出力する指定" tc primSetOutput: tccState with: 0. "指定コードをコンパイル" tc primCompile: tccState with: ' void foo(char *msg) { printf("ffi calling Success!(by %s)\n", msg); }'. tc primRelocate: tccState. "関数fooのアドレスを得る" address := tc primGet: tccState with: 'foo'. "関数fooのアドレスをFFIコールアドレスとする" ExternalLibraryFunction allInstancesDo: [:ex | ex name = #foo ifTrue: [ | b | b := ByteArray new:4. b unsignedLongAt: 1 put: address. ex setHandle: b asExternalPointer. ]. ]. "TinyCCでコンパイルした関数fooを呼び出す" FFICallTest primFFICall: 'hkawa'.
コンソール出力:
ffi calling Success!(by hkawa)
課題として実行するメソッドのExternalLibraryFunctionをどうやって効率的に見つけ出せるかです。methodDictにあるExternalLibraryFunctionへのポインタからExternalLibraryFunctionを取り出すかよくわかっていない(というかそれでできるかもわからない...)。そのほかにこのコードで正しく他の場合もうまくいくか検証する必要があるな。