2016年12月20日火曜日

Pharoからgnuplotでsin(x)

UnifiedFFIを使ってC言語の関数を呼べたので、 Pharoからgnuplotを呼び出してみた。

呼び出す関数は、以前書いたgnuplotへのpipeを開いて コマンドを書き込む以下の関数。

/* gpdo.c */
#include <stdio.h>

FILE *gpstart(void);
void gpstop(FILE *p);
void gpdo(FILE *p, char *s);

FILE *gpstart(void) {
    /* start gnuplot process */
    return popen("gnuplot.exe --persist", "w");
}

void gpstop(FILE *p) {
    /* stop gnuplot process */
    gpdo(p, "quit");
    pclose(p);
}

void gpdo(FILE *p, char *s) {
    /* send command string to gnuplot process */
    fprintf(p, s);
    fprintf(p, "\n");
    fflush(p);
}

Windowsのgcc(MinGW)で共有ライブラリにします。

gcc -shared -o gpdo.so gpdo.c
出力されたgpdo.soをPharo.exeがあるフォルダに配置しました。

と同様に、Pharoを起動してFFILibraryを継承したライブラリファイルを示す クラスGnuplotDoLibを作成しました。そのクラスに、win32ModuleNameメソッド を追加し、共有ライブラリのファイル名を返すようにします。

win32ModuleName
    ^ 'gpdo.so'

次は、関数呼び出し用のクラスを作ります。Objectクラスを継承してGnuplotDoクラスを 作りました。メソッドは関数を呼び出すだけなので、クラス側のメソッドにします。 これで、呼び出すときにわざわざインスタンスを生成する必要がなくなります。 三つの関数についてそれぞれメソッドを追加しました。 FILE構造体へのポインタ(FILE *)については、 今回はPharo側で解釈する必要がない(メンバーにアクセスしたりしない)ため、(void *)とします。

gpOpen
    ^ self ffiCall: #(void * gpstart ()) module: GnuplotDoLib.

gpClose: aHandle
    self ffiCall: #( void gpstop (void * aHandle)) module: GnuplotDoLib

gpHndl: aHandle gpCmd: aString
    self ffiCall: #( void gpdo (void * aHandle, String aString) ) module: GnuplotDoLib

これで準備完了です。Playgroundを開いて動かしてみます。

hndl := GnuplotDo gpOpen.
GnuplotDo gpHndl: hndl gpCmd: 'set xlabel "x"'.
GnuplotDo gpHndl: hndl gpCmd: 'set ylabel "y"'.
GnuplotDo gpHndl: hndl gpCmd: 'plot sin(x)'.
GnuplotDo gpClose: hndl.

とりあえず、これでPharoからgnuplotを起動してラベル設定してsin(x)を プロットする手続きが行えました。 エラーが起こるようなコマンドをgnuplotに渡すとgnuplotがクラッシュ してしまいますが、よしとします。

0 件のコメント: