1
0

More than 3 years have passed since last update.

JavaScriptの関数をC++に公開する

Posted at

はじめに

前回は、C++の実行結果をhtmlに反映させました。今回は、JavaScriptの関数をC++に公開してC++内でhtmlを変更します。これによって複雑な計算をC++で行って直ぐにhtmlに反映させるようなことができてJavaScriptとC++の垣根が低くなるかと思います。

環境

  • windows 10
  • python:3.6.5
  • emcc:1.39.16
  • clang:11.0.0

Webアセンブリファイルを作成する

まずは、Webアセンブリ用のC++を作成してコンパイルをします。今回はC++のソースとコンパイルがそれぞれ変わっています。

C/C++ファイルの作成

例としてテキストボックスに数字を入れる関数(set_text)を想定します。C++ではextern void set_text(int x)で関数の定義だけしています。そして、使用したい関数(今回はmain)内でその関数を呼び出します。

cmain.cpp

#include <emscripten/emscripten.h>

extern "C" {
    extern void set_text(int x);
}

int main() {
    set_text(1111);
    return 0;
}

C/C++ファイルのコンパイル

Emscripten用のコマンドプロンプトを起動してコンパイルをします。コマンドプロンプトの起動などは前回を見てください。コンパイル時に-s SIDE_MODULE=1-O1のオプションを追加します。 -s SIDE_MODULE=1はサイドモジュールのオプションになります。-O1は、最適化オプションで必須ではないですがimportObjectの設定が手間なので入れます。

コマンド

em++ 入力C++ファイル -s SIDE_MODULE=1 -O1 -o 出力wasmファイル

ちなみにWASMは入れていません。デフォルトが1なのでいらないことに気が付きました。


>em++ cmain.cpp -s SIDE_MODULE=1 -O1 -o hello.wasm 

>

コマンドが終わると同フォルダ内にhello.wasmができているはずです。

wasmを呼び出すhtmlを作成する

前回のソースに加えてimportObjectの情報を追加して、C++のmain関数は戻り値を使用せずに単純に呼び出すだけにします。

importObjectの設定

前回と同じように確認した情報をimportObjectに設定していきます。その際に連想配列の関数にC++へ公開する関数の処理を書いていきます。今回はoutputに引数を格納しています。


    var importObject = { 
      wasi_snapshot_preview1: { proc_exit:args => console.log(arg) }, 
      env: {
        set_text: arg => document.getElementById("output").value = arg, 
      } };

インポート後の処理

インポート後の情報はobjに格納されているため、obj.instance.exports.main()でC++の関数を実行するだけにしています。

my_hello.html

<html>
<head>
  <meta charset="utf-8" />
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>WebAssembly</title>
</head>
<body>
  <input type="button" id="test_view" value="表示" /><input type="text" id="output"/>

  <script>
    var importObject = { 
      wasi_snapshot_preview1: { proc_exit:args => console.log(arg) }, 
      env: {
        set_text: arg => document.getElementById("output").value = arg, 
      } };

    document.getElementById('test_view').addEventListener('click', () => {
      WebAssembly.instantiateStreaming(
        fetch('hello.wasm'), importObject
      ).then(obj => obj.instance.exports.main());
      }, false
    );      
  </script>
</body>
</html>

実行

確認用のサーバを再起動して上のhtmlを実行します。表示ボタンを押すとC++のmainが実行されていset_text()が実行されて与えていた1111が表示されました。うまくC++からJavaScriptの関数を実行することができました。

1.png

JQueryを使用してみる

JavaScriptをC++に公開しているのでJavaScriptのライブラリであるJQueryも公開できるはずと思いJQueryを使用してみました。

JQueryのダウンロード

npmを使えるので、npm経由でJQueryをダウンロードしました。

コマンド


npm install jquery

フォルダ内にnode_modulesができました。

JQueryをhtmlに適用

JQueryを使用してテキストを入れ替えます。先ほどの例に<script>$("#output").val(arg)を追加しました。

my_hello.html

<html>
<head>
  <meta charset="utf-8" />
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>WebAssembly</title>
</head>
<body>
  <input type="button" id="test_view" value="表示" /><input type="text" id="output"/>

  <script>
    var importObject = { 
      wasi_snapshot_preview1: { proc_exit:args => console.log(arg) }, 
      env: {
        set_text: arg => $("#output").val(arg), 
      } };

    document.getElementById('test_view').addEventListener('click', () => {
      WebAssembly.instantiateStreaming(
        fetch('hello.wasm'), importObject
      ).then(obj => obj.instance.exports.main());
      }, false
    );      
  </script>
  <script type="text/javascript" src="node_modules/jquery/dist/jquery.min.js"></script>
</body>
</html>

実験

サーバを立てて試してみたところ先ほどと同じように追加できました。JQueryも無事C++に公開することができました。

2.png

おわりに

JavaScriptの関数をC++に公開して実行できるようにしてみました。ぱっと見はそこまで恩恵はないように思いますが、処理速度が速くなっていたり、メモリ消費が抑えられていると恩恵は大きくなります。次回はそこら辺を実験してみようかと思います。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0