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

# はじめに
[前回](https://qiita.com/mink0212/items/d5947ec0d619d6d74eb2)は、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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481713/1727f951-d1af-aacf-a756-a47bef225f62.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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481713/05157c48-3aab-5b9b-e8a9-bda480dda463.png)



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