* 概要 [#n5707163] - OCaml特有の話 -- OCamlの関数を.soなり.dllなりのシンボルとして直接エクスポートすることはできない。 Cの関数でスタブを書く必要がある。 -- OCaml側で, モジュール初期化時に '''Callback.register 文字列 関数''' とすれば 関数を '''"文字列"''' という名前でエクスポートできる -- C側では*caml_named_value(文字列)として関数の名前を取得する。 -- caml_callbackで関数を呼ぶ - FFI一般の話 -- OCamlランタイムを初期化する必要がある。 -- OCamlの値とCの値の相互変換が必要である。下の例ではVal_int(C→OCaml)とInt_val(OCaml→C)を用いている。 OCamlのint型は31ビット幅であることに注意。 * Linuxの場合 [#gc0eda21] ** ライブラリ側ファイル [#s85a88f9] - foo.ml let succ x = x+1 let _ = Callback.register "succ" succ - foostub.h int succ_caml(int x); - foostub.c #include <caml/mlvalues.h> #include <caml/callback.h> #include "foostub.h" int succ_caml(int x) { return Int_val(caml_callback(*caml_named_value("succ"), Val_int(x))); } *** コンパイル [#g467c1d9] - ocamlcにオプション -output-obj -o lib'''name'''.so とすれば共有ライブラリが得られる. gcc -I/usr/local/lib/ocaml -c foostub.c ocamlc -output-obj -o libfoo.so foo.ml foostub.o ** プログラム本体 [#s0de3411] - usefoo.c #include "foostub.h" #include <stdio.h> #include <caml/callback.h> int main(int argc, char** argv) { caml_startup(argv); printf("%d\n", succ_caml(10)); return 0; } *** コンパイル [#d73d3ca5] - 普通の共有ライブラリとしてリンクして実行。 gcc -I/usr/local/lib/ocaml -o usefoo libfoo.so usefoo.c *** 実行 [#jcb410e8] $ export LD_LIBRARY_PATH=`pwd`:$LD_LIBRARY_PATH $ ./usefoo 11 * ネイティブコードの場合 [#udcf5489] - 上のocamlcをocamloptに変えるだけ * (参考)静的リンクの場合 [#w51d1ea0] -- -output-obj foo.o で オブジェクトコードを生成できるのでarで.aを作るなりリンクするなり - -output-obj foo.o で オブジェクトコードを生成できるのでarで.aを作るなりリンクするなりすればよい -- その場合 -lcamlrun (ネイティブコードなら -lasmrun) を付けるのを忘れずに -- 以下はネイティブコード用静的リンク ocamlopt -output-obj -o foo.o foo.ml gcc -I/opt/local/lib/ocaml -c foostub.c gcc -I/opt/local/lib/ocaml -c usefoo.c gcc -o usefoo foo.o foostub.o usefoo.o -L/opt/local/lib/ocaml -lasmrun