Docs · Toolchain
Targets
Vyi compiles the same program to three targets: WebAssembly (the default),
native linux/x86-64, and native linux/AArch64. A program's behavior is
identical on every target — same values, same diagnostics, same panic traces —
so the target choice is about where the artifact runs, not what it means.
Select with --target on any CLI command (the CLI reference has the
full flag list; flags come before the entry path).
WebAssembly (wasm, default)
vyi build produces a standard .wasm module; vyi run executes it in the
CLI's embedded runtime. The module speaks WASI, so it also runs under any
WASI-aware host (wasmtime, wazero, a browser shim): main is exported through
the conventional _start, standard streams and args() come from the host,
and the process exit code is main's result.
C interop on wasm compiles your c_included C sources alongside the program —
see guide 15 for the shape of that boundary.
Native linux/x86-64 (x86-64-linux)
vyi build --target x86-64-linux -o app main.vyi links a self-contained ELF
executable: main becomes the process entry, Ok(code) becomes the exit
status, an error from main prints error: <message> and exits 1, and a
panic prints its trace and exits 101 — exactly as on wasm. Native binaries
call the system's libc for I/O and allocation.
Native linux/AArch64 (arm64-linux)
vyi build --target arm64-linux -o app main.vyi links a self-contained
linux/AArch64 ELF executable under the same process contract as x86-64-linux:
main is the entry, Ok(code) is the exit status, an error from main prints
error: <message> and exits 1, and a panic prints its trace and exits
101. Linking uses the system C compiler the same way native x86-64 does.
Writing target-conditional code
The @target package exposes the active target as known string values, so a
file-scope if selects declarations at compile time — the unused branch never
enters the program:
import { targetOS } from "@target"
if targetOS == "wasm" {
con banner = "running on wasm\n"
} else {
con banner = "running native\n"
}
fn main() !u8 {
con b = banner
return Ok(0)
}targetOS is "wasm" or "linux"; targetArch is "wasm32", "x86_64", or
"aarch64". Because these are known values, they also drive ordinary if
statements inside function bodies, which fold at compile time (known values).
What varies, what doesn't
| wasm | x86-64-linux | arm64-linux | |
|---|---|---|---|
| Pointer/word width | 32-bit | 64-bit | 64-bit |
sizeof results for pointer-shaped types | smaller | larger | larger |
Integer widths i8–i64, u8–u64 | identical | identical | identical |
| Program behavior, diagnostics, panic traces | identical | identical | identical |
Write against the type system rather than a width: sizeof(T) and
alignof(T) always answer for the active target, and code that needs a
pointer-sized integer should ask for one with sizeof instead of assuming a
number.