From c324c671d09c98dcaf3be96f18aeb2b06051acde Mon Sep 17 00:00:00 2001 From: Edoardo Vacchi Date: Mon, 23 Jan 2023 11:54:05 +0100 Subject: [PATCH] docs: add zig section (#1051) Signed-off-by: Edoardo Vacchi --- examples/allocation/zig/README.md | 5 - .../wasi_snapshot_preview1/example/README.md | 1 + site/content/languages/_index.md | 1 + site/content/languages/zig.md | 196 ++++++++++++++++++ 4 files changed, 198 insertions(+), 5 deletions(-) create mode 100644 site/content/languages/zig.md diff --git a/examples/allocation/zig/README.md b/examples/allocation/zig/README.md index 3ff400d6..3e652154 100644 --- a/examples/allocation/zig/README.md +++ b/examples/allocation/zig/README.md @@ -22,8 +22,3 @@ This example uses `@panic()` rather than `unreachable` to handle errors since `unreachable` emits a call to panic only in `Debug` and `ReleaseSafe` mode. In `ReleaseFast` and `ReleaseSmall` mode, it would lead into undefined behavior. - -If building wasm with a pre-release version of Zig 0.10.0, use `-fstage1` to -avoid [bugs in the new compiler][1]. - -[1]: https://github.com/ziglang/zig/wiki/Self-Hosted-Compiler-Upgrade-Guide#is-it-time-to-upgrade diff --git a/imports/wasi_snapshot_preview1/example/README.md b/imports/wasi_snapshot_preview1/example/README.md index 221e9bb9..ad8ca82f 100644 --- a/imports/wasi_snapshot_preview1/example/README.md +++ b/imports/wasi_snapshot_preview1/example/README.md @@ -13,6 +13,7 @@ to use Wasm built with "tinygo". Here are the included examples: * [cargo-wasi](testdata/cargo-wasi) - Built via `cargo wasi build --release; mv ./target/wasm32-wasi/release/cat.wasm .` * [tinygo](testdata/tinygo) - Built via `tinygo build -o cat.wasm -scheduler=none --no-debug -target=wasi cat.go` +* [zig](testdata/zig) - Built via `zig build-exe cat.zig -target=wasm32-wasi -OReleaseSmall` * [zig-cc](testdata/zig-cc) - Built via `zig cc cat.c -o cat.wasm --target=wasm32-wasi -O3` To run the same example with zig-cc: diff --git a/site/content/languages/_index.md b/site/content/languages/_index.md index 6cc18846..fb783c9b 100644 --- a/site/content/languages/_index.md +++ b/site/content/languages/_index.md @@ -20,6 +20,7 @@ Below are notes wazero contributed so far, in alphabetical order by language. * [Go](go) e.g. `GOARCH=wasm GOOS=js go build -o X.wasm X.go` * [TinyGo](tinygo) e.g. `tinygo build -o X.wasm -target=wasi X.go` * [Rust](rust) e.g. `rustc -o X.wasm --target wasm32-wasi X.rs` +* [Zig](zig) e.g. `zig build-exe X.zig -target wasm32-wasi` wazero is a runtime that embeds in Go applications, not a web browser. As such, these notes bias towards backend use of WebAssembly, not browser use. diff --git a/site/content/languages/zig.md b/site/content/languages/zig.md new file mode 100644 index 00000000..2cc60eb7 --- /dev/null +++ b/site/content/languages/zig.md @@ -0,0 +1,196 @@ ++++ +title = "Zig" ++++ + +## Introduction + +Beginning with 0.4.0 [Zig][1] can generate `%.wasm` files instead of +architecture-specific binaries through three targets: + +* `wasm32-emscripten`: mostly for browser (JavaScript) use. +* `wasm32-freestanding`: for standalone use in or outside the browser. +* `wasm32-wasi`: for use outside the browser. + +This document is maintained by wazero, which is a WebAssembly runtime that +embeds in Go applications. Hence, our notes focus on targets used outside the +browser, tested by wazero: `wasm32-freestanding` and `wasm32-wasi`. + +## Overview + +When Zig compiles a `%.zig` file with a `wasm32-*` target, the output `%.wasm` +depends on a subset of features in the [WebAssembly 2.0 +Core specification]({{< ref "/specs#core" >}}) and [WASI]({{< ref "/specs#wasi" >}}) host +functions. + +Unlike some compilers, Zig also supports importing custom host functions and +exporting functions back to the host. + +Here's a basic example of source in Zig: + +```zig +export fn add(a: i32, b: i32) i32 { + return a + b; +} +``` + +The following is the minimal command to build a Wasm file. + +```bash +zig build-lib -dynamic -target wasm32-freestanding main.zig +``` + +The resulting Wasm `export`s the `add` function so that the embedding host can +call it, regardless of if the host is written in Zig or not. + +Notice we are using `zig build-lib -dynamic`: this +compiles the source as a library, i.e. without a `main` function. + +## Disclaimer + +This document includes notes contributed by the wazero community for Zig 0.10.1. +While wazero includes Zig examples, and maintainers contribute to Zig, this +isn't a Zig official document. For more help, consider the [WebAssembly Documentation][4] +or joining the [#programming-discussion channel on +Zig's Discord][5]. + +Meanwhile, please help us [maintain][6] this document and [star our GitHub +repository][7], if it is helpful. Together, we can make WebAssembly easier on +the next person. + +## Constraints + +Please read our overview of WebAssembly and +[constraints]({{< ref "_index.md#constraints" >}}). In short, expect +limitations in both language features and library choices when developing your +software. + +## Memory + +The Zig language performs no memory management on behalf of the programmer. +However, Zig has no default allocator. Instead, functions which need to allocate +accept an `Allocator` parameter. + +### Host Allocations + +Sometimes a host function needs to allocate memory directly. For example, to write JSON +of a given length before invoking an exported function to parse it. + +```zig +pub export fn configure(ptr: [*]const u8, size: u32) void { + _configure(message[0..size]) catch |err| @panic(switch (err) { + error.OutOfMemory => "out of memory", + }); +} +``` + +The general flow is that the host allocates memory by calling an allocation +function with the size needed. Then, it writes data, in this case JSON, to the +memory offset (`ptr`). At that point, it can call a host function, ex +`configure`, passing the `ptr` and `size` allocated. The guest Wasm (compiled +from Zig) will be able to read the data. To ensure no memory leaks, the host +calls a free function, with the same `ptr`, afterwards and unconditionally. + +Note: wazero includes an [example project][9] that shows this. + +The [zig example][9] does a few things of interest: +* Uses `@ptrToInt` to change a Zig pointer to a numeric type +* Uses `[*]u8` as an argument to take a pointer and slices it to build back a +string +* It also shows how to import a host function using the `extern` directive + +To allow the host to allocate memory, you need to define your own `malloc` and +`free` functions: +```webassembly +(func (export "malloc") (param $size i32) (result (;$ptr;) i32)) +(func (export "free") (param $ptr i32) (param $size i32)) +``` + +Because Zig easily allows end-users to [plug their own allocators][12], it relatively easy to +export custom `malloc`/`free` pairs to the host. + +For instance, the following code exports `malloc`, `free` from Zig's `page_allocator`: + +```zig +const allocator = std.heap.page_allocator; + +pub export fn malloc(length: usize) ?[*]u8 { + const buff = allocator.alloc(u8, length) catch return null; + return buff.ptr; +} + +pub export fn free(buf: [*]u8, length: usize) void { + allocator.free(buf[0..length]); +} +``` + +## System Calls + +Please read our overview of WebAssembly and +[System Calls]({{< ref "_index.md#system-calls" >}}). In short, WebAssembly is +a stack-based virtual machine specification, so operates at a lower level than +an operating system. + +For functionality the operating system would otherwise provide, you must use +the `wasm32-wasi` target. This imports host functions in +[WASI]({{< ref "/specs#wasi" >}}). + +Zig's standard library support for WASI is under active development. +In general, you should favor use of the standard library when compiling against +wasm32-wasi target (e.g. `std.io`). + +Note: wazero includes an [example WASI project][10] including [source code][11] +that implements `cat` without any WebAssembly-specific code. + +## Concurrency + +Please read our overview of WebAssembly and +[concurrency]({{< ref "_index.md#concurrency" >}}). In short, the current +WebAssembly specification does not support parallel processing. + +## Optimizations + +Below are some commonly used configurations that allow optimizing for size or +performance vs defaults. Note that sometimes one sacrifices the other. + +### Binary size + +Those with `%.wasm` binary size constraints can change their source, +e.g. picking a [different allocator][9b] or set `zig` flags to reduce it. + +[`zig` flags][13]: +Zig provides several flags to control binary size, speed of execution, +safety checks. For instance you may use +* `-ODebug`: Fast build, enabled safety checks, slower runtime performance, + larger binary size +* `-OReleaseSafe`: Medium runtime performance, enabled safety checks, + slower compilation speed, larger binary size +* `-OReleaseSmall`: Medium runtime performance, disabled safety checks, + slower compilation speed, smaller binary size + +### Performance + +Those with runtime performance constraints can change their source or set +`zig` flags to improve it. + +[`zig` flags][13]: +* `-OReleaseFast`: Enable additional optimizations, possibly at the cost of + increased binary size. + +## Frequently Asked Questions + +### Why is my `%.wasm` binary so big? +Zig defaults can be overridden for those who can sacrifice features or +performance for a [smaller binary](#binary-size). After that, tuning your +source code may reduce binary size further. + +[1]: https://ziglang.org/download/0.4.0/release-notes.html +[2]: https://ziglang.org/documentation/0.10.1/#WASI +[4]: https://ziglang.org/documentation/0.10.1/#WebAssembly +[5]: https://discord.gg/gxsFFjE +[6]: https://github.com/tetratelabs/wazero/tree/main/site/content/languages/zig.md +[7]: https://github.com/tetratelabs/wazero/stargazers +[9]: https://github.com/tetratelabs/wazero/tree/main/examples/allocation/zig +[9b]: https://ziglang.org/documentation/0.10.1/#Memory +[10]: https://github.com/tetratelabs/wazero/tree/main/imports/wasi_snapshot_preview1/example/testdata/zig +[11]: https://github.com/tetratelabs/wazero/blob/main/imports/wasi_snapshot_preview1/example/testdata/zig/cat.zig +[13]: https://ziglang.org/documentation/0.10.1/#Build-Mode