Home / WebAssembly


WebAssembly System Interface(WASI)
WebAssembly Standard Interface(WASI) ... 書籍ではこう書かれている。


諸々

C++をEmscriptenでコンパイルしてブラウザ上で動かしてみた | DevelopersIO

コンパイルするには

Rust ... wasm-packをインストール。
C++ .... a. Emscripten
b. Clangとwasi-sdkを使用

wasi-sdkを利用してさくっとWASMを試す | DevelopersIO

GitHub - WebAssembly/wasi-sdk: WASI-enabled WebAssembly C/C++ toolchain

WebAssemblyが含まれているのは Qt5.13 から

Ubuntu上にQtのWebAssembly開発環境を構築する - Qiita

WASMの用途

動画 WebAssemblyについて - YouTube.mkv より

ブラウザ内:

ブラウザ外:


Emscripten

公式サイト:

Download and install — Emscripten 3.1.26-git (dev) documentation

~/opt/ に解凍したのでインストール先は ~/opt/emsdk-main/ になり、そこで作業する。

emsdk install latest
~/opt/emsdk-main$ ./emsdk install latest
Resolving SDK alias 'latest' to '3.1.27'
Resolving SDK version '3.1.27' to 'sdk-releases-upstream-48ce0b44015d0182fc8c27aa9fbc0a4474b55982-
64bit'
Installing SDK 'sdk-releases-upstream-48ce0b44015d0182fc8c27aa9fbc0a4474b55982-64bit'..
Installing tool 'node-14.18.2-64bit'..
Downloading: ***/opt/emsdk-main/zips/node-v14.18.2-linux-x64.tar.xz from https://storage.
googleapis.com/webassembly/emscripten-releases-builds/deps/node-v14.18.2-linux-x64.tar.xz, 2184841
6 Bytes
Unpacking '***/opt/emsdk-main/zips/node-v14.18.2-linux-x64.tar.xz' to '***/opt/e
msdk-main/node/14.18.2_64bit'
Done installing tool 'node-14.18.2-64bit'.
Installing tool 'releases-upstream-48ce0b44015d0182fc8c27aa9fbc0a4474b55982-64bit'..
Downloading: ***/opt/emsdk-main/zips/48ce0b44015d0182fc8c27aa9fbc0a4474b55982-wasm-binari
es.tbz2 from https://storage.googleapis.com/webassembly/emscripten-releases-builds/linux/48ce0b440
15d0182fc8c27aa9fbc0a4474b55982/wasm-binaries.tbz2, 371163051 Bytes
Unpacking '***/opt/emsdk-main/zips/48ce0b44015d0182fc8c27aa9fbc0a4474b55982-wasm-binaries
.tbz2' to '***/opt/emsdk-main/upstream'
Done installing tool 'releases-upstream-48ce0b44015d0182fc8c27aa9fbc0a4474b55982-64bit'.
Done installing SDK 'sdk-releases-upstream-48ce0b44015d0182fc8c27aa9fbc0a4474b55982-64bit'.
emsdk activate latest
~/opt/emsdk-main$ ./emsdk activate latest
Resolving SDK alias 'latest' to '3.1.27'                                                                 
Resolving SDK version '3.1.27' to 'sdk-releases-upstream-48ce0b44015d0182fc8c27aa9fbc0a4474b55982-64bit'
Setting the following tools as active:
   node-14.18.2-64bit
   releases-upstream-48ce0b44015d0182fc8c27aa9fbc0a4474b55982-64bit

Next steps:
- To conveniently access emsdk tools from the command line,
  consider adding the following directories to your PATH:
    ***/opt/emsdk-main
    ***/opt/emsdk-main/node/14.18.2_64bit/bin
    ***/opt/emsdk-main/upstream/emscripten
- This can be done for the current shell by running:
    source "***/opt/emsdk-main/emsdk_env.sh"
- Configure emsdk in your shell startup scripts by running:
    echo 'source "***/opt/emsdk-main/emsdk_env.sh"' >> $HOME/.bash_profile
PATHの追加(emsdk_env.sh)

上記の終わりに有るように shell 起動スクリプトへ追記させる。

~/opt/emsdk-main$ source "***/opt/emsdk-main/emsdk_env.sh"' >> $HOME/.bash_profile

因みに emsdk_env.sh を実行しただけの場合の表示は次の通り。

~/opt/emsdk-main$ source "./emsdk_env.sh"
Setting up EMSDK environment (suppress these messages with EMSDK_QUIET=1)
Adding directories to PATH:
PATH += ***/opt/emsdk-main
PATH += ***/opt/emsdk-main/upstream/emscripten
PATH += ***/opt/emsdk-main/node/14.18.2_64bit/bin

