Stream: wasmtime

Topic: Using wasi 0.2 in WAT (WebAssembly Text Format)


view this post on Zulip Binus (Oct 24 2024 at 16:07):

I'm trying to write WAT (WebAssembly Text Format) to understand WebAssembly better. I'd like to perform some I/O operations and I was able to find that importing "wasi_snapshot_preview1" "fd_write" let's you write to stdout. I'd like to learn how to use wasi 0.2 as well, but I'm having trouble finding the namespace used for it. I know I am missing something, and it's probably somewhere in you documentation or source code.

view this post on Zulip Lann Martin (Oct 24 2024 at 17:00):

Stdout is handled through the wasi:cli/stdout interface, in conjunction with wasi:io's output-stream resource. For hand-written code you'd probably be most interested in the blocking-write-and-flush method which avoids a lot of complexity around non-blocking operations.

WebAssembly System Interface. Contribute to WebAssembly/WASI development by creating an account on GitHub.
WebAssembly System Interface. Contribute to WebAssembly/WASI development by creating an account on GitHub.
WebAssembly System Interface. Contribute to WebAssembly/WASI development by creating an account on GitHub.

view this post on Zulip Binus (Oct 24 2024 at 21:35):

Lann Martin said:

Stdout is handled through the wasi:cli/stdout interface, in conjunction with wasi:io's output-stream resource. For hand-written code you'd probably be most interested in the blocking-write-and-flush method which avoids a lot of complexity around non-blocking operations.

Thank you for the reply. However, I could not figure it out. Maybe I am missing something obvious, but I can't figure out how to write the import statement for those functions. I tried a variety of version of something like:

(module $test
  (import "wasi:cli/stdout" "get-stdout" (func ...))
)

And more for the "blocking-write-and-flush" function you mentioned. I'm sorry if I'm missing something obvious. I've tried to look at the wit documentation and wat documentation, but I don't think I understand it well enough.

view this post on Zulip Alex Crichton (Oct 24 2024 at 21:42):

one perhaps useful bit of context here is that unlike WASIp1 the WASIp2 proposals (e.g. wasi 0.2) are defined in terms of the component model, not core wasm. That means that unlike WASIp1 there isn't a single definition you can do in core wasm.

Tooling conventions are in place, however, to be able to convert a core wasm module from core wasm to a component. This involves some understanding of components and the translations being made here though. One thing you can try out is to use wasm-tools component embed --dummy ./wit to explore what core wasm can do. That emits a core wasm module which uses the world definition within ./wit. If you've got a copy of wasi:cli then you can pass --world wasi:cli/command (or something similar to that) to generate a core wasm module that has access to all of the various imports. You probably don't need everything so you can trim it down to what you want.

As to what all the parameters/results are, that's where the canonical ABI of the component model kicks in

view this post on Zulip Alex Crichton (Oct 24 2024 at 21:44):

So for example if you check out this repo and run wasm-tools component embed --dummy ./wit --world command -t then you should see something like:

