diff --git a/examples/hello-world/hello-world.go.en-us.md b/examples/hello-world/hello-world.go.en-us.md index 8ed84f1..e64065c 100644 --- a/examples/hello-world/hello-world.go.en-us.md +++ b/examples/hello-world/hello-world.go.en-us.md @@ -4,7 +4,7 @@ ## Overview -For our first program, we will be doing a "Hello world" type of program in [Golang (Go)](https://golang.org/), using the [TinyGo Compiler](https://tinygo.org/). Go is a popular open source general purpose programming language. TinyGo is a compiler based on [LLVM](https://llvm.org/), that helps bring Go to embedable devices int the IoT space like microcontrollers. [WebAssembly support in the Go ecosystem](https://github.com/golang/go/wiki/WebAssembly) is still a bit young (as of April, 2020). For example, Wasm modules tend to be a bit large and support for new Wasm specifications like the [WebAssembly System Interface (WASI)](https://github.com/golang/go/issues/31105) are bit behind, compared to other mature WebAssembly toolchains. To help with our Wasm module sizes, we are using TinyGo, as this will generate much smaller Wasm modules, at the expense of some missing or incomplete features from the Go stdlib. +For our first program, we will be doing a "Hello world" type of program in [Golang (Go)](https://golang.org/), using the [TinyGo Compiler](https://tinygo.org/). Go is a popular open source general purpose programming language. TinyGo is a compiler based on [LLVM](https://llvm.org/), that helps bring Go to embedable devices int the IoT space like microcontrollers. [WebAssembly support in the Go ecosystem](https://github.com/golang/go/wiki/WebAssembly) is still a bit young (as of July, 2021). For example, Wasm modules tend to be a bit large and support for new Wasm specifications like the [WebAssembly System Interface (WASI)](https://github.com/golang/go/issues/31105) are bit behind, compared to other mature WebAssembly toolchains. To help with our Wasm module sizes, we are using TinyGo, as this will generate much smaller Wasm modules, at the expense of some missing or incomplete features from the Go stdlib. To see a list of the supported stdlib by TinyGo, please visit the [language support section in the TinyGo documentation](https://tinygo.org/docs/reference/lang-support/). To keep things simple with Wasm's limitations mentioned [in the introduction example](/example-redirect?exampleName=introduction&programmingLanguage=all), instead of displaying a string, we will add two numbers together and display the result. Though, it is good to keep in mind, in later examples, a lot of these limitations will be abstracted away by your WebAssembly Language of choice (In this case, Go). diff --git a/examples/wasi-hello-world/demo/go/helloworld.txt b/examples/wasi-hello-world/demo/go/helloworld.txt new file mode 100644 index 0000000..cd08755 --- /dev/null +++ b/examples/wasi-hello-world/demo/go/helloworld.txt @@ -0,0 +1 @@ +Hello world! diff --git a/examples/wasi-hello-world/demo/go/main.go b/examples/wasi-hello-world/demo/go/main.go new file mode 100644 index 0000000..5c06d37 --- /dev/null +++ b/examples/wasi-hello-world/demo/go/main.go @@ -0,0 +1,29 @@ +package main + +// Import "fmt" from the Go Standard library to write to standard out +// Import "io/ioutil" from the Go Standard library to write to the filesystem +import ( + "fmt" + "io/ioutil" +) + +func main() { + // Print out hello world! + // This will handle writing to stdout for us using the WASI APIs (e.g fd_write) + fmt.Println("Hello world!") + + // Get our hello world string as bytes, so we can write the string using ioutil + helloWorldAsBytes := []byte("Hello world!\n") + + // We are writing a `helloworld.txt` file + // This code requires the Wasi host to provide a directory on the guest. + // For example, in Wasmtime, if you want to access to the current directory, + // invoke the wasmtime with the flag/argument: `--dir .` + err := ioutil.WriteFile("./helloworld.txt", helloWorldAsBytes, 0644) + + // If err is not nil, that means we could not create/write the file + // (Probably because we did not add the `--dir` flag on our wasmtime command) + if err != nil { + panic(err) + } +} diff --git a/examples/wasi-hello-world/demo/go/main.wasm b/examples/wasi-hello-world/demo/go/main.wasm new file mode 100755 index 0000000..b5bf20c Binary files /dev/null and b/examples/wasi-hello-world/demo/go/main.wasm differ diff --git a/examples/wasi-hello-world/demo/go/run.sh b/examples/wasi-hello-world/demo/go/run.sh new file mode 100755 index 0000000..7594251 --- /dev/null +++ b/examples/wasi-hello-world/demo/go/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# Compile the TinyGo Wasm Module that targets WASI +# Note, some features aren't fully supported by WASI. So if you hit nil pointer references +# You may want to play around with the scheduler and gc flags. For example: +# "-scheduler=none -gc=conservative" or "-scheduler=coroutines -gc=leaking" +tinygo build -wasm-abi=generic -target=wasi -o main.wasm main.go + +# Run the Wasm module with wasmtime, +# while passing in the capability to modify the filesytem of the current directory +wasmtime --dir . main.wasm diff --git a/examples/wasi-hello-world/wasi-hello-world.go.en-us.md b/examples/wasi-hello-world/wasi-hello-world.go.en-us.md new file mode 100644 index 0000000..7675ad9 --- /dev/null +++ b/examples/wasi-hello-world/wasi-hello-world.go.en-us.md @@ -0,0 +1,77 @@ +# WASI Hello World + +## Overview + +In this example, We will be writing "Hello world!" to both the console (`stdout`), and a newly created file `helloworld.txt`. We highly reccomended that you have read the [WASI Introduction](/example-redirect?exampleName=wasi-introduction&programmingLanguage=all) before procedding with this example. You should install [wasmtime](https://wasmtime.dev/) as that is the WebAssembly runtime we will be using as our host. + +--- + +## Implementation + +First, we will create a new `main.go` file, with the following code: + +```go +package main + +// Import "fmt" from the Go Standard library to write to standard out +// Import "io/ioutil" from the Go Standard library to write to the filesystem +import ( + "fmt" + "io/ioutil" +) + +func main() { + // Print out hello world! + // This will handle writing to stdout for us using the WASI APIs (e.g fd_write) + fmt.Println("Hello world!") + + // Get our hello world string as bytes, so we can write the string using ioutil + helloWorldAsBytes := []byte("Hello world!\n") + + // We are writing a `helloworld.txt` file + // This code requires the Wasi host to provide a directory on the guest. + // For example, in Wasmtime, if you want to access to the current directory, + // invoke the wasmtime with the flag/argument: `--dir .` + err := ioutil.WriteFile("./helloworld.txt", helloWorldAsBytes, 0644) + + // If err is not nil, that means we could not create/write the file + // (Probably because we did not add the `--dir` flag on our wasmtime command) + if err != nil { + panic(err) + } +} +``` + +As mentioned in the code comments, even though the [WASI APIs](https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/docs.md) are not being used directly, when we compile our program to WASI, TinyGo will be calling the host functions for us through it's standard library functions. + +Next, Let's compile our `main.go` into a Wasm module that targets WASI! + +This can be down with the `-wasm-abi=generic` and `-target=wasi` flags when you run the TinyGo compiler: + +```bash +tinygo build -wasm-abi=generic -target=wasi -o main.wasm main.go +``` + +Which should output (`-o`) a `main.wasm` file that we can run in a WebAssembly runtime that supports WASI! + +> **NOTE:** As of July, 2021 goroutines and other language features may be in a funny place in terms of WASI support. Thus, if this is something you are trying to support it is worth playing around with the `-scheduler` and `-gc` compiler flags. For example, it may be worth adding the flags `"-scheduler=none -gc=conservative"` or `"-scheduler=coroutines -gc=leaking"` flag combination to a simple TinyGo compilation. (E.g `tinygo build -wasm-abi=generic -target=wasi -scheduler=coroutines -gc=leaking -o main.wasm main.go`). + +Now that we have our Wasm Module that targets WASI, we can run the module using the Wasmtime CLI. We mentioned wasmtime should be installed at the beginning of this tutorial. However, there is one thing to note that was mentioned in the code comments. **We need to give our program explicit access to create files on our host, because our program creates a new file**. As mentioned in the [WASI Introduction](/example-redirect?exampleName=wasi-introduction), our guest will not have this capability unless we give them the capability. + +Thus, when we use the Wasmtime CLI to run our wasm module, we should pass the `--dir .` flag. This grants wasmtime the capability to read/write files in the current directory (`.`). + +Finally, let's run our Wasm module with the Wasmtime CLI: + +```bash +wasmtime --dir . main.wasm +``` + +You should then see "Hello World!" logged in your terminal. You should also notice that a `helloworld.txt` file was created in your current directory, with the contents of "Hello World!". + +Yay! We have successfully written our first WASI module! + +--- + +WASI is still growing, and there are a lot of projects that are taking advantages of WASI to do interesting things! You can see some examples of projects written for, or ported to WebAssembly using WASI, by searching "WASI" on [Made with WebAssembly](https://madewithwebassembly.com/). + +Feel free to [fix, suggest, or contribute more examples](https://github.com/torch2424/wasm-by-example)!