🙆♀️
React+TypeScriptで、WebAssemblyなjsモジュールを実行してみた。
Abstract
前回ので、jsモジュールの読込みができる様になったので、今回は、WebAssemblyのjsモジュールの読込みを実装してみた。
結論
今回の成果物はココ↓
前提
- windowsだよ。
- React+Typescriptの開発環境は構築済 [環境構築]WindowsにVSCode+React+TypeScriptの開発環境を構築してみた。
- WebAssemblyのビルド環境も構築済み。[環境構築]Windowsで、WebAssemblyを初めてみた。
- 前回プロジェクトReactTs-WebAsm001から。
ざっくり手順
- cppファイル生成 -> ビルド
- ビルドでできたwasmファイルをpublic配下にコピー
- インターフェースとなるjsモジュールと、対となるd.tsファイルを作成
- App.tsxでimportして呼び出す。
- 実行
手順詳細
-
cppファイル生成 -> ビルド
cd ReactTs-WebAsm001/src # プロジェクトフォルダに移動 rmdir libs # libsフォルダは削除 mkdir asm-cpp # jsモジュール置き場を作成 type nul > asm-cpp/hello.cpp # hello.cppを自分で生成
hello.cppの中身#include <stdio.h> #ifdef __EMSCRIPTEN__ #include <emscripten.h> #else #define EMSCRIPTEN_KEEPALIVE #endif extern "C" { int EMSCRIPTEN_KEEPALIVE add(int a, int b){ return a + b; } int EMSCRIPTEN_KEEPALIVE sub(int a, int b){ return a - b; } } /* extern "C" */
で、ビルド
コマントプロンプト<emsdkをインストールしたフォルダ>emsdk\emsdk_env.bat # <- コマントプロンプト起動の度に毎回する。 emcc asem-cpp/hello.cpp -o asem-cpp/hello.js -sWASM=1 -sEXIT_RUNTIME=1 -sEXPORTED_RUNTIME_METHODS=ccall,cwrap
成功したら、フォルダ構成は以下の様になる。
コマントプロンプト$ プロジェクトフォルダ ~略~ └─src │ ~略~ └─asm-cpp hello.cpp hello.js # <- ビルドで生成される hello.wasm # <- ビルドで生成される
-
ビルドでできたwasmファイルをpublic配下にコピー
コマントプロンプト$ プロジェクトフォルダ ~略~ ├─public │ └─wasm │ hello.wasm # <- ここにコピー │ ~略~ │ └─asm-cpp │ hello.wasm # <- これを、
-
インターフェースとなるjsモジュールと、対となるd.tsファイルを作成
cd ReactTs-WebAsm001/src type nul > asm-cpp/helloif.js # 自分で生成 type nul > asm-cpp/helloif.d.ts # 自分で生成
helloif.jsは以下の様に。
helloif.js(wasmを呼び出すためのインターフェース)export function helloif(argnum1, argnum2, setter) { WebAssembly.instantiateStreaming(fetch("wasm/hello.wasm")).then( (obj) => { const ret1 = obj.instance.exports._Z3addii(argnum1, argnum2); console.log('retretret=', ret1); setter(ret1); const ret2 = obj.instance.exports._Z3subii(argnum1, argnum2); # <- こっちはお試し。使ってない console.log('retretret=', ret2); # <- こっちはお試し。使ってない } ); return 100; # <- 戻り値は使わないので適当に。 }
helloif.d.tsは以下の様に。
helloif.d.tsdeclare export function helloif(argnum1: number, argnum2: number, setter:React.Dispatch<React.SetStateAction<number>>): number;
-
App.tsxでimportして呼び出す。
helloif.js(wasmを呼び出すためのインターフェース)-import React from 'react'; +import React, { useState } from 'react'; import './App.css'; -import { aaa00, aaa01, aaa02 } from './libs/aaaaa'; +import { helloif } from './asm-cpp/helloif'; function App() { - console.log('---- ret00 = ', aaa00('aaa000', 0)) - const persons = aaa01(['aaa001', 'bbb002'], 1) - console.log('---- ret01 = ', ...persons) - const argbuf = new Uint8Array([11, 22, 33]) - const ret02 = aaa02(argbuf, 2) - console.log('---- ret02 = ', ret02) - const [count, setCount] = useState(0) + const [count, setCount] = useState(0) + console.log('---------------- asmret=', helloif(11, 22, setCount)) return ( <div className="App"> hello world!! + <div>count= {count}</div> </div> ); } export default App;
-
実行
出来た!!
合計4回呼ばれてるのが腑に落ちないけど、ひとまず、WebAssemblyのコードが呼ばれたので良しとする。
修正した。
Discussion