search
LoginSignup
6

More than 3 years have passed since last update.

posted at

updated at

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

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: 続編は近日公開予定です

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
What you can do with signing up
6