(module
  ;; ...
  (import "cm32p2|wasi:cli/environment@0.2" "get-environment" (func (;0;) (type 0)))
  (import "cm32p2|wasi:cli/environment@0.2" "get-arguments" (func (;1;) (type 0)))
  ;; ...
  (import "cm32p2|wasi:io/streams@0.2" "[method]output-stream.blocking-write-and-flush" (func (;17;) (type 5)))
  ;; ...
  (import "cm32p2|wasi:cli/stdin@0.2" "get-stdin" (func (;27;) (type 7)))
  (import "cm32p2|wasi:cli/stdout@0.2" "get-stdout" (func (;28;) (type 7)))
  (import "cm32p2|wasi:cli/stderr@0.2" "get-stderr" (func (;29;) (type 7)))
  ;; ...
  (memory (;0;) 0)
  (export "cm32p2|wasi:cli/run@0.2|run" (func 136))
  (export "cm32p2_memory" (memory 0))
  (func (;136;) (type 7) (result i32)
    unreachable
  )
  ;; ...
Command-Line Interface (CLI) World for WASI. Contribute to WebAssembly/wasi-cli development by creating an account on GitHub.

view this post on Zulip Alex Crichton (Oct 24 2024 at 21:45):

You can sort of edit and fill in the skeleton with raw *.wat if you'd like

view this post on Zulip Alex Crichton (Oct 24 2024 at 21:45):

that can then turn into a component with wasm-tools component new

view this post on Zulip Alex Crichton (Oct 24 2024 at 21:51):

so for example this module:

(module
  (import "cm32p2|wasi:io/streams@0.2" "[method]output-stream.blocking-write-and-flush" (func $blocking-write-and-flush (param i32 i32 i32 i32)))
  (import "cm32p2|wasi:cli/stdout@0.2" "get-stdout" (func $get-stdout (result i32)))
  (func (export "cm32p2|wasi:cli/run@0.2|run") (result i32)
    (call $blocking-write-and-flush
      (call $get-stdout)
      (i32.const 100)
      (i32.const 6)
      (i32.const 200))
    (i32.const 0)
  )

  (memory (export "cm32p2_memory") 1)

  (data (i32.const 100) "hello\n")
)

runs like so:

$ wasm-tools component embed  ./wit --world command  foo.wat -o foo.core.wasm
$ wasm-tools component new foo.core.wasm -o foo.component.wasm
$ wasmtime run foo.wasm
hello

view this post on Zulip Binus (Oct 24 2024 at 22:47):

Alex Crichton said:

one perhaps useful bit of context here is that unlike WASIp1 the WASIp2 proposals (e.g. wasi 0.2) are defined in terms of the component model, not core wasm. That means that unlike WASIp1 there isn't a single definition you can do in core wasm.

Tooling conventions are in place, however, to be able to convert a core wasm module from core wasm to a component. This involves some understanding of components and the translations being made here though. One thing you can try out is to use wasm-tools component embed --dummy ./wit to explore what core wasm can do. That emits a core wasm module which uses the world definition within ./wit. If you've got a copy of wasi:cli then you can pass --world wasi:cli/command (or something similar to that) to generate a core wasm module that has access to all of the various imports. You probably don't need everything so you can trim it down to what you want.

As to what all the parameters/results are, that's where the canonical ABI of the component model kicks in

Some things you mentioned went over my head ;) But I got wasi 2 up and running now so thank you! I'm a little confused about one thing though. I'm mostly interested in WebAssembly for its cross compatibility, but I see now that our names for the same modules are slightly different. My "cmp32p2|wasi:io/streams@0.2" is called "wasi:io/stream@0.2.2". So, would my compiled "foo.component.wasm" work on your machine?

view this post on Zulip Alex Crichton (Oct 25 2024 at 00:11):

For more component-related docs if you're interested I'd recommend browsing these docs, but otherwise:

My "cmp32p2|wasi:io/streams@0.2" is called "wasi:io/stream@0.2.2". So, would my compiled "foo.component.wasm" work on your machine?

Yes, this has to do with how versions work in component runtimes and how core wasm is wrapped up into components, but the general idea is that it shoudl all work out ok

view this post on Zulip Binus (Oct 25 2024 at 13:50):

Alex Crichton said:

For more component-related docs if you're interested I'd recommend browsing these docs, but otherwise:

My "cmp32p2|wasi:io/streams@0.2" is called "wasi:io/stream@0.2.2". So, would my compiled "foo.component.wasm" work on your machine?

Yes, this has to do with how versions work in component runtimes and how core wasm is wrapped up into components, but the general idea is that it shoudl all work out ok

Nice! The .wasm file works on both of my computers. There is a lot to unpack in these final .wasm files. I would ask more questions, but it's probably best if I read the docs for component syntax first. Thank you for your help.


Last updated: Dec 23 2024 at 13:07 UTC