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:

vyi
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

wasmx86-64-linuxarm64-linux
Pointer/word width32-bit64-bit64-bit
sizeof results for pointer-shaped typessmallerlargerlarger
Integer widths i8i64, u8u64identicalidenticalidentical
Program behavior, diagnostics, panic tracesidenticalidenticalidentical

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.