Setting environment variables:
PATH = ***/opt/emsdk-main:***/opt/emsdk-main/upstream/emscripten:***/opt/emsdk-main/node/14.18.2_64bit/bin:***/opt/flutter/bin/:***/.config/nvm/versions/node/v14.17.1/bin:***/usr/bin:***/.tfenv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
EMSDK = ***/opt/emsdk-main
EMSDK_NODE = ***/opt/emsdk-main/node/14.18.2_64bit/bin/node

働くかどうか確認には $ bash --login とすれば、上記と同じ内容が表示されるはず。

因みに某の環境 PATH は次のようになったので node は emsdk の v14.18.2 が使われる(nvm は flutter で入った物か…)。

$ printenv PATH|awk 'BEGIN{RS=":"}{print}'
/home/usskim/opt/emsdk-main
/home/usskim/opt/emsdk-main/upstream/emscripten
/home/usskim/opt/emsdk-main/node/14.18.2_64bit/bin
/home/usskim/opt/flutter/bin/
/home/usskim/.config/nvm/versions/node/v14.17.1/bin
/home/usskim/usr/bin
/home/usskim/.tfenv/bin
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/usr/games
/usr/local/games
/snap/bin

list 表示

emsdk list
~/opt/emsdk-main$ emsdk list

The *recommended* precompiled SDK download is 3.1.27 (48ce0b44015d0182fc8c27aa9fbc0a4474b55982).         
                                                                                                         
To install/activate it, use one of:                                                                      
         latest                  [default (llvm) backend]                                                
         latest-fastcomp         [legacy (fastcomp) backend]                                             
                                                                                                         
Those are equivalent to installing/activating the following:                                             
         3.1.27             INSTALLED                                                                    
         3.1.27-fastcomp                                                                                 
                                                                                                         
All recent (non-legacy) installable versions are:                                                        
         3.1.27    INSTALLED                                                                             
         3.1.26                                                                                          
         3.1.25    
         3.1.24    
         3.1.23    
         3.1.22    
         3.1.21    
         3.1.20    
         3.1.19    
         3.1.18    
         3.1.17    
         3.1.16    
         3.1.15    
         3.1.14    
         3.1.13    
         3.1.12    
         3.1.11    
         3.1.10    
         3.1.9    
         3.1.8    
         3.1.7    
         3.1.6    
         3.1.5    
         3.1.4    
         3.1.3    
         3.1.2    
         3.1.1    
         3.1.0    
         3.1.27-asserts    
         3.1.26-asserts    
         3.1.25-asserts    
         3.1.24-asserts    
         3.1.23-asserts    
         3.1.22-asserts    
         3.1.21-asserts    
         3.1.20-asserts    
         3.1.19-asserts    
         3.1.18-asserts    
         3.1.17-asserts    
         3.1.16-asserts    
         3.1.15-asserts    
         3.1.14-asserts    
         3.1.13-asserts    
         3.1.12-asserts    
         3.1.11-asserts    
         3.1.10-asserts    
         3.1.9-asserts    
         3.1.8-asserts    
         3.1.7-asserts    
         3.1.6-asserts    
         3.1.5-asserts    
         3.1.4-asserts    
         3.1.3-asserts    
         3.1.2-asserts    
         3.1.1-asserts    
         3.1.0-asserts    
         3.0.1    
         3.0.0    
         3.0.1-asserts    
         3.0.0-asserts    
         2.0.34    
         2.0.33    
         2.0.32    
         2.0.31    
         2.0.30    
         2.0.29    
         2.0.28    
         2.0.27    
         2.0.26    
         2.0.25    
         2.0.24    
         2.0.23    
         2.0.22    
         2.0.21    
         2.0.20   
         2.0.19    
         2.0.18    
         2.0.17    
         2.0.16    
         2.0.15    
         2.0.14    
         2.0.13    
         2.0.12    
         2.0.11    
         2.0.10    
         2.0.9    
         2.0.8    
         2.0.7    
         2.0.6    
         2.0.5    
         2.0.4    
         2.0.3    
         2.0.2    
         2.0.1    
         2.0.0    
         2.0.31-asserts    
         2.0.30-asserts    
         2.0.29-lto    
         2.0.28-lto    
         2.0.27-lto    
         2.0.26-lto    
         2.0.23-lto    
         2.0.20-lto    
         2.0.19-lto    
         1.40.1    
         1.40.0    
         1.39.20    
         1.39.19    
         1.39.18    
         1.39.17    
         1.39.16    
         1.39.15    
         1.39.14    
         1.39.13    
         1.39.12    
         1.39.11    
         1.39.10    
         1.39.9    
         1.39.8    
         1.39.7    
         1.39.6    
         1.39.5    
         1.39.4    
         1.39.3    
         1.39.2    
         1.39.1    
         1.39.0    
         1.38.48    
         1.38.47    
         1.38.46    
         1.38.45    
         1.38.44    
         1.38.43    
         1.38.42    
         1.38.41    
         1.38.40    
         1.38.39    
         1.38.38    
         1.38.37    
         1.38.36    
         1.38.35    
         1.38.34    
         1.38.33    

