🔖

jco componentizeで-d allしてもimport wasi:io/pollが残ってしまう

2025/01/10に公開

発生事象

jcoのドキュメント上にあるサンプルをベースに以下を実行する。

> npx jco --version
1.8.1
> npx jco componentize cowsay.js --wit cowsay.wit -o cowsay.wasm
> npx jco wit .\cowsay.wasm                  
package root:component;

world root {
  import wasi:io/error@0.2.2;
  import wasi:io/poll@0.2.2;
  import wasi:io/streams@0.2.2;
  import wasi:cli/stdin@0.2.2;
  import wasi:cli/stdout@0.2.2;
  import wasi:cli/stderr@0.2.2;
  import wasi:cli/terminal-input@0.2.2;
  import wasi:cli/terminal-output@0.2.2;
  import wasi:cli/terminal-stdin@0.2.2;
  import wasi:cli/terminal-stdout@0.2.2;
  import wasi:cli/terminal-stderr@0.2.2;
  import wasi:clocks/monotonic-clock@0.2.2;
  import wasi:clocks/wall-clock@0.2.2;
  import wasi:filesystem/types@0.2.2;
  import wasi:filesystem/preopens@0.2.2;
  import wasi:random/random@0.2.2;
  import wasi:http/types@0.2.2;
  import wasi:http/outgoing-handler@0.2.2;

  export cow: interface {
    enum cows {
      default,
      owl,
    }

    say: func(text: string, cow: option<cows>) -> string;
  }
}

> npx jco componentize cowsay.js --wit cowsay.wit -o cowsay.wasm -d all
> npx jco wit .\cowsay.wasm                  
package root:component;

world root {
  import wasi:io/poll@0.2.2;

  export cow: interface {
    enum cows {
      default,
      owl,
    }

    say: func(text: string, cow: option<cows>) -> string;
  }
}

本来jcoの-dオプションにallを指定するとimportがなくなるはずだが、wasi:io/pollが残ってしまう。

推測される原因

ComponentizeJSでは同問題の報告がある。
ComponentizeJS側では修正をリリース済みだが、jcoには取り込まれていないと考えられる。

https://github.com/bytecodealliance/ComponentizeJS/issues/159
https://github.com/bytecodealliance/ComponentizeJS/pull/162

対処法

ComponentizeJSを直接利用する。
参考:https://github.com/bytecodealliance/ComponentizeJS/blob/main/EXAMPLE.md

componentize-jsのバージョン

> npm list @bytecodealliance/componentize-js
20250109_jco@1.0.0
├── @bytecodealliance/componentize-js@0.15.1
└─┬ @bytecodealliance/jco@1.8.1
  └── @bytecodealliance/componentize-js@0.14.0

以下の内容でconvert.mjsを作成

import { componentize } from '@bytecodealliance/componentize-js';
import { readFile, writeFile } from 'node:fs/promises';

const jsSource = await readFile('cowsay.js', 'utf8');
const witSource = await readFile('cowsay.wit', 'utf8');

const { component } = await componentize(jsSource, witSource, {disableFeatures: ['clocks', 'http', 'random', 'stdio']});

await writeFile('cowsay2.wasm', component);

以下のコマンドを実行

> node convert.mjs
> npx jco wit .\cowsay2.wasm
package root:component;

world root {
  export cow: interface {
    enum cows {
      default,
      owl,
    }

    say: func(text: string, cow: option<cows>) -> string;
  }
}

生成されたwasmファイルは10MBくらい、変換には50秒(@Core i5-8265U)程度を要した。
(かなり弱めのCPUなので通常のデスクトップならもっと早いと思われる)

動作確認

実際に動かしてみる。
WASM Componentは動かす方法が良く分からない...(適当にcli向けラッパを作るのが良い?)

wasmtime run(失敗)

wasmtime runでinvokeは出来無さそう

>wasmtime run --invoke say cowsay2.wasm                                          
Error: failed to run main module `cowsay2.wasm`

Caused by:
    using `--invoke` with components is not supported

Pythonから

Pythonから呼んでみる。
(参考: https://component-model.bytecodealliance.org/language-support/python.html#running-components-from-python-applications

binding生成

> pipenv run python -m wasmtime.bindgen cowsay2.wasm --out-dir cowsay2py   
Generating cowsay2py\__init__.py
Generating cowsay2py\exports\__init__.py
Generating cowsay2py\exports\cow.py
Generating cowsay2py\intrinsics.py
Generating cowsay2py\root.core0.wasm

load2.py

from cowsay2py import Root
from cowsay2py.exports.cow import Cow, Cows
from wasmtime import Store

def main():
    store = Store()
    component = Root(store)
    cow = Cow(component)
    print(cow.say(store, "Hello, World!", Cows.DEFAULT))
    print(cow.say(store, "Hello, World from owl!", Cows.OWL))

if __name__ == '__main__':
    main()

実行

> pipenv run python .\load2.py                                         
Hello, World!
    \   ^__^
      \  (oo)\______
        (__)\      )/\
            ||----w |
            ||     ||

Hello, World from owl!
     ___
    (o o)
   (  V  )
  /--m-m-

Discussion