Web

WebAssembly を試してみた

投稿日:2018年10月24日 更新日:

2018年10月における WebAssembly の状況を記録するために、現時点での WebAssembly を試してみることにしました。

1. WebAssembly とは?

これまで、ウェブサイト上で何かプログラミングによる処理を行いたい場合(サーバー側ではなくブラウザ側の話しです)は、JavaScript を使うしかありませんでした。JavaScript は唯一のウェブ標準プログラミング言語だったのです。これに続いて、新たなウェブの標準として登場したプログラミング言語が「WebAssembly」です。

JavaScript よりも実行速度が求められる処理で使用することを主な目的として、主要ウェブブラウザベンダが、W3C WebAssembly Working Group というグループを介して開発しています。

WebAssembly は低水準なプログラミング言語ですので、人間が直接記述するものではありません。C/C++/Rust といったプログラミング言語で記述したコードを WebAssembly に変換して使用します。モジュール化できるので便利ですし、JavaScript と連携することも可能です。

WebAssembly を実行する方法

WebAssembly を実行するには 2通りの方法があります。

1つ目は、JavaScript API を使って wasm ファイル(WebAssembly のバイナリファイル)を読み込む方法です。既に主要ブラウザでは WebAssembly という JavaScript のオブジェクトが実装されているのですが、このオブジェクトを通して WebAssembly JavaScript API を使うことができます。この API を使うと wasm ファイルを読み込んで利用することができます。

Chrome の開発者ツール [Console]タブで WebAssembly の存在が確認できます
Chrome の開発者ツール [Console]タブで WebAssembly の存在が確認できます

もう1つは、<script type='module'> といったタグを書くことで、直接 wasm ファイルをブラウザに読み込ませて処理させる方法です。なのですが、主要ブラウザにおいてもまだこの機能は実装されていません。

2. WebAssembly を使ってみる

Developer’s Guide – WebAssembly に、簡単な使用例が載っていますので、これを試してみることにしました。

環境

  • Windows 10
  • WSL (Ubuntu 16.04 TLS)

作業

WSL のターミナルからの操作が中心となります。

1. Windows 10 installation

Windows 10 の環境なので、まずは WSL (Windows Subsystem for Linux) を利用して Linux をインストールします。しかし、今回の環境では既に Ubuntu がインストール済みでした。

その次に進み、python 2.7 を導入します。

$ sudo apt update
$ sudo apt upgrade
$ sudo apt install python2.7 python-pip

2. Downloading the Toolchain

C/C++ のコードを WebAssembly にコンパイルするツールを導入します。具体的には、Emscripten というツールになります。

まず、今回作業するディレクトリ ~/local に移動しておきます(どこでもよいです)。

$ cd ~/local

以下のコマンドで、Emscripten をインストールします。

$ git clone https://github.com/juj/emsdk.git
$ cd emsdk
$ ./emsdk install latest
$ ./emsdk activate latest

この操作、何がどこにインストールされるのか分からないので不気味でしたが、su (またはsudo) で実行するわけではないので、ひどいことにはならないだろうと判断して進めました。

いざやってみると、どうやらカレントディレクトリ (emsdk) 直下にインストールが行われたようです。そのため、アンインストールするには、このディレクトリを削除すればよさそうです(削除に関しては、README.txt に書いてありました)。

上記の最後のコマンド「./emsdk activate latest」を実際に実行した結果が以下です。

$ ./emsdk activate latest
Writing .emscripten configuration file to user home directory /mnt/c/Users/foo/
The Emscripten configuration file /mnt/c/Users/foo/.emscripten has been rewritten with the following contents:

