Zig cross-compilation
Contract
| Field | Bound contract |
|---|---|
| Trigger | The user wants a binary for a different OS or CPU from Zig or C sources, asks which Zig triple names a board or platform, needs a CPU feature set, or targets bare metal or WebAssembly. |
| Authority | Read-only. The skill emits commands, build.zig loops, and triple choices to chat; the user runs them. Rollback is not needed. No remote mutation. |
| Side effect | Chat output; scratch cross builds write into a scratch directory. |
| Done | The triple, CPU, and command for the target are reported, the triple appears in zig targets on the installed Zig, and a scratch build for that triple produces a file whose format file reports as the target's. |
Inputs
- Zig version from
zig version: required. Commands ran on Zig 0.14.1. - Target platform: required. OS or bare metal, architecture, ABI, and the exact CPU when known.
- Sources: required. Zig, C, or both.
- Linker script for bare-metal targets: required when the target is freestanding.
- macOS SDK path when targeting macOS: required for anything beyond a plain executable that needs system frameworks.
Procedure
Compose the triple
<arch>-<os>-<abi>from the listszig targetsprints (a ZON document; sections.arch,.os,.abi, and.libcfor the triples with a bundled libc). Common choices:x86_64-linux-gnu,x86_64-linux-musl(static),aarch64-linux-gnu,aarch64-linux-musl,arm-linux-gnueabihf(32-bit ARM with FPU),x86_64-windows-gnu,aarch64-macos-none,x86_64-macos-none,wasm32-freestanding,wasm32-wasi,thumb-freestanding-eabihf(Cortex-M with FPU; the CPU selects the M variant),riscv32-freestanding-none. Done when: the triple appears inzig targets.Build Zig for the target:
zig build-exe src/main.zig -target aarch64-linux-gnu -O ReleaseFast, or through the build system withzig build -Dtarget=aarch64-linux-gnu -Doptimize=ReleaseFast. Windows from Linux or macOS:-target x86_64-windows-gnuproduces a.exe. macOS from Linux:-target aarch64-macos-nonelinks a plain executable; code that needs Apple frameworks needs the macOS SDK. Done when:filereports the target's executable format.Select the CPU with
-mcpu.-mcpu nativedetects the build host and is wrong for a cross build;-mcpu baselineis the portable floor for the architecture; add or remove features with+and-, for example-mcpu x86_64+avx2+bmi2,-mcpu x86_64_v3,-mcpu cortex_a72(Raspberry Pi 4),-mcpu cortex_m4+vfp4,-mcpu neoverse_n1,-mcpu apple_m1. CPU and feature names are listed per architecture under.cpusinzig targets. Done when: the CPU name is present in that list.Cross-compile C with
zig cc, which needs no system cross toolchain:zig cc -target aarch64-linux-gnu -O2 -o myapp-arm64 main.c,zig cc -target x86_64-windows-gnu main.c -o myapp.exe,zig cc -target x86_64-linux-musl -static main.c -o myapp-static. In a Makefile, define oneCCper platform, such asCC_LINUX_ARM64 = zig cc -target aarch64-linux-gnu. Done when: the C artifact matches the target format.Build every target from one
build.zig: loop overstd.Target.Queryvalues, resolve each withb.resolveTargetQuery(t), and give each executable a distinct name:const targets = [_]std.Target.Query{ .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .gnu }, .{ .cpu_arch = .aarch64, .os_tag = .linux, .abi = .gnu }, .{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu }, .{ .cpu_arch = .aarch64, .os_tag = .macos }, }; for (targets) |t| { const exe = b.addExecutable(.{ .name = b.fmt("myapp-{s}-{s}", .{ @tagName(t.cpu_arch.?), @tagName(t.os_tag.?) }), .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = b.resolveTargetQuery(t), .optimize = .ReleaseFast, }), }); b.installArtifact(exe); }Done when:
zig-out/binholds one artifact per target.Target bare metal:
zig build-exe src/main.zig -target thumb-freestanding-eabihf -mcpu cortex_m4+vfp4 -O ReleaseSmall -T linker.ld. The root file suppliespub fn panic(msg: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturnand an exported entry point named in the linker script, such asexport fn _start() void. Freestanding code cannot use std facilities that need an OS (threads, files,std.debug.print); the compiler reportsUnsupported operating system freestandingwhen it does. Done when: the ELF links with the script's entry symbol.Target WebAssembly. Browser:
zig build-exe src/main.zig -target wasm32-freestanding -O ReleaseSmall --export=init --export=update -fno-entry, where each exported function isexport fn. WASI:zig build-exe src/main.zig -target wasm32-wasi -O ReleaseSafeproducesmain.wasmfor a WASI runtime. Done when:filereports a WebAssembly module.Confirm with a scratch build and
fileon the output. Done when: the reported format is the target's.
Failure and recovery
| Failure class | Behavior |
|---|---|
available architectures: listing after -target |
The arch name is not one Zig uses; thumbv7em is not an arch, thumb plus -mcpu cortex_m4 is. |
Feature warnings such as is not a recognized feature |
Distribution Zig builds against a different LLVM; the build still completes. Report it as noise, not failure. |
Unsupported operating system freestanding |
An std call needs an OS; remove it from the freestanding path. |
| macOS build needs frameworks | Provide the SDK via --sysroot and framework paths; a plain executable needs nothing. |
| System cross toolchain required by the build | GCC triplets, sysroots, and QEMU: use cross-gcc. Rust's equivalent: use rust-cross. |
Output
A chat report with the triple and CPU, the build command or build.zig loop, the bare-metal or WebAssembly specifics when they apply, and the file line from the scratch build proving the target format. The triple and CPU lists are in references/zig-target-triples.md.