⚡ Zig Guide LiveUnofficialbut fully verified
✓ Zig 0.17.0What's newOn an older Zig?Blog

builtin.mode is deprecated: read builtin.optimize

· Written against Zig 0.17.0-dev.2056+79a9897cd

The runnable examples on this page are checked every night and currently run on Zig 0.17.0. The plain code blocks are not checked, and may no longer compile.

On 25 September we changed five files in this guide.

All five read something from @import("builtin").

The code still compiled.

But Zig master had marked the names we used as deprecated.

This guide fails its own build on a deprecated name, so we fix it before the name is removed.

Here is what changed.

The old names

This is the shape you will find in a lot of Zig code:

const builtin = @import("builtin");

const safety_on = switch (builtin.mode) {
    .debug, .safe => true,
    .fast, .small => false,
};

const arch = builtin.cpu.arch;
const os = builtin.os.tag;

Three names here are now deprecated: builtin.mode, builtin.cpu and builtin.os.

The new names

The build mode is builtin.optimize.

The target is one value, builtin.target, and the CPU and OS are fields on it.

const builtin = @import("builtin");

const safety_on = switch (builtin.optimize) {
    .debug, .safe => true,
    .fast, .small => false,
};

const arch = builtin.target.cpu.arch;
const os = builtin.target.os.tag;

The switch did not change.

Only the name in front of it did.

The full list:

OldNew
builtin.modebuiltin.optimize
builtin.cpubuiltin.target.cpu
builtin.osbuiltin.target.os
builtin.abibuiltin.target.abi
builtin.object_formatbuiltin.target.ofmt

Check it on your own compiler

You do not need to trust this post.

The builtin module is generated by the compiler for each build, and Zig will print it for you:

zig build-exe --show-builtin

On Zig 0.17.0-dev.2056 the relevant lines are:

/// Deprecated; to be removed in 0.18.0. Use `target.cpu` instead.
pub const cpu: std.Target.Cpu = .{
/// Deprecated, to be removed after 0.18.0
pub const mode = optimize;
pub const optimize: std.lang.Optimize = .debug;

So mode is now only another name for optimize.

That is why the old code still compiles today.

It will stop compiling when the old names are removed.

If your compiler prints no optimize line, it is older than this change, and builtin.mode is still the name to use.

The new form, running

This is one of the five files we changed.

It runs in your browser, and it is checked every night against Zig master, so it stays correct after this post is old.

const std = @import("std");
const builtin = @import("builtin");

pub fn main(init: std.process.Init) !void {
    var buf: [256]u8 = undefined;
    var fw = std.Io.File.stdout().writerStreaming(init.io, &buf);
    const out = &fw.interface;

    try out.print("cpu arch: {t}\n", .{builtin.target.cpu.arch});
    try out.print("os tag:   {t}\n", .{builtin.target.os.tag});
    try out.print("pointer:  {d} bits\n", .{@bitSizeOf(usize)});

    try out.flush();
}

Why this shows up late

The compiler gives no warning when you use these names.

The comment in --show-builtin is the only notice.

So a project can use builtin.mode for a long time with nothing failing, and then fail all at once on the day it is removed.

This repository checks every snippet and every chapter for deprecated names on each build. How this guide is verified describes the rest of the checks.

The Build Modes chapter now uses builtin.optimize, and shows that -O ReleaseFast and -O fast build the same thing.

← All posts