Stream: wit-bindgen

Topic: Example steps for a component with TinyGo


view this post on Zulip adam (Mar 23 2024 at 03:17):

Hey. Following along the instructions at https://github.com/bytecodealliance/wit-bindgen?tab=readme-ov-file#guest-tinygo

I'm not sure how to tinygo build if my-component.go is using package main, because then I can't access the wit-bindgen generated Go types in the package matching the interface name in my wit file. I'm using wit-bindgen to generate in the same directory as my-component.go, even though the example uses a subdirectory called gen. Am I supposed to generate the subpackage and install it in $GOPATH and resolve with a full repository/module url?

A language binding generator for WebAssembly interface types - bytecodealliance/wit-bindgen

view this post on Zulip adam (Mar 23 2024 at 04:02):

Got it working by treating it like a separate Go package. Derp.

view this post on Zulip Randy Reddig (Mar 24 2024 at 07:52):

We’re working on pure Go bindings for TinyGo: https://github.com/ydnar/wasm-tools-go

WebAssembly + Component Model tools for Go. Contribute to ydnar/wasm-tools-go development by creating an account on GitHub.

view this post on Zulip Randy Reddig (Mar 24 2024 at 07:55):

Currently it can generate Go bindings for imports, but not (yet) exports. It maps WIT types to their equivalent Go types where possible (e.g. enum->constants, records->structs, resources->handle types with methods).

view this post on Zulip Rajat Jindal (Apr 01 2024 at 15:35):

Hi @Randy Reddig , I was trying out this binding generator, and ran into a issue. it is quite possible that it is due to WIP support for exports in wasm-tools-go, in which case I apologize to waste your time in advance:

foo.wit

interface foo {
    greet: func() -> string;
}

from running wasm-tools component wit ./foo-wit -j > wit.json

    {
      "name": "foo",
      "types": {},
      "functions": {
        "greet": {
          "name": "greet",
          "kind": "freestanding",
          "params": [],
          "results": [
            {
              "type": "string"
            }
          ]
        }
      },
      "package": 7
    }

