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を取り出すかよくわかっていない(というかそれでできるかもわからない...)。そのほかにこのコードで正しく他の場合もうまくいくか検証する必要があるな。