The additional following precompiled SDKs are also available for download:
    *    sdk-releases-upstream-48ce0b44015d0182fc8c27aa9fbc0a4474b55982-64bit   INSTALLED
         sdk-releases-upstream-630810e5a312f57d17efbe384ed7e4299f796bc1-64bit
         sdk-releases-fastcomp-edf24e7233e0def312a08cc8dcec63a461155da1-64bit
         sdk-releases-fastcomp-536568644fd67d53778f6111fdd5f64ad3f4c539-64bit
         sdk-fastcomp-1.38.30-64bit
         sdk-fastcomp-1.38.31-64bit

The following SDKs can be compiled from source:
         sdk-upstream-main-64bit  
         sdk-upstream-main-32bit  
         sdk-fastcomp-tag-1.38.30-64bit
         sdk-fastcomp-tag-1.38.31-64bit

The following precompiled tool packages are available for download:
    (*)    releases-upstream-48ce0b44015d0182fc8c27aa9fbc0a4474b55982-64bit     INSTALLED
           releases-upstream-630810e5a312f57d17efbe384ed7e4299f796bc1-64bit
           releases-fastcomp-edf24e7233e0def312a08cc8dcec63a461155da1-64bit
           releases-fastcomp-536568644fd67d53778f6111fdd5f64ad3f4c539-64bit
           fastcomp-clang-e1.38.30-64bit
           fastcomp-clang-e1.38.31-64bit
    (*)    node-14.18.2-64bit           INSTALLED
           node-14.15.5-64bit       
           emscripten-1.38.30       
           emscripten-1.38.31     

The following tools can be compiled from source:
           llvm-git-main-32bit      
           llvm-git-main-64bit      
           clang-tag-e1.38.30-32bit 
           clang-tag-e1.38.31-32bit 
           fastcomp-clang-tag-e1.38.30-64bit
           fastcomp-clang-tag-e1.38.31-64bit
           fastcomp-clang-master-32bit
           fastcomp-clang-master-64bit
           emscripten-tag-1.38.30-32bit
           emscripten-tag-1.38.31-32bit
           emscripten-tag-1.38.30-64bit
           emscripten-tag-1.38.31-64bit
           binaryen-tag-1.38.30-32bit
           binaryen-tag-1.38.31-32bit
           binaryen-tag-1.38.30-64bit
           binaryen-tag-1.38.31-64bit
           emscripten-main-32bit    
           emscripten-main-64bit    
           binaryen-main-32bit      
           binaryen-main-64bit      
           ninja-git-release-64bit  
           ccache-git-emscripten-64bit

Items marked with * are activated for the current user.
Items marked with (*) are selected for use, 
 but your current shell environment is not configured to use them.
 Type "source ./emsdk_env.sh" to set up your current shell to use them.

To access the historical archived versions, type 'emsdk list --old'

Run "./emsdk update" to pull in the latest list.

Emscripten は固有の識別子 __EMSCRIPTEN__ を持つようだ。従って

#ifdef __EMSCRIPTEN__
  #include <emscripten.h>
#endif

MDN: Mozilla Developer Network


書籍: ハンズオン WebAssembly

書籍中のサンプルコード: oreilly-japan/WebAssembly: 『ハンズオンWebAssembly』のコードリポジトリ

3.4章 .wasm と .js と .htmlの生成(emcc *.c -o *.html)

    createWasm()
    instantiateAsync()
    fetch(...)
    WebAssembly.instantiateStreaming()
  

なお、MDN にはカスタム HTML テンプレートの使い方も述べてある。
--shell-file に続けて指定するもよう。テンプレートの中身は高度で解らない。

emcc calculate_primes.c -O3 -o calculate_primes.html --shell-file shell_minimal.html
3.5章 .wasm と .js の生成(emcc *.c -o *.js)

3.5章では -o ***.html ではなく ***.js を指定する。 すると .wasm と .js のみ生成される(.html は生成されない)。 .js は同じ物が生成されるが、例ではファイル名を変えてあるので、.wasm の名前の部分だけが異なるようだ。

diff -y で見比べると判る。

1050 var wasmBinaryFile;                                     var wasmBinaryFile;
1051   wasmBinaryFile = 'html_template.wasm';              |   wasmBinaryFile = 'js_plumbing.wasm';
1052   if (!isDataURI(wasmBinaryFile)) {                       if (!isDataURI(wasmBinaryFile)) {
1053     wasmBinaryFile = locateFile(wasmBinaryFile);            wasmBinaryFile = locateFile(wasmBinaryFile);
1054   }                                                       }

