Skip to main content
Zig’s target system provides fine-grained control over the platform, architecture, ABI, and other target-specific settings for your build.

Target Overview

A target in Zig consists of:
  • CPU Architecture - x86_64, aarch64, riscv64, etc.
  • Operating System - linux, windows, macos, freestanding, etc.
  • ABI - gnu, musl, msvc, etc.
  • Object Format - elf, coff, macho, wasm, etc.
lib/std/Target.zig:1-10
//! All the details about the machine that will be executing code.
//! Unlike `Query` which might leave some things as "default" or "host", this
//! data is fully resolved into a concrete set of OS versions, CPU features,
//! etc.

cpu: Cpu,
os: Os,
abi: Abi,
ofmt: ObjectFormat,
dynamic_linker: DynamicLinker = DynamicLinker.none,

Specifying Targets

Standard Target Options

The most common way to configure targets:
const target = b.standardTargetOptions(.{});
This allows users to specify targets via command line:
zig build -Dtarget=x86_64-linux-gnu
zig build -Dtarget=aarch64-macos
zig build -Dtarget=wasm32-wasi
zig build -Dtarget=riscv64-linux-musl

Default Target

Set a default target when none is specified:
lib/std/Build.zig:18-22
const target = b.standardTargetOptions(.{
    .default_target = .{
        .ofmt = if (only_c) .c else null,
    },
});

Explicit Target

Resolve a specific target directly:
const target = b.resolveTargetQuery(std.Target.Query.parse(.{
    .arch_os_abi = "wasm32-wasi",
    .cpu_features = "baseline-extended_const+nontrapping_bulk_memory_len0",
}) catch unreachable);

Target Components

CPU Architecture

Supported architectures include:
// Common architectures
.x86_64      // 64-bit x86
.x86         // 32-bit x86
.aarch64     // 64-bit ARM
.arm         // 32-bit ARM
.riscv64     // 64-bit RISC-V
.riscv32     // 32-bit RISC-V
.wasm32      // WebAssembly 32-bit
.wasm64      // WebAssembly 64-bit

// Additional architectures
.powerpc64
.powerpc
.mips64
.mips
.sparc64
.s390x
.hexagon
.avr
.msp430
.bpf
.nvptx64
.spirv64

Operating Systems

