はじめに
本記事はQualiArts Advent Calendar 2022 16日目の記事になります
ここでは Google Apps Script(以下GAS) を用いて WebAssembly(以下wasm) に入門するための紹介を行います
GAS や wasm, Rust などの基本的な説明は行いません
なぜGAS?
GASの実行環境もV8ランタイムがサポートされており、wasmが使えた場合はGASやspreadsheetなどを用いる業務に活かすことができそうだと思い検証してみました
準備するもの
- 生成したwasmファイルをホストできる環境
wasmファイルの生成
GASではTextEncoderなど対応されていないAPIがあるためそのままではGoなど一部の言語を用いて生成したwasmを使用することはできません
もしGoを用いて実行したい場合はwasm_exec.jsで実装してあるAPIをGAS向けに実装しなおす必要などがあります。(未検証)
そのため、今回はRustを用いてwasmファイルを生成します
#[no_mangle]
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
今回は wasm32-unknown-unknown
をターゲットとし、ビルドします
wasm32-wasi
でも可能ですが手順が少し変わります。(後述)
$ cargo build --target=wasm32-unknown-unknown
./target/wasm32-unknown-unknown/debug
配下にpackage名のwasmファイルが生成されているはずなのでそれをホストできる環境などにアップロードします
GAS
まずは WebAssembly.Instance オブジェクトを生成します
let instance;
(async () => {
const resp = UrlFetchApp.fetch('ホストしたwasmファイルのURL')
const obj = await WebAssembly.instantiate(new Uint8Array(resp.getContent()).buffer);
instance = obj.instance
})();
GASにはfetch APIは存在しないため、UrlFetchApp.fetchを用いてファイルを取得します
取得したファイルデータをバイナリコードに変換しWebAssembly.instantiate()
を用いてinstanceを生成します
現在では、WebAssembly.instantiateStreaming()
を用いることが推奨されていますがGASには存在しないためWebAssembly.instantiate()
を使用します
そのため、今回使用するホストサーバーが MIMEタイプ application/wasm
で返してくれなくても問題ありません
function main(){
console.log(instance.exports.add(5, 10))
}
後は生成されたinstanceからエクスポートされたwasm関数を呼び出すだけです
wasm32-wasiの場合
wasm32-wasiをターゲットにビルドする場合は必要となるAPIを実装する必要があります。
let instance;
(async () => {
const resp = UrlFetchApp.fetch('ホストしたwasmファイルのURL')
var importObject = {
// 必要となるAPIの実装
wasi_snapshot_preview1: {
proc_exit: () => {...},
fd_write: () => {...},
fd_prestat_get: () => {...},
fd_prestat_dir_name: () => {...},
environ_sizes_get: () => {...},
environ_get: () => {...}
},
}
const obj = await WebAssembly.instantiate(new Uint8Array(resp.getContent()).buffer, importObject);
instance = obj.instance
})();
以下記事がとても参考になります
おわりに
GASでもwasmを動かすことができました
今回はwasmを自作しましたが、wapm.ioなどすでにホストサービスが存在しているためもっとwasmが賑わったらGASでもwasmの恩恵を受けられるかもしれません
wasm楽しいのでこれからも色々と追っていきたいと思います!