この場合の .html は scriptタグに .js を指定するだけで良い。生成された .js が WebAssembly モジュールのロードとインスタンス化をやってくれるらしい。さらに main関数を書いているので Startセクションに登録されるそうな。

<body>
    HTML page I created for my WebAssembly module. 
    <script src="js_plumbing.js"></script>
</body>
3.6章 .wasm のみ生成(emcc *.c ... -o *.wasm)== 関数呼出し

お待ちかね、JavaScript から関数を呼び出す例。
ソースファイル side_module.c は本当にこれだけ↓。

int Increment(int value)
{ 
    return (value + 1); 
}
emcc side_module.c -O1 --no-entry -s "EXPORTED_FUNCTIONS=['_Increment']" -o side_module.wasm

グルーコードは無いので、自分でダウンロードとインスタンス化を書かねばならない。
最小限のコードらしく、呼び出し部(と結果)は次の通り。

  1. fetch()
  2. WebAssemblyモジュールのダウンロード要求。非同期のHTTP通信。
    ここでは第2パラメータは省略されている。
    Responseオブジェクトを返す。
     ↓
  3. instantiateStreaming()
  4.  ↓
  5. instance.exports.Increment()

MDNの関数呼出し手順 - C で定義されたカスタム関数を呼び出す

3.6章の方法と違っている。
Emscripten の仕組みを使った方法なようだ。

まず、この例では main関数を含んではいるが、呼び出すのは別の関数となっている。
従って --no-entry は指定しない。
その場合の Emscripten は既定で main()を呼び出し、他のデッドコードは削除するそうな。

それでは困るので EMSCRIPTEN_KEEPALIVE 修飾子(キーワード?)を加えるそうな。(識別子 __EMSCRIPTEN__ で見分けるのが作法か…)

#ifdef __EMSCRIPTEN__
EMSCRIPTEN_KEEPALIVE
#endif
void myFunction(int argc, char ** argv)
{
    printf("MyFunction Called\n");
}

コンパイルは次の通り。

  1. -s NO_EXIT_RUNTIME=1 ....... main()関数が終了したときにランタイムがシャットダウンされないように。
  2. -s "EXPORTED_RUNTIME_METHODS=['ccall']" ... ccall を呼べるように。
emcc -o hello3.html hello3.c -O3 --shell-file html_template/shell_minimal.html 
-s NO_EXIT_RUNTIME=1 
-s "EXPORTED_RUNTIME_METHODS=['ccall']"

Module.ccall() を使うらしい。これが fetch やらインスタンス化をやってくれる、と推測。

document
  .getElementById("mybutton")
  .addEventListener("click", () => {
    alert("check console");
    const result = Module.ccall(
      "myFunction",  // name of C function
      null,  // return type
      null,  // argument types
      null,  // arguments
    );
  });

この辺の説明は Emscripten に書かれているもよう。
ccall/cwrap を使用して JavaScript からコンパイル済みの C 関数を呼び出す


4章

検証ロジックをブラウザとサーバとで同じコードを使う例。
理に適っており素晴らしい。が、呼び出し周りは少々手間が入る。

.cpp のコードでは(必要なら)エラーメッセージを引数のポインタに strcpy で書き込んで返す。その為、領域を malloc/free しないといけない模様。
 ならばポインタのポインタ、或いはポインタの参照を渡せば良さそうだが、その構文が JavaScript に無いのだろう…
何れにしても JavaScript の文字列として扱うには UTF8ToString() で変換しないといけないようだ。


4.2章 サイドモジュール

此方の方法は関数を直接呼び出せる。しかし、js の文字列を C文字列に理解させるにはメモリコピー、エンコードの必要が生じ、ややこしくなる。

但し、パラメータの受け渡しが無い場合は、この方法も悪く無さそうだ(混在するのはどうかと思うが…)。

付録A

インストール関係の補足

WebAssembly のメディアタイプ(application/wasm)は登録されているか調べる。

これは Python に追加されているか否かを調べるもの。

$ grep 'wasm' /etc/mime.types
      application/wasm                                wasm
  

Node.js に WebAssembly が追加されたのは ver. 8以降。

$ node --version
  v14.17.1 ... OK!
  

なお、Emscripten のインストールと共に node-14.18.2-64bit がインストールされ、そちらの Path が優先される点に注意。


書籍: 入門 WebAssembly

キャンバスに描く例題が有る!


Home / WebAssembly


© 2008 usskim    http://usskim.web.fc2.com/
inserted by FC2 system