import os
LLVM_ROOT='/mnt/c/Users/foo/local/emsdk/clang/e1.38.13_64bit'
EMSCRIPTEN_NATIVE_OPTIMIZER='/mnt/c/Users/foo/local/emsdk/clang/e1.38.13_64bit/optimizer'
BINARYEN_ROOT='/mnt/c/Users/foo/local/emsdk/clang/e1.38.13_64bit/binaryen'
NODE_JS='/mnt/c/Users/foo/local/emsdk/node/8.9.1_64bit/bin/node'
EMSCRIPTEN_ROOT='/mnt/c/Users/foo/local/emsdk/emscripten/1.38.13'
SPIDERMONKEY_ENGINE = ''
V8_ENGINE = ''
TEMP_DIR = '/tmp'
COMPILER_ENGINE = NODE_JS
JS_ENGINES = [NODE_JS]

To conveniently access the selected set of tools from the command line, consider adding the following directories to PATH, or call 'source ./emsdk_env.sh' to do this for you.

   /mnt/c/Users/foo/local/emsdk:/mnt/c/Users/foo/local/emsdk/clang/e1.38.13_64bit:/mnt/c/Users/foo/local/emsdk/node/8.9.1_64bit/bin:/mnt/c/Users/foo/local/emsdk/emscripten/1.38.13
Set the following tools as active:
   clang-e1.38.13-64bit
   node-8.9.1-64bit
   emscripten-1.38.13

※ ユーザー名は「foo」としてあります。

Emscripten について

Emscripten を使うと、以下の変換処理を行うことができます。

C/C++ ファイル

↓ 変換処理

wasmファイル, HTMLファイル, JavaScriptファイル

HTMLファイルと JavaScriptファイルまで出力されることに少し違和感があるかもしれませんが、この2つのファイルには wasm ファイルを実行するために必要な記述が含まれています。

3. Environment setup after installation (環境変数のセット)

./emsdk activate latest」の実行結果にも書いてありましたが、このツールを使うには環境変数を追加する必要があります。これは、用意されているシェルスクリプトを実行することで可能です。

$ source ./emsdk_env.sh --build=Release

実際に実行した結果を以下に示します。

$ source ./emsdk_env.sh --build=Release
Adding directories to PATH:
PATH += /mnt/c/Users/foo/local/emsdk
PATH += /mnt/c/Users/foo/local/emsdk/clang/e1.38.13_64bit
PATH += /mnt/c/Users/foo/local/emsdk/node/8.9.1_64bit/bin
PATH += /mnt/c/Users/foo/local/emsdk/emscripten/1.38.13

Setting environment variables:
EMSDK = /mnt/c/Users/foo/local/emsdk
EM_CONFIG = /mnt/c/Users/foo/.emscripten
LLVM_ROOT = /mnt/c/Users/foo/local/emsdk/clang/e1.38.13_64bit
EMSCRIPTEN_NATIVE_OPTIMIZER = /mnt/c/Users/foo/local/emsdk/clang/e1.38.13_64bit/optimizer
BINARYEN_ROOT = /mnt/c/Users/foo/local/emsdk/clang/e1.38.13_64bit/binaryen
EMSDK_NODE = /mnt/c/Users/foo/local/emsdk/node/8.9.1_64bit/bin/node
EMSCRIPTEN = /mnt/c/Users/foo/local/emsdk/emscripten/1.38.13

4. Compile and run a simple program

では、ここからは実際に C言語で簡単なプログラムを書き、Emscripten を使ってコンパイルします。

この作業のためのディレクトリを用意して、そこに移動しておきます。

$ mkdir ~/tmp/hello
$ cd ~/tmp/hello

以下の内容を記述した hello.c ファイルを作成します。

#include <stdio.h>
int main(int argc, char ** argv) {
  printf("Hello, world!\n");
}

コンパイルします。

$ emcc hello.c -s WASM=1 -o hello.html

オプションの簡単な説明

  • -s WASM=1 : wasm ファイルを生成します。
  • -o hello.html : HTMLファイルも生成します(拡張子 .html がポイントです)。

結果、以下のファイルが生成されました。

  • hello.html
  • hello.js
  • hello.wasm

