ものすごく久しぶりの投稿となってしまいました。すみません。
今回は、Emscripten で C++ を実行するときに、
JSの関数を関数ポインタとして登録し、それを呼び出せるようにする方法を紹介します。
実行環境
- Ubuntu 14.04.5 LTS
- emcc 1.36.0
- clang version 3.9.0
やりたいこと
- JS の関数を
set_js_listener
関数を使用して登録する
call_listener
関数を呼び出した時、登録した JS の関数を実行する
手順1: set_js_listener、call_listener 関数を実装
typedef void(*JS_LISTENER)();
JS_LISTENER js_listener = NULL;
extern "C"
{
void set_js_listener(JS_LISTENER f)
{
js_listener = f;
}
}
void call_listener()
{
js_listener();
}
EMSCRIPTEN_BINDINGS()
{
emscripten::function("call_listener", &call_listener);
}
typedef を利用して、型を簡略化して使用できるようにしています。
また、set_js_listener
は、EMSCRIPTEN_BINDINGS
は使用せず、
ビルド時に EXPORTED_FUNCTIONS
で js から呼び出せるようにします。
そうしないと、次のようなエラーが出ます。
(EMSCRIPTEN_BINDINGS、allow_raw_pointers を使用した場合)
手順2: ビルドする
$ emcc main.cpp -std=c++11 -s RESERVED_FUNCTION_POINTERS=1 --bind -s EXPORTED_FUNCTIONS="['_set_js_listener']"
それぞれの引数は、次のような意味があります。
– std=c++11
を指定しないと、embind を使用する際にエラーが出ます。
– -s RESERVED_FUNCTION_POINTERS=1
: 1つの関数ポインタを使えるようにします。
– --bind
: embind を使えるようにします。
– -s EXPORTED_FUNCTIONS="['_set_js_listener']"
: set_js_listener を js から呼び出せるようにします。
手順3: 関数ポインタをJSで作成する
var fnPointer = Runtime.addFunction(function() {
console.log("called!");
});
// 登録する
Module.ccall("set_js_listener", "void", [], [fnPointer]);
関数ポインタは、Runtime.addFunction
を通して使用します。
set_js_listener は、Module.ccall
を使用して呼び出します。
手順4: 登録した関数ポインタを呼び出す
JS から関数ポインタを呼び出します。
Module.call_listener();
called!
とコンソールに出力されたので、登録した関数が呼び出されたことがわかります。
コード
今回実行したコードは次のようになりました。
参考
http://stackoverflow.com/questions/12358877/passing-js-function-to-emscripten-generated-code