【Emscripten】 C++ でJSの関数を関数ポインタとして使う
TOC
ものすごく久しぶりの投稿となってしまいました。すみません。
今回は、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 関数を実装
1 | typedef void(*JS_LISTENER)(); |
typedef を利用して、型を簡略化して使用できるようにしています。
また、set_js_listener
は、EMSCRIPTEN_BINDINGS
は使用せず、
ビルド時に EXPORTED_FUNCTIONS
で js から呼び出せるようにします。
そうしないと、次のようなエラーが出ます。
(EMSCRIPTEN_BINDINGS、allow_raw_pointers を使用した場合)
手順2: ビルドする
1 | $ 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で作成する
1 | var fnPointer = Runtime.addFunction(function() { |
関数ポインタは、Runtime.addFunction
を通して使用します。
set_js_listener は、Module.ccall
を使用して呼び出します。
手順4: 登録した関数ポインタを呼び出す
JS から関数ポインタを呼び出します。
1 | Module.call_listener(); |
called!
とコンソールに出力されたので、登録した関数が呼び出されたことがわかります。
コード
今回実行したコードは次のようになりました。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <emscripten.h> | |
#include "emscripten/bind.h" | |
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); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="ja"> | |
<head> | |
<meta charset="UTF-8"/> | |
<title></title> | |
<!-- Emscripten で出力されたコード --> | |
<script type="text/javascript" src="a.out.js"></script> | |
<script type="text/javascript"> | |
var fnPointer = Runtime.addFunction(function() { | |
console.log("called!"); | |
}); | |
Module.ccall("set_js_listener", "void", [], [fnPointer]); | |
Module.call_listener(); | |
</script> | |
</head> | |
<body></body> | |
</html> |
参考
http://stackoverflow.com/questions/12358877/passing-js-function-to-emscripten-generated-code