lib/std/Target.zig:18-68
pub const Tag = enum {
    freestanding,
    other,

    contiki,
    fuchsia,
    hermit,
    managarm,

    haiku,
    hurd,
    illumos,
    linux,
    plan9,
    rtems,
    serenity,

    dragonfly,
    freebsd,
    netbsd,
    openbsd,

    driverkit,
    ios,
    maccatalyst,
    macos,
    tvos,
    visionos,
    watchos,

    windows,
    uefi,

    @"3ds",

    ps3,
    ps4,
    ps5,
    vita,

    emscripten,
    wasi,

    amdhsa,
    amdpal,
    cuda,
    mesa3d,
    nvcl,
    opencl,
    opengl,
    vulkan,

Darwin OS Detection

lib/std/Target.zig:78-90
pub inline fn isDarwin(tag: Tag) bool {
    return switch (tag) {
        .driverkit,
        .ios,
        .maccatalyst,
        .macos,
        .tvos,
        .visionos,
        .watchos,
        => true,
        else => false,
    };
}

ABI (Application Binary Interface)

lib/std/Target.zig:739-766
pub const Abi = enum {
    none,
    gnu,
    gnuabin32,
    gnuabi64,
    gnueabi,
    gnueabihf,
    gnuf32,
    gnusf,
    gnux32,
    eabi,
    eabihf,
    ilp32,
    android,
    androideabi,
    musl,
    muslabin32,
    muslabi64,
    musleabi,
    musleabihf,
    muslf32,
    muslsf,
    muslx32,
    msvc,
    itanium,
    simulator,
    ohos,
    ohoseabi,

Object Formats

  • elf - Executable and Linkable Format (Linux, BSDs)
  • coff - Common Object File Format (Windows)
  • macho - Mach-O (macOS, iOS)
  • wasm - WebAssembly
  • c - C source code output
  • hex - Intel HEX format
  • raw - Raw binary
  • spirv - SPIR-V (GPU shaders)
  • plan9 - Plan 9 object format

OS Version Ranges

Version Range System

lib/std/Target.zig:372-377
pub const VersionRange = union {
    none: void,
    semver: std.SemanticVersion.Range,
    hurd: HurdVersionRange,
    linux: LinuxVersionRange,
    windows: WindowsVersion.Range,

Windows Versions

lib/std/Target.zig:220-250
pub const WindowsVersion = enum(u32) {
    nt4 = 0x04000000,
    win2k = 0x05000000,
    xp = 0x05010000,
    ws2003 = 0x05020000,
    vista = 0x06000000,
    win7 = 0x06010000,
    win8 = 0x06020000,
    win8_1 = 0x06030000,
    win10 = 0x0A000000,
    win10_th2 = 0x0A000001,
    win10_rs1 = 0x0A000002,
    win10_rs2 = 0x0A000003,
    win10_rs3 = 0x0A000004,
    win10_rs4 = 0x0A000005,
    win10_rs5 = 0x0A000006,
    win10_19h1 = 0x0A000007,
    win10_vb = 0x0A000008,
    win10_mn = 0x0A000009,
    win10_fe = 0x0A00000A,
    win10_co = 0x0A00000B,
    win10_ni = 0x0A00000C,
    win10_cu = 0x0A00000D,
    win11_zn = 0x0A00000E,
    win11_ga = 0x0A00000F,
    win11_ge = 0x0A000010,
    win11_dt = 0x0A000011,
    _,

    /// Latest Windows version
    pub const latest = WindowsVersion.win11_dt;

Linux Versions

lib/std/Target.zig:331-346
pub const LinuxVersionRange = struct {
    range: std.SemanticVersion.Range,
    glibc: std.SemanticVersion,
    /// Android API level.
    android: u32,

    pub inline fn includesVersion(range: LinuxVersionRange, ver: std.SemanticVersion) bool {
        return range.range.includesVersion(ver);
    }

    /// Checks if system is guaranteed to be at least `version` or older than `version`.
    /// Returns `null` if a runtime check is required.
    pub inline fn isAtLeast(range: LinuxVersionRange, ver: std.SemanticVersion) ?bool {
        return range.range.isAtLeast(ver);
    }
};

Default Version Ranges

lib/std/Target.zig:430-446
.linux => .{
    .linux = .{
        .range = .{
            .min = .{ .major = 5, .minor = 10, .patch = 0 },
            .max = .{ .major = 6, .minor = 17, .patch = 0 },
        },
        .glibc = .{ .major = 2, .minor = 31, .patch = 0 },
        .android = 29,
    },
},

CPU Features

Configure specific CPU features:
lib/std/Build.zig:628-634
const target = b.resolveTargetQuery(std.Target.Query.parse(.{
    .arch_os_abi = "wasm32-wasi",
    .cpu_features = "baseline-extended_const+nontrapping_bulk_memory_len0",
}) catch unreachable);
Feature syntax:
  • baseline - Default features for the architecture
  • +feature - Enable a feature
  • -feature - Disable a feature

Target-Specific Configuration

Querying Target Properties

if (target.result.os.tag == .windows) {
    // Windows-specific configuration
    exe.root_module.linkSystemLibrary("ws2_32", .{});
    exe.root_module.linkSystemLibrary("version", .{});
}

if (target.result.os.tag.isDarwin()) {
    // macOS/iOS-specific configuration
    exe.headerpad_max_install_names = true;
}

if (target.result.cpu.arch == .wasm32) {
    // WebAssembly-specific configuration
}

File Extensions

lib/std/Target.zig:99-109
pub fn exeFileExt(tag: Tag, arch: Cpu.Arch) [:0]const u8 {
    return switch (tag) {
        .windows => ".exe",
        .uefi => ".efi",
        .plan9 => arch.plan9Ext(),
        else => switch (arch) {
            .wasm32, .wasm64 => ".wasm",
            else => "",
        },
    };
}

Library Extensions

lib/std/Target.zig:111-134
pub fn staticLibSuffix(tag: Tag, abi: Abi) [:0]const u8 {
    return switch (abi) {
        .msvc, .itanium => ".lib",
        else => switch (tag) {
            .windows, .uefi => ".lib",
            else => ".a",
        },
    };
}

pub fn dynamicLibSuffix(tag: Tag) [:0]const u8 {
    return switch (tag) {
        .windows, .uefi => ".dll",
        .driverkit,
        .ios,
        .maccatalyst,
        .macos,
        .tvos,
        .visionos,
        .watchos,
        => ".dylib",
        else => ".so",
    };
}

Multi-Target Builds

Build for multiple targets in a single build script:
const targets = [_]std.Target.Query{
    .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .gnu },
    .{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu },
    .{ .cpu_arch = .aarch64, .os_tag = .macos },
    .{ .cpu_arch = .wasm32, .os_tag = .wasi },
};

for (targets) |t| {
    const resolved = b.resolveTargetQuery(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 = resolved,
            .optimize = .ReleaseFast,
        }),
    });
    b.installArtifact(exe);
}

Common Target Patterns

Native Builds

// Build for the host machine
const exe = b.addExecutable(.{
    .name = "tool",
    .root_module = b.createModule(.{
        .root_source_file = b.path("tools/tool.zig"),
        .target = b.graph.host,
        .optimize = .Debug,
    }),
});

Freestanding Targets

const kernel = b.addExecutable(.{
    .name = "kernel",
    .root_module = b.createModule(.{
        .root_source_file = b.path("src/kernel.zig"),
        .target = b.resolveTargetQuery(.{
            .cpu_arch = .x86_64,
            .os_tag = .freestanding,
            .abi = .none,
        }),
        .optimize = .ReleaseSmall,
    }),
});

WebAssembly Targets

const wasm = b.addExecutable(.{
    .name = "app",
    .root_module = b.createModule(.{
        .root_source_file = b.path("src/main.zig"),
        .target = b.resolveTargetQuery(.{
            .cpu_arch = .wasm32,
            .os_tag = .wasi,
        }),
        .optimize = .ReleaseSmall,
    }),
});

Target Resolution

The ResolvedTarget type contains the final, resolved target configuration:
lib/std/Build.zig:127
/// Information about the native target. Computed before build() is invoked.
host: ResolvedTarget,
Key properties:
  • result - The fully resolved std.Target
  • query - The original target query

Advanced Target Features

Default ABI Selection

lib/std/Target.zig:795-812
pub fn default(arch: Cpu.Arch, os_tag: Os.Tag) Abi {
    return switch (os_tag) {
        .freestanding, .other => switch (arch) {
            .arm,
            .armeb,
            .csky,
            .hppa,
            .mips,
            .mipsel,
            .powerpc,
            .powerpcle,
            .sh,
            .sheb,
            .thumb,
            .thumbeb,
            => .eabi,
            else => .none,
        },

PIC Requirements

src/target.zig:49-54
pub fn requiresPIC(target: *const std.Target, linking_libc: bool) bool {
    return target.abi.isAndroid() or
        target.os.tag == .windows or target.os.tag == .uefi or
        osRequiresLibC(target) or
        (linking_libc and target.isGnuLibC());
}

See Also

Build docs developers (and LLMs) love