From a5ff1f52d0eb91761692a5380672363cdedc3c64 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Wed, 16 Jul 2025 21:42:49 -0700 Subject: [PATCH 1/4] Revise Go language support section Added more details where necessary. Factored code examples out into separate files and included them. Made the "Testing the add component" section consistent with other examples involving the example host. --- .../examples/tutorial/go/adder/main.go | 16 ++ .../examples/tutorial/wit/adder/world2.wit | 11 ++ component-model/src/language-support/go.md | 137 +++++++++--------- 3 files changed, 93 insertions(+), 71 deletions(-) create mode 100644 component-model/examples/tutorial/go/adder/main.go create mode 100644 component-model/examples/tutorial/wit/adder/world2.wit diff --git a/component-model/examples/tutorial/go/adder/main.go b/component-model/examples/tutorial/go/adder/main.go new file mode 100644 index 00000000..a7415113 --- /dev/null +++ b/component-model/examples/tutorial/go/adder/main.go @@ -0,0 +1,16 @@ +//go:generate go tool wit-bindgen-go generate --world adder --out internal ./docs:adder@0.1.0.wasm + +package main + +import ( + "example.com/internal/docs/adder/add" +) + +func init() { + add.Exports.Add = func(x uint32, y uint32) uint32 { + return x + y + } +} + +// main is required for the `wasi` target, even if it isn't used. +func main() {} diff --git a/component-model/examples/tutorial/wit/adder/world2.wit b/component-model/examples/tutorial/wit/adder/world2.wit new file mode 100644 index 00000000..6c4b9cbc --- /dev/null +++ b/component-model/examples/tutorial/wit/adder/world2.wit @@ -0,0 +1,11 @@ +package docs:adder@0.1.0; + +interface add { + add: func(x: u32, y: u32) -> u32; +} + +world adder { + include wasi:cli/imports@0.2.0; + + export add; +} \ No newline at end of file diff --git a/component-model/src/language-support/go.md b/component-model/src/language-support/go.md index e3b6cc6e..3b645b5c 100644 --- a/component-model/src/language-support/go.md +++ b/component-model/src/language-support/go.md @@ -2,8 +2,10 @@ The [TinyGo compiler](https://tinygo.org/) v0.34.0 and above has native support for the WebAssembly Component Model and WASI 0.2.0. -This guide walks through building a component that implements `adder` world defined in the [`adder/world.wit` package][adder-wit]. -The component will implement the `adder` world, which contains `add` interface with a `add` function. +This guide walks through building a component that implements +the `adder` world defined in the [`adder/world.wit` package][adder-wit]. +The component will implement the `adder` world, +which contains an `add` interface with an `add` function. [adder-wit]: https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/tutorial/wit/adder/world.wit @@ -32,9 +34,13 @@ $ wasm-tools -V wasm-tools 1.255.0 ... ``` -Optional: Install the [`wkg`][wkg] CLI tool to resolve the imports in the WIT file. The `wkg` CLI is a part of the [Wasm Component package manager](https://github.com/bytecodealliance/wasm-pkg-tools/releases) +Optional: Install the [`wkg`][wkg] CLI tool to resolve the imports in the WIT file. +The `wkg` CLI is a part of the [Wasm Component package manager][wasm-pkg-tools-releases]. +See [the wasm-pkg-tools installation instructions][wasm-pkg-tools] to install manually or using `cargo`. [wkg]: https://github.com/bytecodealliance/wasm-pkg-tools/tree/main/crates/wkg +[wasm-pkg-tools]: https://github.com/bytecodealliance/wasm-pkg-tools?tab=readme-ov-file#installation +[wasm-pkg-tools-releases]: https://github.com/bytecodealliance/wasm-pkg-tools/releases ## 2. Create your Go project @@ -45,12 +51,10 @@ mkdir add && cd add go mod init example.com ``` -Ensure that the following `tool`s are installed: +Install the following `tool`: -``` -tool ( - go.bytecodealliance.org/cmd/wit-bindgen-go -) +```console +go get -tool go.bytecodealliance.org/cmd/wit-bindgen-go ``` > [!NOTE] @@ -60,41 +64,28 @@ Consider also running `go mod tidy` after adding the above tool. [go-1-24-release]: https://go.dev/blog/go1.24 -## 2. Determine which World the Component will Implement +## 2. Determine which world the component will implement -Since we will be implementing the [`adder` world][adder-wit], we can copy the WIT to our project, -under the `wit` folder (e.g. `wit/component.wit`): +Since we will be implementing the [`adder` world][adder-wit], we can copy the WIT to our project. +Create a subdirectory called `wit` and paste the following code +into a file called `wit/component.wit`: ```wit -package docs:adder@0.1.0; - -interface add { - add: func(x: u32, y: u32) -> u32; -} - -world adder { - export add; -} +{{#include ../../examples/tutorial/wit/adder/world2.wit}} ``` -The `wasip2` target of TinyGo assumes that the component is targeting `wasi:cli/command@0.2.0` world -(part of [`wasi:cli`][wasi-cli]) so it requires the imports of `wasi:cli/imports@0.2.0`. - -We need to include those interfaces as well in `component.wit`, by editing the `adder` world: - -```wit -world adder { - include wasi:cli/imports@0.2.0; - export add; -} -``` +The line `include wasi:cli/imports@0.2.0` is necessary because +we are using the `wasip2` target of TinyGo. +TinyGo assumes that the component targets the `wasi:cli/command@0.2.0` world +(part of [`wasi:cli`][wasi-cli]), +so it requires the imports of `wasi:cli/imports@0.2.0`. ### Using `wkg` to automatically resolve and download imports Tools like [`wkg`][wkg] can be convenient to build a complete WIT package by resolving the imports. -Running the `wkg wit fetch` command will resolve the imports and populate your `wit` folder with all relevant -imported namespaces and packages. +Running the `wkg wit build` command will resolve the imports +and populate your `wit` folder with all relevant imported namespaces and packages. ``` $ wkg wit build @@ -105,8 +96,8 @@ WIT package written to docs:adder@0.1.0.wasm ## 3. Generate bindings for the Wasm component -Now that we have our WIT definitions bundled together into a WASM file, -we can generate the bindings for our Wasm component, by adding a build directive: +Now that we have our WIT definitions bundled together into a `.wasm` file, +we can generate the bindings for our WebAssembly component, by adding a build directive: ```console go tool wit-bindgen-go generate --world adder --out internal ./docs:adder@0.1.0.wasm @@ -116,7 +107,7 @@ go tool wit-bindgen-go generate --world adder --out internal ./docs:adder@0.1.0. > The `go tool` directive (added in [Golang 1.24][go-1-24-release]) installs and enables use of `wit-bindgen-go`, > part of the Bytecode Alliance suite of Golang tooling. -The `internal` directory will contain the generated Go code that WIT package. +The `internal` directory will contain the generated Go code for that WIT package. ```console $ tree internal @@ -254,50 +245,54 @@ internal 39 directories, 91 files ``` -The `adder.exports.go` file contains the exported functions that need to be implemented in the Go code called `Exports`. +The `add.exports.go` file contains an `Exports` struct, containing declarations for +the exported functions that need to be implemented in the Go code. ## 4. Implement the `add` Function -```Go -//go:generate go tool wit-bindgen-go generate --world adder --out internal ./docs:adder@0.1.0.wasm +In your `add` directory, create a file called `main.go` +and paste the following code into it: -package main - -import ( - "example.com/internal/docs/adder/add" -) - -func init() { - add.Exports.Add = func(x uint32, y uint32) uint32 { - return x + y - } -} - -// main is required for the `wasi` target, even if it isn't used. -func main() {} +```Go +{{#include ../../examples/tutorial/go/adder/main.go}} ``` -Go's `init` functions are used to do initialization tasks that -should be done before any other tasks. In this case, we are using it to export the `Add` function. +Go's `init` function is used to do initialization tasks +that should be done before any other tasks. +In this case, we are using it to export the `Add` function. ## 5. Build the Component -We can build our component using TinyGo by specifying the wit-package to be `add.wit` and the WIT world to be `adder`. - -Under the hood, TinyGo invokes `wasm-tools` to embed the WIT file to the module and componentize it. +We can build our component using TinyGo. +Under the hood, TinyGo invokes `wasm-tools` +to embed the WIT file to the module and componentize it. ```console -tinygo build -target=wasip2 -o add.wasm --wit-package docs:adder@0.1.0.wasm --wit-world adder main.go +tinygo build -target=wasip2 -o adder.wasm \ + --wit-package docs:adder@0.1.0.wasm \ + --wit-world adder main.go ``` -> **WARNING:** By default, tinygo includes all debug-related information in your .wasm file. That is desirable when prototyping or testing locally to obtain useful backtraces in case of errors (for example, with `wasmtime::WasmBacktraceDetails::Enable`). To remove debug data and optimize your binary file, build with `-no-debug`. The resulting .wasm file will be considerably smaller (up to 75% reduction in size). +* The `-target=wasip2` flag specifies that the code should be compiled + to WebAssembly using Preview 2 methods. +* The `-o adder.wasm` flag directs the output to be saved in `add.wasm` in the current directory. +* The `--wit-package` flag specifies the package name for the WIT code we are using. +* The `--wit-world` flag specifies that the WIT world that defines the imports and exports + for our component is `adder`. -We now have an add component that satisfies our `adder` world, exporting the `add` function, which +We now have an `adder` component that satisfies our `adder` world, exporting the `add` function. + +> [!WARNING] +> By default, tinygo includes all debug-related information in your .wasm file. +> That is desirable when prototyping or testing locally to obtain useful backtraces in case of errors +> (for example, with `wasmtime::WasmBacktraceDetails::Enable`). +> To remove debug data and optimize your binary file, build with `-no-debug`. +> The resulting .wasm file will be considerably smaller (up to 75% reduction in size). We can confirm using the `wasm-tools component wit` command: ```console -$ wasm-tools component wit add.wasm +$ wasm-tools component wit adder.wasm package root:component; world root { @@ -313,20 +308,20 @@ world root { ## 5. Testing the `add` Component -To run our add component, we need to use a host program with a WASI runtime that understands the -`example` world -- we've provided an [`example-host`][example-host] that does just that. +The following section requires you to have [a Rust toolchain][rust] installed. -The example host calls the `add` function of a passed in component providing two operands. +To run our add component, we need to use a host program with a WASI runtime that understands +the `example` world. -To use the example host, clone this repository and run the Rust program: +{{#include example-host-part1.md}} -```console -git clone git@github.com:bytecodealliance/component-docs.git -cd component-docs/component-model/examples/example-host -cargo run --release -- 1 2 /path/to/add.wasm -``` +A successful run should show the following output +(of course, the paths to your example host and adder component will vary): + +{{#include example-host-part2.md}} [example-host]: https://github.com/bytecodealliance/component-docs/tree/main/component-model/examples/example-host +[rust]: https://www.rust-lang.org/learn/get-started [!NOTE]: # [!WARNING]: # From 9add2d3cab51815a5e78a26decc338d7f7de0210 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Thu, 4 Sep 2025 17:43:20 -0700 Subject: [PATCH 2/4] Move WIT example into a separate directory so it doesn't affect the tutorial build --- component-model/examples/tutorial/{wit => go}/adder/world2.wit | 0 component-model/src/language-support/go.md | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename component-model/examples/tutorial/{wit => go}/adder/world2.wit (100%) diff --git a/component-model/examples/tutorial/wit/adder/world2.wit b/component-model/examples/tutorial/go/adder/world2.wit similarity index 100% rename from component-model/examples/tutorial/wit/adder/world2.wit rename to component-model/examples/tutorial/go/adder/world2.wit diff --git a/component-model/src/language-support/go.md b/component-model/src/language-support/go.md index 3b645b5c..50328f27 100644 --- a/component-model/src/language-support/go.md +++ b/component-model/src/language-support/go.md @@ -71,7 +71,7 @@ Create a subdirectory called `wit` and paste the following code into a file called `wit/component.wit`: ```wit -{{#include ../../examples/tutorial/wit/adder/world2.wit}} +{{#include ../../examples/tutorial/go/adder/world2.wit}} ``` The line `include wasi:cli/imports@0.2.0` is necessary because From f033734ba751cf008c412c839b7747377b4c6593 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Mon, 8 Sep 2025 17:52:53 -0700 Subject: [PATCH 3/4] Update component-model/src/language-support/go.md Co-authored-by: Victor Adossi <123968127+vados-cosmonic@users.noreply.github.com> --- component-model/src/language-support/go.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/component-model/src/language-support/go.md b/component-model/src/language-support/go.md index 50328f27..b3acfc12 100644 --- a/component-model/src/language-support/go.md +++ b/component-model/src/language-support/go.md @@ -268,7 +268,8 @@ Under the hood, TinyGo invokes `wasm-tools` to embed the WIT file to the module and componentize it. ```console -tinygo build -target=wasip2 -o adder.wasm \ +tinygo build -target=wasip2 \ + -o adder.wasm \ --wit-package docs:adder@0.1.0.wasm \ --wit-world adder main.go ``` From b55054c57aa6dbd9d7dc442250d6cd569820d1c9 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Tue, 9 Sep 2025 12:24:53 -0700 Subject: [PATCH 4/4] Clarify what `wit wkg build` does --- component-model/src/language-support/go.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/component-model/src/language-support/go.md b/component-model/src/language-support/go.md index b3acfc12..1f190458 100644 --- a/component-model/src/language-support/go.md +++ b/component-model/src/language-support/go.md @@ -84,8 +84,9 @@ so it requires the imports of `wasi:cli/imports@0.2.0`. Tools like [`wkg`][wkg] can be convenient to build a complete WIT package by resolving the imports. -Running the `wkg wit build` command will resolve the imports -and populate your `wit` folder with all relevant imported namespaces and packages. +Running the `wkg wit build` command encodes the WIT into the Component Model binary format. +As a side effect, it resolves the imports +and populates your `wit` folder with all relevant imported namespaces and packages. ``` $ wkg wit build