LoginSignup
6
6

More than 5 years have passed since last update.

【直書き!】AssemblyScriptの(ほぼ)最小構成を作る(環境構築)

Last updated at Posted at 2018-12-22

AssemblyScriptは、TypeScript的な文法でWebAssemblyの .wasm ファイルを出力できるツールです。

GolangやRustでWebAssemblyを作成する時と違い、Runtimeなどがなく、極めてシンプルです。(言い返せば、必要最小限の機能しか備えていません...)

TL;DL

下記URLはDemoソースコードです。(node.js v8以上が必須)
https://github.com/jerrywdlee/assemblyscript-minimum

Hands On

プロジェクトの初期化

AssemblyScriptはBinaryenを使ってバイナリーファイルをコンパイルしているので、環境によってインストールが時間かかる場合があります。

$ npm init
$ npm i -D AssemblyScript/assemblyscript
$ npx asinit .

ここまではおまじないみたいなものです。

成功すれば、プロジェクト配下はこんな感じになります。

assemblyscript-minimum
|--README.md
|--assembly
|  |--index.ts
|  |--tsconfig.json
|--build
|  |--.gitignore
|--index.js
|--node_modules
|--package-lock.json
|--package.json

コンパイル

プロジェクトが初期化された時、assembly/index.tsというサンプルファイルが作成されて、一応コンパイルしてみましょう。

$ npm run asbuild

コンパイルをすると、build/ 配下で下記ファイルが生成されます。

|--build
|  |--.gitignore
+|  |--optimized.wasm
+|  |--optimized.wasm.map
+|  |--optimized.wat
+|  |--untouched.wasm
+|  |--untouched.wasm.map
+|  |--untouched.wat

簡単にいうと、untouched.*シリーズはコンパイルのみ行って圧縮されていないもので、optimized.*シリーズは変数名などを圧縮しました(実行するには両方とも一緒)。
*.wasmはWebAssemblyバイナリーファイルで、*.watはS式ベースのテキスト表現らしいです。

ブラウザで実行

index.htmlを作成して、optimized.wasmをロード

index.html
<h1>It works!</h1>
<script>
  async function loadWasm(url, opt = {}) {
    const wasmRaw = await fetch(url).then(res => res.arrayBuffer());
    const wasmObj = await WebAssembly.instantiate(wasmRaw, opt);
    return wasmObj;
  }

  loadWasm('build/optimized.wasm', {}).then(wasm => {
    console.log(wasm);
  });
</script>

ブラウザで確認

プロジェクト配下で何らかの手段でサーバーを立てて、index.htmlを確認しましょう。
例えば下記のコマンドのどれかを使えば、localhost:8080にてサーバーが立てられます。

# Python2の場合
$ python -m SimpleHTTPServer 8080

# Python3の場合
$ python3 -m http.server 8080

# Rubyの場合
$ ruby -run -e httpd . -p 8080

# node.jsの場合
$ npx http-server -p 8080

localhost:8080にアクセスして、consoleを確認すると、こんなものがみれます。
lvh_me_4242.png
矢印のところの関数は assembly/index.ts の下記関数です。

assembly/index.ts
export function add(a: i32, b: i32): i32 {
  return a + b;
}

コンソルに下記コマンドを入れば確認できます。

loadWasm('build/optimized.wasm').then(wasm => {console.log(wasm.instance.exports.add(42, 24))})

lvh_me_4242.png

軽く解説

fetchbuild/optimized.wasmをArrayBufferとしてロードし、WebAssembly.instantiate()で実行可能状態にインスタンス化しています。Exportされた関数はWASM_OBJECT.instance.exports.FUNCTION_NAMEよりアクセスできます。
WebAssembly.instantiateStreaming()というメソッドについての紹介は散在していますが、おすすめできません。何故ならinstantiateStreaming()はサーバー側が application/wasm というMIME typeの提供が必要である上、実装されたブラウザも少ないです(少なくとも2018年12月時点でiPhoneのSafariでは該当メソッドは未実装)。

Node.jsで実行

npx asinit .で自動生成されたindex.jsはnode.jsモジュールとしてWebAssemblyを動かす方法を示してくれました。

$ node
> const wasm = require('./index.js');
undefined
> wasm
{ memory: Memory {}, table: Table {}, add: [Function: 0] }
> wasm.add(42, 24)
66
>

とても簡単です。

PS: 続編は近日公開予定です

6
6
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
6
6