github.com/AR1011/wazero@v1.0.5/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 97 - Uses `@ptrToInt` to change a Zig pointer to a numeric type 98 - Uses `[*]u8` as an argument to take a pointer and slices it to build back a 99 string 100 - It also shows how to import a host function using the `extern` directive 101 102 To allow the host to allocate memory, you need to define your own `malloc` and 103 `free` functions: 104 105 ```webassembly 106 (func (export "malloc") (param $size i32) (result (;$ptr;) i32)) 107 (func (export "free") (param $ptr i32) (param $size i32)) 108 ``` 109 110 Because Zig easily allows end-users to [plug their own allocators][12], it relatively easy to 111 export custom `malloc`/`free` pairs to the host. 112 113 For instance, the following code exports `malloc`, `free` from Zig's `page_allocator`: 114 115 ```zig 116 const allocator = std.heap.page_allocator; 117 118 pub export fn malloc(length: usize) ?[*]u8 { 119 const buff = allocator.alloc(u8, length) catch return null; 120 return buff.ptr; 121 } 122 123 pub export fn free(buf: [*]u8, length: usize) void { 124 allocator.free(buf[0..length]); 125 } 126 ``` 127 128 ## System Calls 129 130 Please read our overview of WebAssembly and 131 [System Calls]({{< ref "_index.md#system-calls" >}}). In short, WebAssembly is 132 a stack-based virtual machine specification, so operates at a lower level than 133 an operating system. 134 135 For functionality the operating system would otherwise provide, you must use 136 the `wasm32-wasi` target. This imports host functions in 137 [WASI]({{< ref "/specs#wasi" >}}). 138 139 Zig's standard library support for WASI is under active development. 140 In general, you should favor use of the standard library when compiling against 141 wasm32-wasi target (e.g. `std.io`). 142 143 Note: wazero includes an [example WASI project][10] including [source code][11] 144 that implements `cat` without any WebAssembly-specific code. 145 146 ## Concurrency 147 148 Please read our overview of WebAssembly and 149 [concurrency]({{< ref "_index.md#concurrency" >}}). In short, the current 150 WebAssembly specification does not support parallel processing. 151 152 ## Optimizations 153 154 Below are some commonly used configurations that allow optimizing for size or 155 performance vs defaults. Note that sometimes one sacrifices the other. 156 157 ### Binary size 158 159 Those with `%.wasm` binary size constraints can change their source, 160 e.g. picking a [different allocator][9b] or set `zig` flags to reduce it. 161 162 [`zig` flags][13]: 163 Zig provides several flags to control binary size, speed of execution, 164 safety checks. For instance you may use 165 166 - `-ODebug`: Fast build, enabled safety checks, slower runtime performance, 167 larger binary size 168 - `-OReleaseSafe`: Medium runtime performance, enabled safety checks, 169 slower compilation speed, larger binary size 170 - `-OReleaseSmall`: Medium runtime performance, disabled safety checks, 171 slower compilation speed, smaller binary size 172 173 ### Performance 174 175 Those with runtime performance constraints can change their source or set 176 `zig` flags to improve it. 177 178 [`zig` flags][13]: 179 180 - `-OReleaseFast`: Enable additional optimizations, possibly at the cost of 181 increased binary size. 182 183 ## Frequently Asked Questions 184 185 ### Why is my `%.wasm` binary so big? 186 187 Zig defaults can be overridden for those who can sacrifice features or 188 performance for a [smaller binary](#binary-size). After that, tuning your 189 source code may reduce binary size further. 190 191 [1]: https://ziglang.org/download/0.4.0/release-notes.html 192 [2]: https://ziglang.org/documentation/0.10.1/#WASI 193 [4]: https://ziglang.org/documentation/0.10.1/#WebAssembly 194 [5]: https://discord.gg/gxsFFjE 195 [6]: https://github.com/AR1011/wazero/tree/main/site/content/languages/zig.md 196 [7]: https://github.com/AR1011/wazero/stargazers 197 [9]: https://github.com/AR1011/wazero/tree/main/examples/allocation/zig 198 [9b]: https://ziglang.org/documentation/0.10.1/#Memory 199 [10]: https://github.com/AR1011/wazero/tree/main/imports/wasi_snapshot_preview1/example/testdata/zig 200 [11]: https://github.com/AR1011/wazero/blob/main/imports/wasi_snapshot_preview1/example/testdata/zig/cat.zig 201 [13]: https://ziglang.org/documentation/0.10.1/#Build-Mode