github.com/bananabytelabs/wazero@v0.0.0-20240105073314-54b22a776da8/site/content/languages/zig.md (about) 1 +++ 2 title = "Zig" 3 +++ 4 5 ## Introduction 6 7 Beginning with 0.4.0 [Zig][1] can generate `%.wasm` files instead of 8 architecture-specific binaries through three targets: 9 10 * `wasm32-emscripten`: mostly for browser (JavaScript) use. 11 * `wasm32-freestanding`: for standalone use in or outside the browser. 12 * `wasm32-wasi`: for use outside the browser. 13 14 This document is maintained by wazero, which is a WebAssembly runtime that 15 embeds in Go applications. Hence, our notes focus on targets used outside the 16 browser, tested by wazero: `wasm32-freestanding` and `wasm32-wasi`. 17 18 ## Overview 19 20 When Zig compiles a `%.zig` file with a `wasm32-*` target, the output `%.wasm` 21 depends on a subset of features in the [WebAssembly 2.0 22 Core specification]({{< ref "/specs#core" >}}) and [WASI]({{< ref "/specs#wasi" >}}) host 23 functions. 24 25 Unlike some compilers, Zig also supports importing custom host functions and 26 exporting functions back to the host. 27 28 Here's a basic example of source in Zig: 29 30 ```zig 31 export fn add(a: i32, b: i32) i32 { 32 return a + b; 33 } 34 ``` 35 36 The following is the minimal command to build a Wasm file. 37 38 ```bash 39 zig build-lib -dynamic -target wasm32-freestanding main.zig 40 ``` 41 42 The resulting Wasm `export`s the `add` function so that the embedding host can 43 call it, regardless of if the host is written in Zig or not. 44 45 Notice we are using `zig build-lib -dynamic`: this 46 compiles the source as a library, i.e. without a `main` function. 47 48 ## Disclaimer 49 50 This document includes notes contributed by the wazero community for Zig 0.10.1. 51 While wazero includes Zig examples, and maintainers contribute to Zig, this 52 isn't a Zig official document. For more help, consider the [WebAssembly Documentation][4] 53 or joining the [#programming-discussion channel on 54 Zig's Discord][5]. 55 56 Meanwhile, please help us [maintain][6] this document and [star our GitHub 57 repository][7], if it is helpful. Together, we can make WebAssembly easier on 58 the next person. 59 60 ## Constraints 61 62 Please read our overview of WebAssembly and 63 [constraints]({{< ref "_index.md#constraints" >}}). In short, expect 64 limitations in both language features and library choices when developing your 65 software. 66 67 ## Memory 68 69 The Zig language performs no memory management on behalf of the programmer. 70 However, Zig has no default allocator. Instead, functions which need to allocate 71 accept an `Allocator` parameter. 72 73 ### Host Allocations 74 75 Sometimes a host function needs to allocate memory directly. For example, to write JSON 76 of a given length before invoking an exported function to parse it. 77 78 ```zig 79 pub export fn configure(ptr: [*]const u8, size: u32) void { 80 _configure(message[0..size]) catch |err| @panic(switch (err) { 81 error.OutOfMemory => "out of memory", 82 }); 83 } 84 ``` 85 86 The general flow is that the host allocates memory by calling an allocation 87 function with the size needed. Then, it writes data, in this case JSON, to the 88 memory offset (`ptr`). At that point, it can call a host function, ex 89 `configure`, passing the `ptr` and `size` allocated. The guest Wasm (compiled 90 from Zig) will be able to read the data. To ensure no memory leaks, the host 91 calls a free function, with the same `ptr`, afterwards and unconditionally. 92 93 Note: wazero includes an [example project][9] that shows this. 94 95 The [zig example][9] does a few things of interest: 96 * Uses `@ptrToInt` to change a Zig pointer to a numeric type 97 * Uses `[*]u8` as an argument to take a pointer and slices it to build back a 98 string 99 * It also shows how to import a host function using the `extern` directive 100 101 To allow the host to allocate memory, you need to define your own `malloc` and 102 `free` functions: 103 ```webassembly 104 (func (export "malloc") (param $size i32) (result (;$ptr;) i32)) 105 (func (export "free") (param $ptr i32) (param $size i32)) 106 ``` 107 108 Because Zig easily allows end-users to [plug their own allocators][12], it relatively easy to 109 export custom `malloc`/`free` pairs to the host. 110 111 For instance, the following code exports `malloc`, `free` from Zig's `page_allocator`: 112 113 ```zig 114 const allocator = std.heap.page_allocator; 115 116 pub export fn malloc(length: usize) ?[*]u8 { 117 const buff = allocator.alloc(u8, length) catch return null; 118 return buff.ptr; 119 } 120 121 pub export fn free(buf: [*]u8, length: usize) void { 122 allocator.free(buf[0..length]); 123 } 124 ``` 125 126 ## System Calls 127 128 Please read our overview of WebAssembly and 129 [System Calls]({{< ref "_index.md#system-calls" >}}). In short, WebAssembly is 130 a stack-based virtual machine specification, so operates at a lower level than 131 an operating system. 132 133 For functionality the operating system would otherwise provide, you must use 134 the `wasm32-wasi` target. This imports host functions in 135 [WASI]({{< ref "/specs#wasi" >}}). 136 137 Zig's standard library support for WASI is under active development. 138 In general, you should favor use of the standard library when compiling against 139 wasm32-wasi target (e.g. `std.io`). 140 141 Note: wazero includes an [example WASI project][10] including [source code][11] 142 that implements `cat` without any WebAssembly-specific code. 143 144 ## Concurrency 145 146 Please read our overview of WebAssembly and 147 [concurrency]({{< ref "_index.md#concurrency" >}}). In short, the current 148 WebAssembly specification does not support parallel processing. 149 150 ## Optimizations 151 152 Below are some commonly used configurations that allow optimizing for size or 153 performance vs defaults. Note that sometimes one sacrifices the other. 154 155 ### Binary size 156 157 Those with `%.wasm` binary size constraints can change their source, 158 e.g. picking a [different allocator][9b] or set `zig` flags to reduce it. 159 160 [`zig` flags][13]: 161 Zig provides several flags to control binary size, speed of execution, 162 safety checks. For instance you may use 163 * `-ODebug`: Fast build, enabled safety checks, slower runtime performance, 164 larger binary size 165 * `-OReleaseSafe`: Medium runtime performance, enabled safety checks, 166 slower compilation speed, larger binary size 167 * `-OReleaseSmall`: Medium runtime performance, disabled safety checks, 168 slower compilation speed, smaller binary size 169 170 ### Performance 171 172 Those with runtime performance constraints can change their source or set 173 `zig` flags to improve it. 174 175 [`zig` flags][13]: 176 * `-OReleaseFast`: Enable additional optimizations, possibly at the cost of 177 increased binary size. 178 179 ## Frequently Asked Questions 180 181 ### Why is my `%.wasm` binary so big? 182 Zig defaults can be overridden for those who can sacrifice features or 183 performance for a [smaller binary](#binary-size). After that, tuning your 184 source code may reduce binary size further. 185 186 [1]: https://ziglang.org/download/0.4.0/release-notes.html 187 [2]: https://ziglang.org/documentation/0.10.1/#WASI 188 [4]: https://ziglang.org/documentation/0.10.1/#WebAssembly 189 [5]: https://discord.gg/gxsFFjE 190 [6]: https://github.com/bananabytelabs/wazero/tree/main/site/content/languages/zig.md 191 [7]: https://github.com/bananabytelabs/wazero/stargazers 192 [9]: https://github.com/bananabytelabs/wazero/tree/main/examples/allocation/zig 193 [9b]: https://ziglang.org/documentation/0.10.1/#Memory 194 [10]: https://github.com/bananabytelabs/wazero/tree/main/imports/wasi_snapshot_preview1/example/testdata/zig 195 [11]: https://github.com/bananabytelabs/wazero/blob/main/imports/wasi_snapshot_preview1/example/testdata/zig/cat.zig 196 [13]: https://ziglang.org/documentation/0.10.1/#Build-Mode