Then on trying to build using tinygo (using branch from here: https://github.com/dgryski/tinygo/tree/dgryski/wasi-preview-2):

tinygo build -target=wasip2 -wit-package ./foo-wit -wit-world foo-namespace:pkg/foo-world -o main.wasm -x -work main.go

error: failed to encode a component from module

Caused by:
    0: failed to decode world from module
    1: module was not valid
    2: failed to validate exported interface `foo-namespace:pkg/foo@2.0.0`
    3: type mismatch for function `greet`: expected `[] -> [I32]` but found `[I32, I32] -> []`
error: wasm-tools failed: exit status 1

On trying to use wasm-tools to check the intermediary wasm file:

from running: wasm-tools mutate /var/folders/5r/6y6fr12x1dq6qnt74zn4_1wm0000gn/T/tinygo226195887/main -t | grep -i greet | head -1:

(Notice the param i32 i32, I was expecting it to be something like (param i32) (result i32)

  (func $foo-namespace:pkg/foo@2.0.0#greet (;259;) (type 0) (param i32 i32)

The repo where I was trying this out is here: https://github.com/rajatjindal/foo-wasip2

is it possibly by any chance to workaround this prob or should I wait for wasm-tools-go to have complete exports support.

Go compiler for small places. Microcontrollers, WebAssembly, and command-line tools. Based on LLVM. - GitHub - dgryski/tinygo at dgryski/wasi-preview-2
Contribute to rajatjindal/foo-wasip2 development by creating an account on GitHub.

view this post on Zulip Randy Reddig (Apr 01 2024 at 16:24):

Exports aren’t working yet

view this post on Zulip Randy Reddig (Apr 01 2024 at 16:24):

You can write them by hand with //export in TinyGo

view this post on Zulip Randy Reddig (Apr 01 2024 at 16:24):

with the fully-qualified namespace:package/interface#function name

view this post on Zulip Rajat Jindal (Apr 01 2024 at 16:29):

thank you for your reply. I did try that, but still got same error (tried with both with init and without it):

package foo

type Impl struct{}

//export foo-namespace:pkg/foo@2.0.0#greet
func (i *Impl) Greet() string {
    return "hello from greet"
}

func init() {
    instance = &Impl{}
}

view this post on Zulip Mossaka (Joe) (Apr 03 2024 at 22:00):

adam said:

Hey. Following along the instructions at https://github.com/bytecodealliance/wit-bindgen?tab=readme-ov-file#guest-tinygo

I'm not sure how to tinygo build if my-component.go is using package main, because then I can't access the wit-bindgen generated Go types in the package matching the interface name in my wit file. I'm using wit-bindgen to generate in the same directory as my-component.go, even though the example uses a subdirectory called gen. Am I supposed to generate the subpackage and install it in $GOPATH and resolve with a full repository/module url?

In the latest release of wit-bindgen-cli, I've included a flag to rename the package name of generated Go code to an user provided one. Hope that helps

e.g.

wit-bindgen tiny-go wasi-http/wit --world proxy --rename-package=test

view this post on Zulip Mossaka (Joe) (Apr 03 2024 at 22:25):

I made some modification to the README and updated the example code: https://github.com/bytecodealliance/wit-bindgen/pull/921

Hopefully it should clarify things a bit :)

adds a command to initialize the Go directory and repalces Pirnt to HostPrint in the eample code.

view this post on Zulip adam (Apr 03 2024 at 22:39):

I think in my case I didn't have a valid golang module. Do you know why components compiled with TinyGo are 10-12 times smaller than compiled Rust components? Also, if I compiled a golang function with TinyGo that just adds two numbers, why does it need to have all the WASI imports in the component for a full fledge application?

A single line fn that just uses s32 and mod operator has all these imports. Filesystem and Stdio seem unnecessary.

package root:component;

world root {
  import wasi:io/error@0.2.0;
  import wasi:io/streams@0.2.0;
  import wasi:cli/stdin@0.2.0;
  import wasi:cli/stdout@0.2.0;
  import wasi:cli/stderr@0.2.0;
  import wasi:clocks/wall-clock@0.2.0;
  import wasi:filesystem/types@0.2.0;
  import wasi:filesystem/preopens@0.2.0;

  export is-odd-or-even: func(number: s32) -> bool;
}

view this post on Zulip Randy Reddig (Apr 03 2024 at 22:41):

You’ve got it partially right. The function signature of the export needs to match what’s in the WIT.

Are you using wit-bindgen or wit-bindgen-go?

Rajat Jindal said:

thank you for your reply. I did try that, but still got same error (tried with both with init and without it):

package foo

type Impl struct{}

//export foo-namespace:pkg/foo@2.0.0#greet
func (i *Impl) Greet() string {
    return "hello from greet"
}

func init() {
    instance = &Impl{}
}

view this post on Zulip Rajat Jindal (Apr 04 2024 at 07:13):

Are you using wit-bindgen or wit-bindgen-go?

I am trying out wit-bindgen-go

view this post on Zulip Rajat Jindal (Apr 04 2024 at 10:30):

thank you for the pointer. i was able to fix that by changing def to:

package foo

func init() {
    instance = &Impl{}
}

type Impl struct{}

func (i *Impl) Greet() string {
    return "hello from greet"
}

//export foo-namespace:pkg/foo@2.0.0#greet
func GreetExported() *string {
    x := instance.Greet()
    return &x
}

this atleast get post the export error i was getting earlier.

view this post on Zulip Rajat Jindal (Apr 04 2024 at 16:51):

I tried implementing the export bindings for response-outparam (for inbound-http), but that seemed quite involved. I will try it again over the weekend.


Last updated: Dec 23 2024 at 12:05 UTC