あとは、生成されたウェブページをウェブブラウザで表示するだけなのですが、これにはウェブサーバーを立てる必要があります。ウェブサーバーを用意せずに、生成された HTMLファイルをウェブブラウザにドラッグ・アンド・ドロップして表示しても、wasm の読み込み処理は実行されません。なぜかというと、生成された JavaScript の処理の中に、fetch という API で wasmファイルを読み取る部分があるのですが、fetch はローカルのファイル(file scheme)読み込みに対応していないからです。そのため、ウェブサーバー経由でアクセスして、http scheme (もしくは https scheme) で fetch させないといけないのです。

Emscripten についてくる emrun というコマンドを使うと、簡易的なウェブサーバーを立てることができますので、これを利用します。

ウェブサーバーの起動

$ emrun --no_browser --port 8080 .

補足

emrun でなくても、ウェブサーバーを立てられるなら他のツールでもよいです。
例えば、php コマンドが使えるのであれば、以下でも代用できます。

$ php -S localhost:8080 -t .

ウェブブラウザで、以下のURLにアクセスします。

http://localhost:8080/hello.html
ウェブブラウザで wasm を実行!

ウェブブラウザで wasm を実行!

無事、「Hello, world!」と表示されました。WebAssembly を実行することができたようです。

3. おわりに

今回生成された hello.htmlhello.js ファイルの中を見ると、wasm ファイルを利用するためのコードが想像以上のボリュームで記述されています。特に hello.js は 2,000行以上記述されていました。WebAssembly を利用するために、これほどの量のコードを記述しなければいけないというのは、あまり現実的でないような気がします。

将来的には <script type='module'> といった HTMLタグを書くことで、直接 wasm ファイルをブラウザに読み込ませて実行できる(?)そうですが、速くこれを実現して欲しいなと思いました。

4. 参考

📂-Web

執筆者:labo


  1. >今回生成された hello.html や hello.js ファイルの中を見ると、wasm ファイルを利用する
    >ためのコードが想像以上のボリュームで記述されています。
    >特に hello.js は 2,000行以上記述されていました。WebAssembly を利用するために、
    >これほどの量のコードを記述しなければいけないというのは、あまり現実的でないような気がします。

    自慢になってしまいそうで言いにくのですが、
    http://nowsmartsoft.atwebpages.com
    http://nowsmartsoft.atwebpages.com/demo1/index.html
    http://nowsmartsoft.atwebpages.com/demo2/index.html
    においてあるWasmプログラムは、「ページのソースを表示」などで
    index.html を見たり、スタートアップ用の start.js をブラウザの URL 欄に
    http://nowsmartsoft.atwebpages.com/demo1/start.js
    入れて見てみると分かりますが、以下のようにだいぶコンパクトになっています:
    demo1/index.html : 67行
    demo1/start.js : 303行
    demo1/test.wasm : 89.9 KB

    Emscripten (のemcc) は使わず、自作の C++ nex コンパイラ nwsc と、
    clangで作りました。
    コンパイル時間も emcc よりだいぶ速いです。特に最後のリンク時間が恐らく
    数10倍~100倍くらい速いと思います。

comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

関連記事

Chrome

Chrome の通信ログ(TCP/IPも含む)を記録する

Chrome の通信ログ(TCP/IPも含む)を記録する方法を紹介します。

Web Components

Web Components でスタイルシートを再利用する

Constructable Stylesheet Objects の使い方を説明します。

Chrome

ブロックされた Cookie を確認する方法 (Chrome の場合)

Chrome ブラウザにおいて、ブロックされた Cookie を確認する方法について説明します。

MathJax を試してみました。

MathJax は、HTML上で数式を美しく表示するための JavaScriptライブラリです。 基本的な使い方は、 HTMLファイルに以下を記述して MathJax.js を読み込みます。HTMLフ …

Chrome

Chrome で拡張機能を使わずにスクリーンショットを撮る方法

Chrome で拡張機能を使わずにスクリーンショットを撮る方法について説明します。