Commit 73cf7b6429

Andrew Kelley <andrew@ziglang.org>
2023-01-31 05:39:43
update build.zig API usage
1 parent 71ff60f
Changed files (80)
doc
lib
src
link
MachO
test
link
bss
common_symbols
common_symbols_alignment
interdependent_static_c_libs
macho
bugs
13056
13457
dead_strip
dead_strip_dylibs
dylib
empty
entry
headerpad
linksection
needed_framework
needed_library
objc
objcpp
pagezero
search_strategy
stack_size
strict_validation
tls
unwind_info
uuid
weak_framework
weak_library
static_lib_as_system_lib
wasm
archive
basic-features
bss
export
export-data
extern
extern-mangle
function-table
infer-features
producers
segments
stack_pointer
type
src
standalone
brace_expansion
c_compiler
emit_asm_and_bin
empty_env
global_linkage
install_raw_hex
issue_11595
issue_12588
issue_12706
issue_13030
issue_339
issue_5825
issue_7030
issue_794
issue_8550
issue_9812
load_dynamic_library
main_pkg_path
mix_c_files
mix_o_files
options
pie
pkg_import
shared_library
static_c_lib
test_runner_path
use_alias
windows_spawn
doc/langref.html.in
@@ -9531,8 +9531,12 @@ fn foo(comptime T: type, ptr: *T) T {
 const Builder = @import("std").build.Builder;
 
 pub fn build(b: *Builder) void {
-    const exe = b.addExecutable("example", "example.zig");
-    exe.setBuildMode(b.standardReleaseOptions());
+    const optimize = b.standardOptimizeOption(.{});
+    const exe = b.addExecutable(.{
+        .name = "example",
+        .root_source_file = .{ .path = "example.zig" },
+        .optimize = optimize,
+    });
     b.default_step.dependOn(&exe.step);
 }
       {#code_end#}
@@ -10558,11 +10562,14 @@ pub fn build(b: *Builder) void {
 
     // Standard release options allow the person running `zig build` to select
     // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
 
-    const exe = b.addExecutable("example", "src/main.zig");
-    exe.setTarget(target);
-    exe.setBuildMode(mode);
+    const exe = b.addExecutable(.{
+        .name = "example",
+        .root_source_file = .{ .path = "src/main.zig" },
+        .target = target,
+        .optimize = optimize,
+    });
     exe.install();
 
     const run_cmd = exe.run();
@@ -10584,13 +10591,18 @@ pub fn build(b: *Builder) void {
 const Builder = @import("std").build.Builder;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
-    const lib = b.addStaticLibrary("example", "src/main.zig");
-    lib.setBuildMode(mode);
+    const optimize = b.standardOptimizeOption(.{});
+    const lib = b.addStaticLibrary(.{
+        .name = "example",
+        .root_source_file = .{ .path = "src/main.zig" },
+        .optimize = optimize,
+    });
     lib.install();
 
-    var main_tests = b.addTest("src/main.zig");
-    main_tests.setBuildMode(mode);
+    const main_tests = b.addTest(.{
+        .root_source_file = .{ .path = "src/main.zig" },
+        .optimize = optimize,
+    });
 
     const test_step = b.step("test", "Run library tests");
     test_step.dependOn(&main_tests.step);
@@ -10954,7 +10966,9 @@ const Builder = @import("std").build.Builder;
 pub fn build(b: *Builder) void {
     const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));
 
-    const exe = b.addExecutable("test", null);
+    const exe = b.addExecutable(.{
+        .name = "test",
+    });
     exe.addCSourceFile("test.c", &[_][]const u8{"-std=c99"});
     exe.linkLibrary(lib);
     exe.linkSystemLibrary("c");
@@ -11016,7 +11030,9 @@ const Builder = @import("std").build.Builder;
 pub fn build(b: *Builder) void {
     const obj = b.addObject("base64", "base64.zig");
 
-    const exe = b.addExecutable("test", null);
+    const exe = b.addExecutable(.{
+        .name = "test",
+    });
     exe.addCSourceFile("test.c", &[_][]const u8{"-std=c99"});
     exe.addObject(obj);
     exe.linkSystemLibrary("c");
lib/init-exe/build.zig
@@ -1,5 +1,8 @@
 const std = @import("std");
 
+// Although this function looks imperative, note that its job is to
+// declaratively construct a build graph that will be executed by an external
+// runner.
 pub fn build(b: *std.build.Builder) void {
     // Standard target options allows the person running `zig build` to choose
     // what target to build for. Here we do not override the defaults, which
@@ -7,28 +10,58 @@ pub fn build(b: *std.build.Builder) void {
     // for restricting supported target set are available.
     const target = b.standardTargetOptions(.{});
 
-    // Standard release options allow the person running `zig build` to select
-    // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
-    const mode = b.standardReleaseOptions();
+    // Standard optimization options allow the person running `zig build` to select
+    // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
+    // set a preferred release mode, allowing the user to decide how to optimize.
+    const optimize = b.standardOptimizeOption();
 
-    const exe = b.addExecutable("$", "src/main.zig");
-    exe.setTarget(target);
-    exe.setBuildMode(mode);
+    const exe = b.addExecutable(.{
+        .name = "$",
+        // In this case the main source file is merely a path, however, in more
+        // complicated build scripts, this could be a generated file.
+        .root_source_file = .{ .path = "src/main.zig" },
+        .target = target,
+        .optimize = optimize,
+    });
+
+    // This declares intent for the executable to be installed into the
+    // standard location when the user invokes the "install" step (the default
+    // step when running `zig build`).
     exe.install();
 
+    // This *creates* a RunStep in the build graph, to be executed when another
+    // step is evaluated that depends on it. The next line below will establish
+    // such a dependency.
     const run_cmd = exe.run();
+
+    // By making the run step depend on the install step, it will be run from the
+    // installation directory rather than directly from within the cache directory.
+    // This is not necessary, however, if the application depends on other installed
+    // files, this ensures they will be present and in the expected location.
     run_cmd.step.dependOn(b.getInstallStep());
+
+    // This allows the user to pass arguments to the application in the build
+    // command itself, like this: `zig build run -- arg1 arg2 etc`
     if (b.args) |args| {
         run_cmd.addArgs(args);
     }
 
+    // This creates a build step. It will be visible in the `zig build --help` menu,
+    // and can be selected like this: `zig build run`
+    // This will evaluate the `run` step rather than the default, which is "install".
     const run_step = b.step("run", "Run the app");
     run_step.dependOn(&run_cmd.step);
 
-    const exe_tests = b.addTest("src/main.zig");
-    exe_tests.setTarget(target);
-    exe_tests.setBuildMode(mode);
+    // Creates a step for unit testing.
+    const exe_tests = b.addTest(.{
+        .root_source_file = .{ .path = "src/main.zig" },
+        .target = target,
+        .optimize = optimize,
+    });
 
+    // Similar to creating the run step earlier, this exposes a `test` step to
+    // the `zig build --help` menu, providing a way for the user to request
+    // running the unit tests.
     const test_step = b.step("test", "Run unit tests");
     test_step.dependOn(&exe_tests.step);
 }
lib/init-lib/build.zig
@@ -1,17 +1,44 @@
 const std = @import("std");
 
+// Although this function looks imperative, note that its job is to
+// declaratively construct a build graph that will be executed by an external
+// runner.
 pub fn build(b: *std.build.Builder) void {
-    // Standard release options allow the person running `zig build` to select
-    // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
-    const mode = b.standardReleaseOptions();
+    // Standard target options allows the person running `zig build` to choose
+    // what target to build for. Here we do not override the defaults, which
+    // means any target is allowed, and the default is native. Other options
+    // for restricting supported target set are available.
+    const target = b.standardTargetOptions(.{});
 
-    const lib = b.addStaticLibrary("$", "src/main.zig");
-    lib.setBuildMode(mode);
+    // Standard optimization options allow the person running `zig build` to select
+    // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
+    // set a preferred release mode, allowing the user to decide how to optimize.
+    const optimize = b.standardOptimizeOption();
+
+    const lib = b.addStaticLibrary(.{
+        .name = "$",
+        // In this case the main source file is merely a path, however, in more
+        // complicated build scripts, this could be a generated file.
+        .root_source_file = .{ .path = "src/main.zig" },
+        .target = target,
+        .optimize = optimize,
+    });
+
+    // This declares intent for the library to be installed into the standard
+    // location when the user invokes the "install" step (the default step when
+    // running `zig build`).
     lib.install();
 
-    const main_tests = b.addTest("src/main.zig");
-    main_tests.setBuildMode(mode);
+    // Creates a step for unit testing.
+    const main_tests = b.addTest(.{
+        .root_source_file = .{ .path = "src/main.zig" },
+        .target = target,
+        .optimize = optimize,
+    });
 
+    // This creates a build step. It will be visible in the `zig build --help` menu,
+    // and can be selected like this: `zig build test`
+    // This will evaluate the `test` step rather than the default, which is "install".
     const test_step = b.step("test", "Run library tests");
     test_step.dependOn(&main_tests.step);
 }
lib/std/build/TranslateCStep.zig
@@ -19,11 +19,19 @@ include_dirs: std.ArrayList([]const u8),
 c_macros: std.ArrayList([]const u8),
 output_dir: ?[]const u8,
 out_basename: []const u8,
-target: CrossTarget = CrossTarget{},
+target: CrossTarget,
+optimize: std.builtin.OptimizeMode,
 output_file: build.GeneratedFile,
 
-pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep {
+pub const Options = struct {
+    source_file: build.FileSource,
+    target: CrossTarget,
+    optimize: std.builtin.OptimizeMode,
+};
+
+pub fn create(builder: *Builder, options: Options) *TranslateCStep {
     const self = builder.allocator.create(TranslateCStep) catch unreachable;
+    const source = options.source_file.dupe(builder);
     self.* = TranslateCStep{
         .step = Step.init(.translate_c, "translate-c", builder.allocator, make),
         .builder = builder,
@@ -32,19 +40,32 @@ pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep {
         .c_macros = std.ArrayList([]const u8).init(builder.allocator),
         .output_dir = null,
         .out_basename = undefined,
+        .target = options.target,
+        .optimize = options.optimize,
         .output_file = build.GeneratedFile{ .step = &self.step },
     };
     source.addStepDependencies(&self.step);
     return self;
 }
 
-pub fn setTarget(self: *TranslateCStep, target: CrossTarget) void {
-    self.target = target;
-}
+pub const AddExecutableOptions = struct {
+    name: ?[]const u8 = null,
+    version: ?std.builtin.Version = null,
+    target: ?CrossTarget = null,
+    optimize: ?std.builtin.Mode = null,
+    linkage: ?LibExeObjStep.Linkage = null,
+};
 
 /// Creates a step to build an executable from the translated source.
-pub fn addExecutable(self: *TranslateCStep) *LibExeObjStep {
-    return self.builder.addExecutableSource("translated_c", build.FileSource{ .generated = &self.output_file });
+pub fn addExecutable(self: *TranslateCStep, options: AddExecutableOptions) *LibExeObjStep {
+    return self.builder.addExecutable(.{
+        .root_source_file = .{ .generated = &self.output_file },
+        .name = options.name orelse "translated_c",
+        .version = options.version,
+        .target = options.target orelse self.target,
+        .optimize = options.optimize orelse self.optimize,
+        .linkage = options.linkage,
+    });
 }
 
 pub fn addIncludeDir(self: *TranslateCStep, include_dir: []const u8) void {
@@ -82,6 +103,11 @@ fn make(step: *Step) !void {
         try argv_list.append(try self.target.zigTriple(self.builder.allocator));
     }
 
+    switch (self.optimize) {
+        .Debug => {}, // Skip since it's the default.
+        else => try argv_list.append(self.builder.fmt("-O{s}", .{@tagName(self.optimize)})),
+    }
+
     for (self.include_dirs.items) |include_dir| {
         try argv_list.append("-I");
         try argv_list.append(include_dir);
lib/std/build.zig
@@ -420,10 +420,10 @@ pub const Builder = struct {
 
     pub const ExecutableOptions = struct {
         name: []const u8,
-        root_source_file: ?FileSource,
+        root_source_file: ?FileSource = null,
         version: ?std.builtin.Version = null,
-        target: CrossTarget,
-        optimize: std.builtin.Mode,
+        target: CrossTarget = .{},
+        optimize: std.builtin.Mode = .Debug,
         linkage: ?LibExeObjStep.Linkage = null,
     };
 
@@ -436,13 +436,12 @@ pub const Builder = struct {
             .optimize = options.optimize,
             .kind = .exe,
             .linkage = options.linkage,
-            .version = options.version,
         });
     }
 
     pub const ObjectOptions = struct {
         name: []const u8,
-        root_source_file: ?FileSource,
+        root_source_file: ?FileSource = null,
         target: CrossTarget,
         optimize: std.builtin.Mode,
     };
@@ -459,7 +458,7 @@ pub const Builder = struct {
 
     pub const SharedLibraryOptions = struct {
         name: []const u8,
-        root_source_file: ?FileSource,
+        root_source_file: ?FileSource = null,
         version: ?std.builtin.Version = null,
         target: CrossTarget,
         optimize: std.builtin.Mode,
@@ -501,8 +500,8 @@ pub const Builder = struct {
         name: []const u8 = "test",
         kind: LibExeObjStep.Kind = .@"test",
         root_source_file: FileSource,
-        target: CrossTarget,
-        optimize: std.builtin.Mode,
+        target: CrossTarget = .{},
+        optimize: std.builtin.Mode = .Debug,
         version: ?std.builtin.Version = null,
     };
 
@@ -630,8 +629,8 @@ pub const Builder = struct {
         return FmtStep.create(self, paths);
     }
 
-    pub fn addTranslateC(self: *Builder, source: FileSource) *TranslateCStep {
-        return TranslateCStep.create(self, source.dupe(self));
+    pub fn addTranslateC(self: *Builder, options: TranslateCStep.Options) *TranslateCStep {
+        return TranslateCStep.create(self, options);
     }
 
     pub fn make(self: *Builder, step_names: []const []const u8) !void {
lib/std/builtin.zig
@@ -131,13 +131,16 @@ pub const CodeModel = enum {
 
 /// This data structure is used by the Zig language code generation and
 /// therefore must be kept in sync with the compiler implementation.
-pub const Mode = enum {
+pub const OptimizeMode = enum {
     Debug,
     ReleaseSafe,
     ReleaseFast,
     ReleaseSmall,
 };
 
+/// Deprecated; use OptimizeMode.
+pub const Mode = OptimizeMode;
+
 /// This data structure is used by the Zig language code generation and
 /// therefore must be kept in sync with the compiler implementation.
 pub const CallingConvention = enum {
src/link/MachO/zld.zig
@@ -3596,7 +3596,8 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
         man.hash.addOptionalBytes(options.sysroot);
         try man.addOptionalFile(options.entitlements);
 
-        // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
+        // We don't actually care whether it's a cache hit or miss; we just
+        // need the digest and the lock.
         _ = try man.hit();
         digest = man.final();
 
@@ -4177,9 +4178,11 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
             log.debug("failed to save linking hash digest file: {s}", .{@errorName(err)});
         };
         // Again failure here only means an unnecessary cache miss.
-        man.writeManifest() catch |err| {
-            log.debug("failed to write cache manifest when linking: {s}", .{@errorName(err)});
-        };
+        if (man.have_exclusive_lock) {
+            man.writeManifest() catch |err| {
+                log.debug("failed to write cache manifest when linking: {s}", .{@errorName(err)});
+            };
+        }
         // We hang on to this lock so that the output file path can be used without
         // other processes clobbering it.
         macho_file.base.lock = man.toOwnedLock();
test/link/bss/build.zig
@@ -1,12 +1,15 @@
 const Builder = @import("std").build.Builder;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
     const test_step = b.step("test", "Test");
 
-    const exe = b.addExecutable("bss", "main.zig");
+    const exe = b.addExecutable(.{
+        .name = "bss",
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = optimize,
+    });
     b.default_step.dependOn(&exe.step);
-    exe.setBuildMode(mode);
 
     const run = exe.run();
     run.expectStdOutEqual("0, 1, 0\n");
test/link/common_symbols/build.zig
@@ -1,14 +1,19 @@
 const Builder = @import("std").build.Builder;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
 
-    const lib_a = b.addStaticLibrary("a", null);
+    const lib_a = b.addStaticLibrary(.{
+        .name = "a",
+        .optimize = optimize,
+        .target = .{},
+    });
     lib_a.addCSourceFiles(&.{ "c.c", "a.c", "b.c" }, &.{"-fcommon"});
-    lib_a.setBuildMode(mode);
 
-    const test_exe = b.addTest("main.zig");
-    test_exe.setBuildMode(mode);
+    const test_exe = b.addTest(.{
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = optimize,
+    });
     test_exe.linkLibrary(lib_a);
 
     const test_step = b.step("test", "Test it");
test/link/common_symbols_alignment/build.zig
@@ -1,14 +1,21 @@
 const Builder = @import("std").build.Builder;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
+    const target = b.standardTargetOptions(.{});
 
-    const lib_a = b.addStaticLibrary("a", null);
+    const lib_a = b.addStaticLibrary(.{
+        .name = "a",
+        .optimize = optimize,
+        .target = target,
+    });
     lib_a.addCSourceFiles(&.{"a.c"}, &.{"-fcommon"});
-    lib_a.setBuildMode(mode);
 
-    const test_exe = b.addTest("main.zig");
-    test_exe.setBuildMode(mode);
+    const test_exe = b.addTest(.{
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = optimize,
+        .target = target,
+    });
     test_exe.linkLibrary(lib_a);
 
     const test_step = b.step("test", "Test it");
test/link/interdependent_static_c_libs/build.zig
@@ -1,20 +1,30 @@
 const Builder = @import("std").build.Builder;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
+    const target = b.standardTargetOptions(.{});
 
-    const lib_a = b.addStaticLibrary("a", null);
+    const lib_a = b.addStaticLibrary(.{
+        .name = "a",
+        .optimize = optimize,
+        .target = target,
+    });
     lib_a.addCSourceFile("a.c", &[_][]const u8{});
-    lib_a.setBuildMode(mode);
     lib_a.addIncludePath(".");
 
-    const lib_b = b.addStaticLibrary("b", null);
+    const lib_b = b.addStaticLibrary(.{
+        .name = "b",
+        .optimize = optimize,
+        .target = target,
+    });
     lib_b.addCSourceFile("b.c", &[_][]const u8{});
-    lib_b.setBuildMode(mode);
     lib_b.addIncludePath(".");
 
-    const test_exe = b.addTest("main.zig");
-    test_exe.setBuildMode(mode);
+    const test_exe = b.addTest(.{
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = optimize,
+        .target = target,
+    });
     test_exe.linkLibrary(lib_a);
     test_exe.linkLibrary(lib_b);
     test_exe.addIncludePath(".");
test/link/macho/bugs/13056/build.zig
@@ -2,7 +2,7 @@ const std = @import("std");
 const Builder = std.build.Builder;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
 
     const target: std.zig.CrossTarget = .{ .os_tag = .macos };
     const target_info = std.zig.system.NativeTargetInfo.detect(target) catch unreachable;
@@ -11,7 +11,10 @@ pub fn build(b: *Builder) void {
 
     const test_step = b.step("test", "Test the program");
 
-    const exe = b.addExecutable("test", null);
+    const exe = b.addExecutable(.{
+        .name = "test",
+        .optimize = optimize,
+    });
     b.default_step.dependOn(&exe.step);
     exe.addIncludePath(std.fs.path.join(b.allocator, &.{ sdk.path, "/usr/include" }) catch unreachable);
     exe.addIncludePath(std.fs.path.join(b.allocator, &.{ sdk.path, "/usr/include/c++/v1" }) catch unreachable);
@@ -20,7 +23,6 @@ pub fn build(b: *Builder) void {
         "-nostdinc++",
     });
     exe.addObjectFile(std.fs.path.join(b.allocator, &.{ sdk.path, "/usr/lib/libc++.tbd" }) catch unreachable);
-    exe.setBuildMode(mode);
 
     const run_cmd = exe.run();
     run_cmd.expectStdErrEqual("x: 5\n");
test/link/macho/bugs/13457/build.zig
@@ -3,14 +3,17 @@ const Builder = std.build.Builder;
 const LibExeObjectStep = std.build.LibExeObjStep;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
     const target: std.zig.CrossTarget = .{ .os_tag = .macos };
 
     const test_step = b.step("test", "Test the program");
 
-    const exe = b.addExecutable("test", "main.zig");
-    exe.setBuildMode(mode);
-    exe.setTarget(target);
+    const exe = b.addExecutable(.{
+        .name = "test",
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = optimize,
+        .target = target,
+    });
 
     const run = exe.runEmulatable();
     test_step.dependOn(&run.step);
test/link/macho/dead_strip/build.zig
@@ -3,7 +3,7 @@ const Builder = std.build.Builder;
 const LibExeObjectStep = std.build.LibExeObjStep;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
     const target: std.zig.CrossTarget = .{ .os_tag = .macos };
 
     const test_step = b.step("test", "Test the program");
@@ -11,7 +11,7 @@ pub fn build(b: *Builder) void {
 
     {
         // Without -dead_strip, we expect `iAmUnused` symbol present
-        const exe = createScenario(b, mode, target);
+        const exe = createScenario(b, optimize, target);
 
         const check = exe.checkObject(.macho);
         check.checkInSymtab();
@@ -24,7 +24,7 @@ pub fn build(b: *Builder) void {
 
     {
         // With -dead_strip, no `iAmUnused` symbol should be present
-        const exe = createScenario(b, mode, target);
+        const exe = createScenario(b, optimize, target);
         exe.link_gc_sections = true;
 
         const check = exe.checkObject(.macho);
@@ -37,11 +37,13 @@ pub fn build(b: *Builder) void {
     }
 }
 
-fn createScenario(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarget) *LibExeObjectStep {
-    const exe = b.addExecutable("test", null);
+fn createScenario(b: *Builder, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep {
+    const exe = b.addExecutable(.{
+        .name = "test",
+        .optimize = optimize,
+        .target = target,
+    });
     exe.addCSourceFile("main.c", &[0][]const u8{});
-    exe.setBuildMode(mode);
-    exe.setTarget(target);
     exe.linkLibC();
     return exe;
 }
test/link/macho/dead_strip_dylibs/build.zig
@@ -3,14 +3,14 @@ const Builder = std.build.Builder;
 const LibExeObjectStep = std.build.LibExeObjStep;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
 
     const test_step = b.step("test", "Test the program");
     test_step.dependOn(b.getInstallStep());
 
     {
         // Without -dead_strip_dylibs we expect `-la` to include liba.dylib in the final executable
-        const exe = createScenario(b, mode);
+        const exe = createScenario(b, optimize);
 
         const check = exe.checkObject(.macho);
         check.checkStart("cmd LOAD_DYLIB");
@@ -27,7 +27,7 @@ pub fn build(b: *Builder) void {
 
     {
         // With -dead_strip_dylibs, we should include liba.dylib as it's unreachable
-        const exe = createScenario(b, mode);
+        const exe = createScenario(b, optimize);
         exe.dead_strip_dylibs = true;
 
         const run_cmd = exe.run();
@@ -36,10 +36,12 @@ pub fn build(b: *Builder) void {
     }
 }
 
-fn createScenario(b: *Builder, mode: std.builtin.Mode) *LibExeObjectStep {
-    const exe = b.addExecutable("test", null);
+fn createScenario(b: *Builder, optimize: std.builtin.OptimizeMode) *LibExeObjectStep {
+    const exe = b.addExecutable(.{
+        .name = "test",
+        .optimize = optimize,
+    });
     exe.addCSourceFile("main.c", &[0][]const u8{});
-    exe.setBuildMode(mode);
     exe.linkLibC();
     exe.linkFramework("Cocoa");
     return exe;
test/link/macho/dylib/build.zig
@@ -2,15 +2,18 @@ const std = @import("std");
 const Builder = std.build.Builder;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
     const target: std.zig.CrossTarget = .{ .os_tag = .macos };
 
     const test_step = b.step("test", "Test");
     test_step.dependOn(b.getInstallStep());
 
-    const dylib = b.addSharedLibrary("a", null, b.version(1, 0, 0));
-    dylib.setBuildMode(mode);
-    dylib.setTarget(target);
+    const dylib = b.addSharedLibrary(.{
+        .name = "a",
+        .version = .{ .major = 1, .minor = 0 },
+        .optimize = optimize,
+        .target = target,
+    });
     dylib.addCSourceFile("a.c", &.{});
     dylib.linkLibC();
     dylib.install();
@@ -24,9 +27,11 @@ pub fn build(b: *Builder) void {
 
     test_step.dependOn(&check_dylib.step);
 
-    const exe = b.addExecutable("main", null);
-    exe.setTarget(target);
-    exe.setBuildMode(mode);
+    const exe = b.addExecutable(.{
+        .name = "main",
+        .optimize = optimize,
+        .target = target,
+    });
     exe.addCSourceFile("main.c", &.{});
     exe.linkSystemLibrary("a");
     exe.linkLibC();
test/link/macho/empty/build.zig
@@ -2,17 +2,19 @@ const std = @import("std");
 const Builder = std.build.Builder;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
     const target: std.zig.CrossTarget = .{ .os_tag = .macos };
 
     const test_step = b.step("test", "Test the program");
     test_step.dependOn(b.getInstallStep());
 
-    const exe = b.addExecutable("test", null);
+    const exe = b.addExecutable(.{
+        .name = "test",
+        .optimize = optimize,
+        .target = target,
+    });
     exe.addCSourceFile("main.c", &[0][]const u8{});
     exe.addCSourceFile("empty.c", &[0][]const u8{});
-    exe.setBuildMode(mode);
-    exe.setTarget(target);
     exe.linkLibC();
 
     const run_cmd = std.build.EmulatableRunStep.create(b, "run", exe);
test/link/macho/entry/build.zig
@@ -2,14 +2,16 @@ const std = @import("std");
 const Builder = std.build.Builder;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
 
     const test_step = b.step("test", "Test");
     test_step.dependOn(b.getInstallStep());
 
-    const exe = b.addExecutable("main", null);
-    exe.setTarget(.{ .os_tag = .macos });
-    exe.setBuildMode(mode);
+    const exe = b.addExecutable(.{
+        .name = "main",
+        .optimize = optimize,
+        .target = .{ .os_tag = .macos },
+    });
     exe.addCSourceFile("main.c", &.{});
     exe.linkLibC();
     exe.entry_symbol_name = "_non_main";
test/link/macho/headerpad/build.zig
@@ -4,14 +4,14 @@ const Builder = std.build.Builder;
 const LibExeObjectStep = std.build.LibExeObjStep;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
 
     const test_step = b.step("test", "Test");
     test_step.dependOn(b.getInstallStep());
 
     {
         // Test -headerpad_max_install_names
-        const exe = simpleExe(b, mode);
+        const exe = simpleExe(b, optimize);
         exe.headerpad_max_install_names = true;
 
         const check = exe.checkObject(.macho);
@@ -36,7 +36,7 @@ pub fn build(b: *Builder) void {
 
     {
         // Test -headerpad
-        const exe = simpleExe(b, mode);
+        const exe = simpleExe(b, optimize);
         exe.headerpad_size = 0x10000;
 
         const check = exe.checkObject(.macho);
@@ -52,7 +52,7 @@ pub fn build(b: *Builder) void {
 
     {
         // Test both flags with -headerpad overriding -headerpad_max_install_names
-        const exe = simpleExe(b, mode);
+        const exe = simpleExe(b, optimize);
         exe.headerpad_max_install_names = true;
         exe.headerpad_size = 0x10000;
 
@@ -69,7 +69,7 @@ pub fn build(b: *Builder) void {
 
     {
         // Test both flags with -headerpad_max_install_names overriding -headerpad
-        const exe = simpleExe(b, mode);
+        const exe = simpleExe(b, optimize);
         exe.headerpad_size = 0x1000;
         exe.headerpad_max_install_names = true;
 
@@ -94,9 +94,11 @@ pub fn build(b: *Builder) void {
     }
 }
 
-fn simpleExe(b: *Builder, mode: std.builtin.Mode) *LibExeObjectStep {
-    const exe = b.addExecutable("main", null);
-    exe.setBuildMode(mode);
+fn simpleExe(b: *Builder, optimize: std.builtin.OptimizeMode) *LibExeObjectStep {
+    const exe = b.addExecutable(.{
+        .name = "main",
+        .optimize = optimize,
+    });
     exe.addCSourceFile("main.c", &.{});
     exe.linkLibC();
     exe.linkFramework("CoreFoundation");
test/link/macho/linksection/build.zig
@@ -1,15 +1,18 @@
 const std = @import("std");
 
 pub fn build(b: *std.build.Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
     const target = std.zig.CrossTarget{ .os_tag = .macos };
 
     const test_step = b.step("test", "Test");
     test_step.dependOn(b.getInstallStep());
 
-    const obj = b.addObject("test", "main.zig");
-    obj.setBuildMode(mode);
-    obj.setTarget(target);
+    const obj = b.addObject(.{
+        .name = "test",
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = optimize,
+        .target = target,
+    });
 
     const check = obj.checkObject(.macho);
 
@@ -19,7 +22,7 @@ pub fn build(b: *std.build.Builder) void {
     check.checkInSymtab();
     check.checkNext("{*} (__TEXT,__TestFn) external _testFn");
 
-    if (mode == .Debug) {
+    if (optimize == .Debug) {
         check.checkInSymtab();
         check.checkNext("{*} (__TEXT,__TestGenFnA) _main.testGenericFn__anon_{*}");
     }
test/link/macho/needed_framework/build.zig
@@ -3,16 +3,18 @@ const Builder = std.build.Builder;
 const LibExeObjectStep = std.build.LibExeObjStep;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
 
     const test_step = b.step("test", "Test the program");
     test_step.dependOn(b.getInstallStep());
 
     // -dead_strip_dylibs
     // -needed_framework Cocoa
-    const exe = b.addExecutable("test", null);
+    const exe = b.addExecutable(.{
+        .name = "test",
+        .optimize = optimize,
+    });
     exe.addCSourceFile("main.c", &[0][]const u8{});
-    exe.setBuildMode(mode);
     exe.linkLibC();
     exe.linkFrameworkNeeded("Cocoa");
     exe.dead_strip_dylibs = true;
test/link/macho/needed_library/build.zig
@@ -3,25 +3,30 @@ const Builder = std.build.Builder;
 const LibExeObjectStep = std.build.LibExeObjStep;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
     const target: std.zig.CrossTarget = .{ .os_tag = .macos };
 
     const test_step = b.step("test", "Test the program");
     test_step.dependOn(b.getInstallStep());
 
-    const dylib = b.addSharedLibrary("a", null, b.version(1, 0, 0));
-    dylib.setTarget(target);
-    dylib.setBuildMode(mode);
+    const dylib = b.addSharedLibrary(.{
+        .name = "a",
+        .version = .{ .major = 1, .minor = 0 },
+        .optimize = optimize,
+        .target = target,
+    });
     dylib.addCSourceFile("a.c", &.{});
     dylib.linkLibC();
     dylib.install();
 
     // -dead_strip_dylibs
     // -needed-la
-    const exe = b.addExecutable("test", null);
+    const exe = b.addExecutable(.{
+        .name = "test",
+        .optimize = optimize,
+        .target = target,
+    });
     exe.addCSourceFile("main.c", &[0][]const u8{});
-    exe.setBuildMode(mode);
-    exe.setTarget(target);
     exe.linkLibC();
     exe.linkSystemLibraryNeeded("a");
     exe.addLibraryPath(b.pathFromRoot("zig-out/lib"));
test/link/macho/objc/build.zig
@@ -2,15 +2,17 @@ const std = @import("std");
 const Builder = std.build.Builder;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
 
     const test_step = b.step("test", "Test the program");
 
-    const exe = b.addExecutable("test", null);
+    const exe = b.addExecutable(.{
+        .name = "test",
+        .optimize = optimize,
+    });
     exe.addIncludePath(".");
     exe.addCSourceFile("Foo.m", &[0][]const u8{});
     exe.addCSourceFile("test.m", &[0][]const u8{});
-    exe.setBuildMode(mode);
     exe.linkLibC();
     // TODO when we figure out how to ship framework stubs for cross-compilation,
     // populate paths to the sysroot here.
test/link/macho/objcpp/build.zig
@@ -2,16 +2,18 @@ const std = @import("std");
 const Builder = std.build.Builder;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
 
     const test_step = b.step("test", "Test the program");
 
-    const exe = b.addExecutable("test", null);
+    const exe = b.addExecutable(.{
+        .name = "test",
+        .optimize = optimize,
+    });
     b.default_step.dependOn(&exe.step);
     exe.addIncludePath(".");
     exe.addCSourceFile("Foo.mm", &[0][]const u8{});
     exe.addCSourceFile("test.mm", &[0][]const u8{});
-    exe.setBuildMode(mode);
     exe.linkLibCpp();
     // TODO when we figure out how to ship framework stubs for cross-compilation,
     // populate paths to the sysroot here.
test/link/macho/pagezero/build.zig
@@ -2,16 +2,18 @@ const std = @import("std");
 const Builder = std.build.Builder;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
     const target: std.zig.CrossTarget = .{ .os_tag = .macos };
 
     const test_step = b.step("test", "Test");
     test_step.dependOn(b.getInstallStep());
 
     {
-        const exe = b.addExecutable("pagezero", null);
-        exe.setTarget(target);
-        exe.setBuildMode(mode);
+        const exe = b.addExecutable(.{
+            .name = "pagezero",
+            .optimize = optimize,
+            .target = target,
+        });
         exe.addCSourceFile("main.c", &.{});
         exe.linkLibC();
         exe.pagezero_size = 0x4000;
@@ -29,9 +31,11 @@ pub fn build(b: *Builder) void {
     }
 
     {
-        const exe = b.addExecutable("no_pagezero", null);
-        exe.setTarget(target);
-        exe.setBuildMode(mode);
+        const exe = b.addExecutable(.{
+            .name = "no_pagezero",
+            .optimize = optimize,
+            .target = target,
+        });
         exe.addCSourceFile("main.c", &.{});
         exe.linkLibC();
         exe.pagezero_size = 0;
test/link/macho/search_strategy/build.zig
@@ -3,7 +3,7 @@ const Builder = std.build.Builder;
 const LibExeObjectStep = std.build.LibExeObjStep;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
     const target: std.zig.CrossTarget = .{ .os_tag = .macos };
 
     const test_step = b.step("test", "Test");
@@ -11,7 +11,7 @@ pub fn build(b: *Builder) void {
 
     {
         // -search_dylibs_first
-        const exe = createScenario(b, mode, target);
+        const exe = createScenario(b, optimize, target);
         exe.search_strategy = .dylibs_first;
 
         const check = exe.checkObject(.macho);
@@ -26,7 +26,7 @@ pub fn build(b: *Builder) void {
 
     {
         // -search_paths_first
-        const exe = createScenario(b, mode, target);
+        const exe = createScenario(b, optimize, target);
         exe.search_strategy = .paths_first;
 
         const run = std.build.EmulatableRunStep.create(b, "run", exe);
@@ -36,10 +36,12 @@ pub fn build(b: *Builder) void {
     }
 }
 
-fn createScenario(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarget) *LibExeObjectStep {
-    const static = b.addStaticLibrary("a", null);
-    static.setTarget(target);
-    static.setBuildMode(mode);
+fn createScenario(b: *Builder, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep {
+    const static = b.addStaticLibrary(.{
+        .name = "a",
+        .optimize = optimize,
+        .target = target,
+    });
     static.addCSourceFile("a.c", &.{});
     static.linkLibC();
     static.override_dest_dir = std.build.InstallDir{
@@ -47,9 +49,12 @@ fn createScenario(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarg
     };
     static.install();
 
-    const dylib = b.addSharedLibrary("a", null, b.version(1, 0, 0));
-    dylib.setTarget(target);
-    dylib.setBuildMode(mode);
+    const dylib = b.addSharedLibrary(.{
+        .name = "a",
+        .version = .{ .major = 1, .minor = 0 },
+        .optimize = optimize,
+        .target = target,
+    });
     dylib.addCSourceFile("a.c", &.{});
     dylib.linkLibC();
     dylib.override_dest_dir = std.build.InstallDir{
@@ -57,9 +62,11 @@ fn createScenario(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarg
     };
     dylib.install();
 
-    const exe = b.addExecutable("main", null);
-    exe.setTarget(target);
-    exe.setBuildMode(mode);
+    const exe = b.addExecutable(.{
+        .name = "main",
+        .optimize = optimize,
+        .target = target,
+    });
     exe.addCSourceFile("main.c", &.{});
     exe.linkSystemLibraryName("a");
     exe.linkLibC();
test/link/macho/stack_size/build.zig
@@ -2,15 +2,17 @@ const std = @import("std");
 const Builder = std.build.Builder;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
     const target: std.zig.CrossTarget = .{ .os_tag = .macos };
 
     const test_step = b.step("test", "Test");
     test_step.dependOn(b.getInstallStep());
 
-    const exe = b.addExecutable("main", null);
-    exe.setTarget(target);
-    exe.setBuildMode(mode);
+    const exe = b.addExecutable(.{
+        .name = "main",
+        .optimize = optimize,
+        .target = target,
+    });
     exe.addCSourceFile("main.c", &.{});
     exe.linkLibC();
     exe.stack_size = 0x100000000;
test/link/macho/strict_validation/build.zig
@@ -4,15 +4,18 @@ const Builder = std.build.Builder;
 const LibExeObjectStep = std.build.LibExeObjStep;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
     const target: std.zig.CrossTarget = .{ .os_tag = .macos };
 
     const test_step = b.step("test", "Test");
     test_step.dependOn(b.getInstallStep());
 
-    const exe = b.addExecutable("main", "main.zig");
-    exe.setBuildMode(mode);
-    exe.setTarget(target);
+    const exe = b.addExecutable(.{
+        .name = "main",
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = optimize,
+        .target = target,
+    });
     exe.linkLibC();
 
     const check_exe = exe.checkObject(.macho);
test/link/macho/tls/build.zig
@@ -2,18 +2,23 @@ const std = @import("std");
 const Builder = std.build.Builder;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
     const target: std.zig.CrossTarget = .{ .os_tag = .macos };
 
-    const lib = b.addSharedLibrary("a", null, b.version(1, 0, 0));
-    lib.setBuildMode(mode);
-    lib.setTarget(target);
+    const lib = b.addSharedLibrary(.{
+        .name = "a",
+        .version = .{ .major = 1, .minor = 0 },
+        .optimize = optimize,
+        .target = target,
+    });
     lib.addCSourceFile("a.c", &.{});
     lib.linkLibC();
 
-    const test_exe = b.addTest("main.zig");
-    test_exe.setBuildMode(mode);
-    test_exe.setTarget(target);
+    const test_exe = b.addTest(.{
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = optimize,
+        .target = target,
+    });
     test_exe.linkLibrary(lib);
     test_exe.linkLibC();
 
test/link/macho/unwind_info/build.zig
@@ -4,23 +4,23 @@ const Builder = std.build.Builder;
 const LibExeObjectStep = std.build.LibExeObjStep;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
     const target: std.zig.CrossTarget = .{ .os_tag = .macos };
 
     const test_step = b.step("test", "Test the program");
 
-    testUnwindInfo(b, test_step, mode, target, false);
-    testUnwindInfo(b, test_step, mode, target, true);
+    testUnwindInfo(b, test_step, optimize, target, false);
+    testUnwindInfo(b, test_step, optimize, target, true);
 }
 
 fn testUnwindInfo(
     b: *Builder,
     test_step: *std.build.Step,
-    mode: std.builtin.Mode,
+    optimize: std.builtin.OptimizeMode,
     target: std.zig.CrossTarget,
     dead_strip: bool,
 ) void {
-    const exe = createScenario(b, mode, target);
+    const exe = createScenario(b, optimize, target);
     exe.link_gc_sections = dead_strip;
 
     const check = exe.checkObject(.macho);
@@ -52,8 +52,12 @@ fn testUnwindInfo(
     test_step.dependOn(&run_cmd.step);
 }
 
-fn createScenario(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarget) *LibExeObjectStep {
-    const exe = b.addExecutable("test", null);
+fn createScenario(b: *Builder, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep {
+    const exe = b.addExecutable(.{
+        .name = "test",
+        .optimize = optimize,
+        .target = target,
+    });
     b.default_step.dependOn(&exe.step);
     exe.addIncludePath(".");
     exe.addCSourceFiles(&[_][]const u8{
@@ -61,8 +65,6 @@ fn createScenario(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarg
         "simple_string.cpp",
         "simple_string_owner.cpp",
     }, &[0][]const u8{});
-    exe.setBuildMode(mode);
-    exe.setTarget(target);
     exe.linkLibCpp();
     return exe;
 }
test/link/macho/uuid/build.zig
@@ -29,21 +29,21 @@ pub fn build(b: *Builder) void {
 fn testUuid(
     b: *Builder,
     test_step: *std.build.Step,
-    mode: std.builtin.Mode,
+    optimize: std.builtin.OptimizeMode,
     target: std.zig.CrossTarget,
     comptime exp: []const u8,
 ) void {
     // The calculated UUID value is independent of debug info and so it should
     // stay the same across builds.
     {
-        const dylib = simpleDylib(b, mode, target);
+        const dylib = simpleDylib(b, optimize, target);
         const check_dylib = dylib.checkObject(.macho);
         check_dylib.checkStart("cmd UUID");
         check_dylib.checkNext("uuid " ++ exp);
         test_step.dependOn(&check_dylib.step);
     }
     {
-        const dylib = simpleDylib(b, mode, target);
+        const dylib = simpleDylib(b, optimize, target);
         dylib.strip = true;
         const check_dylib = dylib.checkObject(.macho);
         check_dylib.checkStart("cmd UUID");
@@ -52,10 +52,13 @@ fn testUuid(
     }
 }
 
-fn simpleDylib(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarget) *LibExeObjectStep {
-    const dylib = b.addSharedLibrary("test", null, b.version(1, 0, 0));
-    dylib.setTarget(target);
-    dylib.setBuildMode(mode);
+fn simpleDylib(b: *Builder, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep {
+    const dylib = b.addSharedLibrary(.{
+        .name = "test",
+        .version = .{ .major = 1, .minor = 0 },
+        .optimize = optimize,
+        .target = target,
+    });
     dylib.addCSourceFile("test.c", &.{});
     dylib.linkLibC();
     return dylib;
test/link/macho/weak_framework/build.zig
@@ -3,14 +3,16 @@ const Builder = std.build.Builder;
 const LibExeObjectStep = std.build.LibExeObjStep;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
 
     const test_step = b.step("test", "Test the program");
     test_step.dependOn(b.getInstallStep());
 
-    const exe = b.addExecutable("test", null);
+    const exe = b.addExecutable(.{
+        .name = "test",
+        .optimize = optimize,
+    });
     exe.addCSourceFile("main.c", &[0][]const u8{});
-    exe.setBuildMode(mode);
     exe.linkLibC();
     exe.linkFrameworkWeak("Cocoa");
 
test/link/macho/weak_library/build.zig
@@ -3,23 +3,28 @@ const Builder = std.build.Builder;
 const LibExeObjectStep = std.build.LibExeObjStep;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
     const target: std.zig.CrossTarget = .{ .os_tag = .macos };
 
     const test_step = b.step("test", "Test the program");
     test_step.dependOn(b.getInstallStep());
 
-    const dylib = b.addSharedLibrary("a", null, b.version(1, 0, 0));
-    dylib.setTarget(target);
-    dylib.setBuildMode(mode);
+    const dylib = b.addSharedLibrary(.{
+        .name = "a",
+        .version = .{ .major = 1, .minor = 0, .patch = 0 },
+        .target = target,
+        .optimize = optimize,
+    });
     dylib.addCSourceFile("a.c", &.{});
     dylib.linkLibC();
     dylib.install();
 
-    const exe = b.addExecutable("test", null);
+    const exe = b.addExecutable(.{
+        .name = "test",
+        .target = target,
+        .optimize = optimize,
+    });
     exe.addCSourceFile("main.c", &[0][]const u8{});
-    exe.setTarget(target);
-    exe.setBuildMode(mode);
     exe.linkLibC();
     exe.linkSystemLibraryWeak("a");
     exe.addLibraryPath(b.pathFromRoot("zig-out/lib"));
test/link/static_lib_as_system_lib/build.zig
@@ -2,16 +2,23 @@ const std = @import("std");
 const Builder = std.build.Builder;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
+    const target = b.standardTargetOptions(.{});
 
-    const lib_a = b.addStaticLibrary("a", null);
+    const lib_a = b.addStaticLibrary(.{
+        .name = "a",
+        .optimize = optimize,
+        .target = target,
+    });
     lib_a.addCSourceFile("a.c", &[_][]const u8{});
-    lib_a.setBuildMode(mode);
     lib_a.addIncludePath(".");
     lib_a.install();
 
-    const test_exe = b.addTest("main.zig");
-    test_exe.setBuildMode(mode);
+    const test_exe = b.addTest(.{
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = optimize,
+        .target = target,
+    });
     test_exe.linkSystemLibrary("a"); // force linking liba.a as -la
     test_exe.addSystemIncludePath(".");
     const search_path = std.fs.path.join(b.allocator, &[_][]const u8{ b.install_path, "lib" }) catch unreachable;
test/link/wasm/archive/build.zig
@@ -2,16 +2,17 @@ const std = @import("std");
 const Builder = std.build.Builder;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
-
     const test_step = b.step("test", "Test");
     test_step.dependOn(b.getInstallStep());
 
     // The code in question will pull-in compiler-rt,
     // and therefore link with its archive file.
-    const lib = b.addSharedLibrary("main", "main.zig", .unversioned);
-    lib.setBuildMode(mode);
-    lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding });
+    const lib = b.addSharedLibrary(.{
+        .name = "main",
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = b.standardOptimizeOption(.{}),
+        .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
+    });
     lib.use_llvm = false;
     lib.use_lld = false;
     lib.strip = false;
test/link/wasm/basic-features/build.zig
@@ -1,14 +1,18 @@
 const std = @import("std");
 
 pub fn build(b: *std.build.Builder) void {
-    const mode = b.standardReleaseOptions();
-
     // Library with explicitly set cpu features
-    const lib = b.addSharedLibrary("lib", "main.zig", .unversioned);
-    lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding });
-    lib.target.cpu_model = .{ .explicit = &std.Target.wasm.cpu.mvp };
-    lib.target.cpu_features_add.addFeature(0); // index 0 == atomics (see std.Target.wasm.Features)
-    lib.setBuildMode(mode);
+    const lib = b.addSharedLibrary(.{
+        .name = "lib",
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = b.standardOptimizeOption(.{}),
+        .target = .{
+            .cpu_arch = .wasm32,
+            .cpu_model = .{ .explicit = &std.Target.wasm.cpu.mvp },
+            .cpu_features_add = std.Target.wasm.featureSet(&.{.atomics}),
+            .os_tag = .freestanding,
+        },
+    });
     lib.use_llvm = false;
     lib.use_lld = false;
 
test/link/wasm/bss/build.zig
@@ -2,14 +2,15 @@ const std = @import("std");
 const Builder = std.build.Builder;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
-
     const test_step = b.step("test", "Test");
     test_step.dependOn(b.getInstallStep());
 
-    const lib = b.addSharedLibrary("lib", "lib.zig", .unversioned);
-    lib.setBuildMode(mode);
-    lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding });
+    const lib = b.addSharedLibrary(.{
+        .name = "lib",
+        .root_source_file = .{ .path = "lib.zig" },
+        .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
+        .optimize = b.standardOptimizeOption(.{}),
+    });
     lib.use_llvm = false;
     lib.use_lld = false;
     lib.strip = false;
test/link/wasm/export/build.zig
@@ -1,24 +1,33 @@
 const std = @import("std");
 
 pub fn build(b: *std.build.Builder) void {
-    const mode = b.standardReleaseOptions();
-
-    const no_export = b.addSharedLibrary("no-export", "main.zig", .unversioned);
-    no_export.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding });
-    no_export.setBuildMode(mode);
+    const optimize = b.standardOptimizeOption(.{});
+
+    const no_export = b.addSharedLibrary(.{
+        .name = "no-export",
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = optimize,
+        .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
+    });
     no_export.use_llvm = false;
     no_export.use_lld = false;
 
-    const dynamic_export = b.addSharedLibrary("dynamic", "main.zig", .unversioned);
-    dynamic_export.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding });
-    dynamic_export.setBuildMode(mode);
+    const dynamic_export = b.addSharedLibrary(.{
+        .name = "dynamic",
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = optimize,
+        .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
+    });
     dynamic_export.rdynamic = true;
     dynamic_export.use_llvm = false;
     dynamic_export.use_lld = false;
 
-    const force_export = b.addSharedLibrary("force", "main.zig", .unversioned);
-    force_export.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding });
-    force_export.setBuildMode(mode);
+    const force_export = b.addSharedLibrary(.{
+        .name = "force",
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = optimize,
+        .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
+    });
     force_export.export_symbol_names = &.{"foo"};
     force_export.use_llvm = false;
     force_export.use_lld = false;
test/link/wasm/export-data/build.zig
@@ -5,9 +5,12 @@ pub fn build(b: *Builder) void {
     const test_step = b.step("test", "Test");
     test_step.dependOn(b.getInstallStep());
 
-    const lib = b.addSharedLibrary("lib", "lib.zig", .unversioned);
-    lib.setBuildMode(.ReleaseSafe); // to make the output deterministic in address positions
-    lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding });
+    const lib = b.addSharedLibrary(.{
+        .name = "lib",
+        .root_source_file = .{ .path = "lib.zig" },
+        .optimize = .ReleaseSafe, // to make the output deterministic in address positions
+        .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
+    });
     lib.use_lld = false;
     lib.export_symbol_names = &.{ "foo", "bar" };
     lib.global_base = 0; // put data section at address 0 to make data symbols easier to parse
test/link/wasm/extern/build.zig
@@ -1,10 +1,12 @@
 const std = @import("std");
 
 pub fn build(b: *std.build.Builder) void {
-    const mode = b.standardReleaseOptions();
-    const exe = b.addExecutable("extern", "main.zig");
-    exe.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .wasi });
-    exe.setBuildMode(mode);
+    const exe = b.addExecutable(.{
+        .name = "extern",
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = b.standardOptimizeOption(.{}),
+        .target = .{ .cpu_arch = .wasm32, .os_tag = .wasi },
+    });
     exe.addCSourceFile("foo.c", &.{});
     exe.use_llvm = false;
     exe.use_lld = false;
test/link/wasm/extern-mangle/build.zig
@@ -2,14 +2,15 @@ const std = @import("std");
 const Builder = std.build.Builder;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
-
     const test_step = b.step("test", "Test");
     test_step.dependOn(b.getInstallStep());
 
-    const lib = b.addSharedLibrary("lib", "lib.zig", .unversioned);
-    lib.setBuildMode(mode);
-    lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding });
+    const lib = b.addSharedLibrary(.{
+        .name = "lib",
+        .root_source_file = .{ .path = "lib.zig" },
+        .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
+        .optimize = b.standardOptimizeOption(.{}),
+    });
     lib.import_symbols = true; // import `a` and `b`
     lib.rdynamic = true; // export `foo`
     lib.install();
test/link/wasm/function-table/build.zig
@@ -2,28 +2,37 @@ const std = @import("std");
 const Builder = std.build.Builder;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
 
     const test_step = b.step("test", "Test");
     test_step.dependOn(b.getInstallStep());
 
-    const import_table = b.addSharedLibrary("lib", "lib.zig", .unversioned);
-    import_table.setBuildMode(mode);
-    import_table.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding });
+    const import_table = b.addSharedLibrary(.{
+        .name = "lib",
+        .root_source_file = .{ .path = "lib.zig" },
+        .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
+        .optimize = optimize,
+    });
     import_table.use_llvm = false;
     import_table.use_lld = false;
     import_table.import_table = true;
 
-    const export_table = b.addSharedLibrary("lib", "lib.zig", .unversioned);
-    export_table.setBuildMode(mode);
-    export_table.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding });
+    const export_table = b.addSharedLibrary(.{
+        .name = "lib",
+        .root_source_file = .{ .path = "lib.zig" },
+        .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
+        .optimize = optimize,
+    });
     export_table.use_llvm = false;
     export_table.use_lld = false;
     export_table.export_table = true;
 
-    const regular_table = b.addSharedLibrary("lib", "lib.zig", .unversioned);
-    regular_table.setBuildMode(mode);
-    regular_table.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding });
+    const regular_table = b.addSharedLibrary(.{
+        .name = "lib",
+        .root_source_file = .{ .path = "lib.zig" },
+        .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
+        .optimize = optimize,
+    });
     regular_table.use_llvm = false;
     regular_table.use_lld = false;
 
test/link/wasm/infer-features/build.zig
@@ -1,21 +1,32 @@
 const std = @import("std");
 
 pub fn build(b: *std.build.Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
 
     // Wasm Object file which we will use to infer the features from
-    const c_obj = b.addObject("c_obj", null);
-    c_obj.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding });
-    c_obj.target.cpu_model = .{ .explicit = &std.Target.wasm.cpu.bleeding_edge };
+    const c_obj = b.addObject(.{
+        .name = "c_obj",
+        .optimize = optimize,
+        .target = .{
+            .cpu_arch = .wasm32,
+            .cpu_model = .{ .explicit = &std.Target.wasm.cpu.bleeding_edge },
+            .os_tag = .freestanding,
+        },
+    });
     c_obj.addCSourceFile("foo.c", &.{});
-    c_obj.setBuildMode(mode);
 
     // Wasm library that doesn't have any features specified. This will
     // infer its featureset from other linked object files.
-    const lib = b.addSharedLibrary("lib", "main.zig", .unversioned);
-    lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding });
-    lib.target.cpu_model = .{ .explicit = &std.Target.wasm.cpu.mvp };
-    lib.setBuildMode(mode);
+    const lib = b.addSharedLibrary(.{
+        .name = "lib",
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = optimize,
+        .target = .{
+            .cpu_arch = .wasm32,
+            .cpu_model = .{ .explicit = &std.Target.wasm.cpu.mvp },
+            .os_tag = .freestanding,
+        },
+    });
     lib.use_llvm = false;
     lib.use_lld = false;
     lib.addObject(c_obj);
test/link/wasm/producers/build.zig
@@ -3,14 +3,15 @@ const builtin = @import("builtin");
 const Builder = std.build.Builder;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
-
     const test_step = b.step("test", "Test");
     test_step.dependOn(b.getInstallStep());
 
-    const lib = b.addSharedLibrary("lib", "lib.zig", .unversioned);
-    lib.setBuildMode(mode);
-    lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding });
+    const lib = b.addSharedLibrary(.{
+        .name = "lib",
+        .root_source_file = .{ .path = "lib.zig" },
+        .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
+        .optimize = b.standardOptimizeOption(.{}),
+    });
     lib.use_llvm = false;
     lib.use_lld = false;
     lib.strip = false;
test/link/wasm/segments/build.zig
@@ -2,14 +2,15 @@ const std = @import("std");
 const Builder = std.build.Builder;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
-
     const test_step = b.step("test", "Test");
     test_step.dependOn(b.getInstallStep());
 
-    const lib = b.addSharedLibrary("lib", "lib.zig", .unversioned);
-    lib.setBuildMode(mode);
-    lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding });
+    const lib = b.addSharedLibrary(.{
+        .name = "lib",
+        .root_source_file = .{ .path = "lib.zig" },
+        .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
+        .optimize = b.standardOptimizeOption(.{}),
+    });
     lib.use_llvm = false;
     lib.use_lld = false;
     lib.strip = false;
test/link/wasm/stack_pointer/build.zig
@@ -2,14 +2,15 @@ const std = @import("std");
 const Builder = std.build.Builder;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
-
     const test_step = b.step("test", "Test");
     test_step.dependOn(b.getInstallStep());
 
-    const lib = b.addSharedLibrary("lib", "lib.zig", .unversioned);
-    lib.setBuildMode(mode);
-    lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding });
+    const lib = b.addSharedLibrary(.{
+        .name = "lib",
+        .root_source_file = .{ .path = "lib.zig" },
+        .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
+        .optimize = b.standardOptimizeOption(.{}),
+    });
     lib.use_llvm = false;
     lib.use_lld = false;
     lib.strip = false;
test/link/wasm/type/build.zig
@@ -2,14 +2,15 @@ const std = @import("std");
 const Builder = std.build.Builder;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
-
     const test_step = b.step("test", "Test");
     test_step.dependOn(b.getInstallStep());
 
-    const lib = b.addSharedLibrary("lib", "lib.zig", .unversioned);
-    lib.setBuildMode(mode);
-    lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding });
+    const lib = b.addSharedLibrary(.{
+        .name = "lib",
+        .root_source_file = .{ .path = "lib.zig" },
+        .target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
+        .optimize = b.standardOptimizeOption(.{}),
+    });
     lib.use_llvm = false;
     lib.use_lld = false;
     lib.strip = false;
test/src/compare_output.zig
@@ -6,14 +6,14 @@ const ArrayList = std.ArrayList;
 const fmt = std.fmt;
 const mem = std.mem;
 const fs = std.fs;
-const Mode = std.builtin.Mode;
+const OptimizeMode = std.builtin.OptimizeMode;
 
 pub const CompareOutputContext = struct {
     b: *build.Builder,
     step: *build.Step,
     test_index: usize,
     test_filter: ?[]const u8,
-    modes: []const Mode,
+    optimize_modes: []const OptimizeMode,
 
     const Special = enum {
         None,
@@ -102,7 +102,11 @@ pub const CompareOutputContext = struct {
                     if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
                 }
 
-                const exe = b.addExecutable("test", null);
+                const exe = b.addExecutable(.{
+                    .name = "test",
+                    .target = .{},
+                    .optimize = .Debug,
+                });
                 exe.addAssemblyFileSource(write_src.getFileSource(case.sources.items[0].filename).?);
 
                 const run = exe.run();
@@ -113,19 +117,23 @@ pub const CompareOutputContext = struct {
                 self.step.dependOn(&run.step);
             },
             Special.None => {
-                for (self.modes) |mode| {
+                for (self.optimize_modes) |optimize| {
                     const annotated_case_name = fmt.allocPrint(self.b.allocator, "{s} {s} ({s})", .{
                         "compare-output",
                         case.name,
-                        @tagName(mode),
+                        @tagName(optimize),
                     }) catch unreachable;
                     if (self.test_filter) |filter| {
                         if (mem.indexOf(u8, annotated_case_name, filter) == null) continue;
                     }
 
                     const basename = case.sources.items[0].filename;
-                    const exe = b.addExecutableSource("test", write_src.getFileSource(basename).?);
-                    exe.setBuildMode(mode);
+                    const exe = b.addExecutable(.{
+                        .name = "test",
+                        .root_source_file = write_src.getFileSource(basename).?,
+                        .optimize = optimize,
+                        .target = .{},
+                    });
                     if (case.link_libc) {
                         exe.linkSystemLibrary("c");
                     }
@@ -139,13 +147,20 @@ pub const CompareOutputContext = struct {
                 }
             },
             Special.RuntimeSafety => {
+                // TODO iterate over self.optimize_modes and test this in both
+                // debug and release safe mode
                 const annotated_case_name = fmt.allocPrint(self.b.allocator, "safety {s}", .{case.name}) catch unreachable;
                 if (self.test_filter) |filter| {
                     if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
                 }
 
                 const basename = case.sources.items[0].filename;
-                const exe = b.addExecutableSource("test", write_src.getFileSource(basename).?);
+                const exe = b.addExecutable(.{
+                    .name = "test",
+                    .root_source_file = write_src.getFileSource(basename).?,
+                    .target = .{},
+                    .optimize = .Debug,
+                });
                 if (case.link_libc) {
                     exe.linkSystemLibrary("c");
                 }
test/src/run_translated_c.zig
@@ -85,11 +85,14 @@ pub const RunTranslatedCContext = struct {
         for (case.sources.items) |src_file| {
             write_src.add(src_file.filename, src_file.source);
         }
-        const translate_c = b.addTranslateC(write_src.getFileSource(case.sources.items[0].filename).?);
+        const translate_c = b.addTranslateC(.{
+            .source_file = write_src.getFileSource(case.sources.items[0].filename).?,
+            .target = .{},
+            .optimize = .Debug,
+        });
 
         translate_c.step.name = b.fmt("{s} translate-c", .{annotated_case_name});
-        const exe = translate_c.addExecutable();
-        exe.setTarget(self.target);
+        const exe = translate_c.addExecutable(.{});
         exe.step.name = b.fmt("{s} build-exe", .{annotated_case_name});
         exe.linkLibC();
         const run = exe.run();
test/src/translate_c.zig
@@ -108,10 +108,13 @@ pub const TranslateCContext = struct {
             write_src.add(src_file.filename, src_file.source);
         }
 
-        const translate_c = b.addTranslateC(write_src.getFileSource(case.sources.items[0].filename).?);
+        const translate_c = b.addTranslateC(.{
+            .source_file = write_src.getFileSource(case.sources.items[0].filename).?,
+            .target = case.target,
+            .optimize = .Debug,
+        });
 
         translate_c.step.name = annotated_case_name;
-        translate_c.setTarget(case.target);
 
         const check_file = translate_c.addCheckFile(case.expected_lines.items);
 
test/standalone/brace_expansion/build.zig
@@ -1,8 +1,10 @@
 const Builder = @import("std").build.Builder;
 
 pub fn build(b: *Builder) void {
-    const main = b.addTest("main.zig");
-    main.setBuildMode(b.standardReleaseOptions());
+    const main = b.addTest(.{
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = b.standardOptimizeOption(.{}),
+    });
 
     const test_step = b.step("test", "Test it");
     test_step.dependOn(&main.step);
test/standalone/c_compiler/build.zig
@@ -12,23 +12,27 @@ fn isRunnableTarget(t: CrossTarget) bool {
 }
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
     const target = b.standardTargetOptions(.{});
 
     const test_step = b.step("test", "Test the program");
 
-    const exe_c = b.addExecutable("test_c", null);
+    const exe_c = b.addExecutable(.{
+        .name = "test_c",
+        .optimize = optimize,
+        .target = target,
+    });
     b.default_step.dependOn(&exe_c.step);
     exe_c.addCSourceFile("test.c", &[0][]const u8{});
-    exe_c.setBuildMode(mode);
-    exe_c.setTarget(target);
     exe_c.linkLibC();
 
-    const exe_cpp = b.addExecutable("test_cpp", null);
+    const exe_cpp = b.addExecutable(.{
+        .name = "test_cpp",
+        .optimize = optimize,
+        .target = target,
+    });
     b.default_step.dependOn(&exe_cpp.step);
     exe_cpp.addCSourceFile("test.cpp", &[0][]const u8{});
-    exe_cpp.setBuildMode(mode);
-    exe_cpp.setTarget(target);
     exe_cpp.linkLibCpp();
 
     switch (target.getOsTag()) {
test/standalone/emit_asm_and_bin/build.zig
@@ -1,8 +1,10 @@
 const Builder = @import("std").build.Builder;
 
 pub fn build(b: *Builder) void {
-    const main = b.addTest("main.zig");
-    main.setBuildMode(b.standardReleaseOptions());
+    const main = b.addTest(.{
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = b.standardOptimizeOption(.{}),
+    });
     main.emit_asm = .{ .emit_to = b.pathFromRoot("main.s") };
     main.emit_bin = .{ .emit_to = b.pathFromRoot("main") };
 
test/standalone/empty_env/build.zig
@@ -1,8 +1,11 @@
 const Builder = @import("std").build.Builder;
 
 pub fn build(b: *Builder) void {
-    const main = b.addExecutable("main", "main.zig");
-    main.setBuildMode(b.standardReleaseOptions());
+    const main = b.addExecutable(.{
+        .name = "main",
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = b.standardOptimizeOption(.{}),
+    });
 
     const run = main.run();
     run.clearEnvironment();
test/standalone/global_linkage/build.zig
@@ -1,16 +1,26 @@
 const Builder = @import("std").build.Builder;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
 
-    const obj1 = b.addStaticLibrary("obj1", "obj1.zig");
-    obj1.setBuildMode(mode);
+    const obj1 = b.addStaticLibrary(.{
+        .name = "obj1",
+        .root_source_file = .{ .path = "obj1.zig" },
+        .optimize = optimize,
+        .target = .{},
+    });
 
-    const obj2 = b.addStaticLibrary("obj2", "obj2.zig");
-    obj2.setBuildMode(mode);
+    const obj2 = b.addStaticLibrary(.{
+        .name = "obj2",
+        .root_source_file = .{ .path = "obj2.zig" },
+        .optimize = optimize,
+        .target = .{},
+    });
 
-    const main = b.addTest("main.zig");
-    main.setBuildMode(mode);
+    const main = b.addTest(.{
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = optimize,
+    });
     main.linkLibrary(obj1);
     main.linkLibrary(obj2);
 
test/standalone/install_raw_hex/build.zig
@@ -10,11 +10,14 @@ pub fn build(b: *std.build.Builder) void {
         .abi = .gnueabihf,
     };
 
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
 
-    const elf = b.addExecutable("zig-nrf52-blink.elf", "main.zig");
-    elf.setTarget(target);
-    elf.setBuildMode(mode);
+    const elf = b.addExecutable(.{
+        .name = "zig-nrf52-blink.elf",
+        .root_source_file = .{ .path = "main.zig" },
+        .target = target,
+        .optimize = optimize,
+    });
 
     const test_step = b.step("test", "Test the program");
     b.default_step.dependOn(test_step);
test/standalone/issue_11595/build.zig
@@ -12,11 +12,15 @@ fn isRunnableTarget(t: CrossTarget) bool {
 }
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
     const target = b.standardTargetOptions(.{});
 
-    const exe = b.addExecutable("zigtest", "main.zig");
-    exe.setBuildMode(mode);
+    const exe = b.addExecutable(.{
+        .name = "zigtest",
+        .root_source_file = .{ .path = "main.zig" },
+        .target = target,
+        .optimize = optimize,
+    });
     exe.install();
 
     const c_sources = [_][]const u8{
@@ -39,7 +43,6 @@ pub fn build(b: *Builder) void {
     exe.defineCMacro("QUX", "\"Q\" \"UX\"");
     exe.defineCMacro("QUUX", "\"QU\\\"UX\"");
 
-    exe.setTarget(target);
     b.default_step.dependOn(&exe.step);
 
     const test_step = b.step("test", "Test the program");
test/standalone/issue_12588/build.zig
@@ -2,12 +2,15 @@ const std = @import("std");
 const Builder = std.build.Builder;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
     const target = b.standardTargetOptions(.{});
 
-    const obj = b.addObject("main", "main.zig");
-    obj.setBuildMode(mode);
-    obj.setTarget(target);
+    const obj = b.addObject(.{
+        .name = "main",
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = optimize,
+        .target = target,
+    });
     obj.emit_llvm_ir = .{ .emit_to = b.pathFromRoot("main.ll") };
     obj.emit_llvm_bc = .{ .emit_to = b.pathFromRoot("main.bc") };
     obj.emit_bin = .no_emit;
test/standalone/issue_12706/build.zig
@@ -12,11 +12,15 @@ fn isRunnableTarget(t: CrossTarget) bool {
 }
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
     const target = b.standardTargetOptions(.{});
 
-    const exe = b.addExecutable("main", "main.zig");
-    exe.setBuildMode(mode);
+    const exe = b.addExecutable(.{
+        .name = "main",
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = optimize,
+        .target = target,
+    });
     exe.install();
 
     const c_sources = [_][]const u8{
@@ -26,7 +30,6 @@ pub fn build(b: *Builder) void {
     exe.addCSourceFiles(&c_sources, &.{});
     exe.linkLibC();
 
-    exe.setTarget(target);
     b.default_step.dependOn(&exe.step);
 
     const test_step = b.step("test", "Test the program");
test/standalone/issue_13030/build.zig
@@ -4,13 +4,15 @@ const Builder = std.build.Builder;
 const CrossTarget = std.zig.CrossTarget;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
     const target = b.standardTargetOptions(.{});
 
-    const obj = b.addObject("main", "main.zig");
-    obj.setBuildMode(mode);
-
-    obj.setTarget(target);
+    const obj = b.addObject(.{
+        .name = "main",
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = optimize,
+        .target = target,
+    });
     b.default_step.dependOn(&obj.step);
 
     const test_step = b.step("test", "Test the program");
test/standalone/issue_339/build.zig
@@ -1,7 +1,12 @@
 const Builder = @import("std").build.Builder;
 
 pub fn build(b: *Builder) void {
-    const obj = b.addObject("test", "test.zig");
+    const obj = b.addObject(.{
+        .name = "test",
+        .root_source_file = .{ .path = "test.zig" },
+        .target = b.standardTargetOptions(.{}),
+        .optimize = b.standardOptimizeOption(.{}),
+    });
 
     const test_step = b.step("test", "Test the program");
     test_step.dependOn(&obj.step);
test/standalone/issue_5825/build.zig
@@ -6,17 +6,22 @@ pub fn build(b: *Builder) void {
         .os_tag = .windows,
         .abi = .msvc,
     };
-    const mode = b.standardReleaseOptions();
-    const obj = b.addObject("issue_5825", "main.zig");
-    obj.setTarget(target);
-    obj.setBuildMode(mode);
+    const optimize = b.standardOptimizeOption(.{});
+    const obj = b.addObject(.{
+        .name = "issue_5825",
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = optimize,
+        .target = target,
+    });
 
-    const exe = b.addExecutable("issue_5825", null);
+    const exe = b.addExecutable(.{
+        .name = "issue_5825",
+        .optimize = optimize,
+        .target = target,
+    });
     exe.subsystem = .Console;
     exe.linkSystemLibrary("kernel32");
     exe.linkSystemLibrary("ntdll");
-    exe.setTarget(target);
-    exe.setBuildMode(mode);
     exe.addObject(obj);
 
     const test_step = b.step("test", "Test the program");
test/standalone/issue_7030/build.zig
@@ -1,10 +1,13 @@
 const Builder = @import("std").build.Builder;
 
 pub fn build(b: *Builder) void {
-    const exe = b.addExecutable("issue_7030", "main.zig");
-    exe.setTarget(.{
-        .cpu_arch = .wasm32,
-        .os_tag = .freestanding,
+    const exe = b.addExecutable(.{
+        .name = "issue_7030",
+        .root_source_file = .{ .path = "main.zig" },
+        .target = .{
+            .cpu_arch = .wasm32,
+            .os_tag = .freestanding,
+        },
     });
     exe.install();
     b.default_step.dependOn(&exe.step);
test/standalone/issue_794/build.zig
@@ -1,7 +1,9 @@
 const Builder = @import("std").build.Builder;
 
 pub fn build(b: *Builder) void {
-    const test_artifact = b.addTest("main.zig");
+    const test_artifact = b.addTest(.{
+        .root_source_file = .{ .path = "main.zig" },
+    });
     test_artifact.addIncludePath("a_directory");
 
     b.default_step.dependOn(&test_artifact.step);
test/standalone/issue_8550/build.zig
@@ -8,12 +8,15 @@ pub fn build(b: *std.build.Builder) !void {
             .explicit = &std.Target.arm.cpu.arm1176jz_s,
         },
     };
-    const mode = b.standardReleaseOptions();
-    const kernel = b.addExecutable("kernel", "./main.zig");
+    const optimize = b.standardOptimizeOption(.{});
+    const kernel = b.addExecutable(.{
+        .name = "kernel",
+        .root_source_file = .{ .path = "./main.zig" },
+        .optimize = optimize,
+        .target = target,
+    });
     kernel.addObjectFile("./boot.S");
     kernel.setLinkerScriptPath(.{ .path = "./linker.ld" });
-    kernel.setBuildMode(mode);
-    kernel.setTarget(target);
     kernel.install();
 
     const test_step = b.step("test", "Test it");
test/standalone/issue_9812/build.zig
@@ -1,9 +1,11 @@
 const std = @import("std");
 
 pub fn build(b: *std.build.Builder) !void {
-    const mode = b.standardReleaseOptions();
-    const zip_add = b.addTest("main.zig");
-    zip_add.setBuildMode(mode);
+    const optimize = b.standardOptimizeOption(.{});
+    const zip_add = b.addTest(.{
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = optimize,
+    });
     zip_add.addCSourceFile("vendor/kuba-zip/zip.c", &[_][]const u8{
         "-std=c99",
         "-fno-sanitize=undefined",
test/standalone/load_dynamic_library/build.zig
@@ -1,13 +1,23 @@
 const Builder = @import("std").build.Builder;
 
 pub fn build(b: *Builder) void {
-    const opts = b.standardReleaseOptions();
+    const target = b.standardTargetOptions(.{});
+    const optimize = b.standardOptimizeOption(.{});
 
-    const lib = b.addSharedLibrary("add", "add.zig", b.version(1, 0, 0));
-    lib.setBuildMode(opts);
+    const lib = b.addSharedLibrary(.{
+        .name = "add",
+        .root_source_file = .{ .path = "add.zig" },
+        .version = .{ .major = 1, .minor = 0 },
+        .optimize = optimize,
+        .target = target,
+    });
 
-    const main = b.addExecutable("main", "main.zig");
-    main.setBuildMode(opts);
+    const main = b.addExecutable(.{
+        .name = "main",
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = optimize,
+        .target = target,
+    });
 
     const run = main.run();
     run.addArtifactArg(lib);
test/standalone/main_pkg_path/build.zig
@@ -1,7 +1,9 @@
 const Builder = @import("std").build.Builder;
 
 pub fn build(b: *Builder) void {
-    const test_exe = b.addTest("a/test.zig");
+    const test_exe = b.addTest(.{
+        .root_source_file = .{ .path = "a/test.zig" },
+    });
     test_exe.setMainPkgPath(".");
 
     const test_step = b.step("test", "Test the program");
test/standalone/mix_c_files/build.zig
@@ -12,14 +12,17 @@ fn isRunnableTarget(t: CrossTarget) bool {
 }
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
     const target = b.standardTargetOptions(.{});
 
-    const exe = b.addExecutable("test", "main.zig");
+    const exe = b.addExecutable(.{
+        .name = "test",
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = optimize,
+        .target = target,
+    });
     exe.addCSourceFile("test.c", &[_][]const u8{"-std=c11"});
-    exe.setBuildMode(mode);
     exe.linkLibC();
-    exe.setTarget(target);
     b.default_step.dependOn(&exe.step);
 
     const test_step = b.step("test", "Test the program");
test/standalone/mix_o_files/build.zig
@@ -1,9 +1,19 @@
 const Builder = @import("std").build.Builder;
 
 pub fn build(b: *Builder) void {
-    const obj = b.addObject("base64", "base64.zig");
+    const optimize = b.standardOptimizeOption(.{});
 
-    const exe = b.addExecutable("test", null);
+    const obj = b.addObject(.{
+        .name = "base64",
+        .root_source_file = .{ .path = "base64.zig" },
+        .optimize = optimize,
+        .target = .{},
+    });
+
+    const exe = b.addExecutable(.{
+        .name = "test",
+        .optimize = optimize,
+    });
     exe.addCSourceFile("test.c", &[_][]const u8{"-std=c99"});
     exe.addObject(obj);
     exe.linkSystemLibrary("c");
test/standalone/options/build.zig
@@ -2,11 +2,13 @@ const std = @import("std");
 
 pub fn build(b: *std.build.Builder) void {
     const target = b.standardTargetOptions(.{});
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
 
-    const main = b.addTest("src/main.zig");
-    main.setTarget(target);
-    main.setBuildMode(mode);
+    const main = b.addTest(.{
+        .root_source_file = .{ .path = "src/main.zig" },
+        .target = target,
+        .optimize = optimize,
+    });
 
     const options = b.addOptions();
     main.addOptions("build_options", options);
test/standalone/pie/build.zig
@@ -1,8 +1,10 @@
 const Builder = @import("std").build.Builder;
 
 pub fn build(b: *Builder) void {
-    const main = b.addTest("main.zig");
-    main.setBuildMode(b.standardReleaseOptions());
+    const main = b.addTest(.{
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = b.standardOptimizeOption(.{}),
+    });
     main.pie = true;
 
     const test_step = b.step("test", "Test the program");
test/standalone/pkg_import/build.zig
@@ -1,13 +1,14 @@
 const Builder = @import("std").build.Builder;
 
 pub fn build(b: *Builder) void {
-    const exe = b.addExecutable("test", "test.zig");
-    exe.addPackagePath("my_pkg", "pkg.zig");
+    const optimize = b.standardOptimizeOption(.{});
 
-    // This is duplicated to test that you are allowed to call
-    // b.standardReleaseOptions() twice.
-    exe.setBuildMode(b.standardReleaseOptions());
-    exe.setBuildMode(b.standardReleaseOptions());
+    const exe = b.addExecutable(.{
+        .name = "test",
+        .root_source_file = .{ .path = "test.zig" },
+        .optimize = optimize,
+    });
+    exe.addPackagePath("my_pkg", "pkg.zig");
 
     const run = exe.run();
 
test/standalone/shared_library/build.zig
@@ -1,12 +1,21 @@
 const Builder = @import("std").build.Builder;
 
 pub fn build(b: *Builder) void {
+    const optimize = b.standardOptimizeOption(.{});
     const target = b.standardTargetOptions(.{});
-    const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));
-    lib.setTarget(target);
+    const lib = b.addSharedLibrary(.{
+        .name = "mathtest",
+        .root_source_file = .{ .path = "mathtest.zig" },
+        .version = .{ .major = 1, .minor = 0 },
+        .target = target,
+        .optimize = optimize,
+    });
 
-    const exe = b.addExecutable("test", null);
-    exe.setTarget(target);
+    const exe = b.addExecutable(.{
+        .name = "test",
+        .target = target,
+        .optimize = optimize,
+    });
     exe.addCSourceFile("test.c", &[_][]const u8{"-std=c99"});
     exe.linkLibrary(lib);
     exe.linkSystemLibrary("c");
test/standalone/static_c_lib/build.zig
@@ -1,15 +1,20 @@
 const Builder = @import("std").build.Builder;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
 
-    const foo = b.addStaticLibrary("foo", null);
+    const foo = b.addStaticLibrary(.{
+        .name = "foo",
+        .optimize = optimize,
+        .target = .{},
+    });
     foo.addCSourceFile("foo.c", &[_][]const u8{});
-    foo.setBuildMode(mode);
     foo.addIncludePath(".");
 
-    const test_exe = b.addTest("foo.zig");
-    test_exe.setBuildMode(mode);
+    const test_exe = b.addTest(.{
+        .root_source_file = .{ .path = "foo.zig" },
+        .optimize = optimize,
+    });
     test_exe.linkLibrary(foo);
     test_exe.addIncludePath(".");
 
test/standalone/test_runner_path/build.zig
@@ -1,7 +1,10 @@
 const Builder = @import("std").build.Builder;
 
 pub fn build(b: *Builder) void {
-    const test_exe = b.addTestExe("test", "test.zig");
+    const test_exe = b.addTest(.{
+        .root_source_file = .{ .path = "test.zig" },
+        .kind = .test_exe,
+    });
     test_exe.test_runner = "test_runner.zig";
 
     const test_run = test_exe.run();
test/standalone/use_alias/build.zig
@@ -1,8 +1,10 @@
 const Builder = @import("std").build.Builder;
 
 pub fn build(b: *Builder) void {
-    const main = b.addTest("main.zig");
-    main.setBuildMode(b.standardReleaseOptions());
+    const main = b.addTest(.{
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = b.standardOptimizeOption(.{}),
+    });
     main.addIncludePath(".");
 
     const test_step = b.step("test", "Test it");
test/standalone/windows_spawn/build.zig
@@ -1,13 +1,20 @@
 const Builder = @import("std").build.Builder;
 
 pub fn build(b: *Builder) void {
-    const mode = b.standardReleaseOptions();
+    const optimize = b.standardOptimizeOption(.{});
 
-    const hello = b.addExecutable("hello", "hello.zig");
-    hello.setBuildMode(mode);
+    const hello = b.addExecutable(.{
+        .name = "hello",
+        .root_source_file = .{ .path = "hello.zig" },
+        .optimize = optimize,
+    });
+
+    const main = b.addExecutable(.{
+        .name = "main",
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = optimize,
+    });
 
-    const main = b.addExecutable("main", "main.zig");
-    main.setBuildMode(mode);
     const run = main.run();
     run.addArtifactArg(hello);
 
test/tests.zig
@@ -8,7 +8,7 @@ const fs = std.fs;
 const mem = std.mem;
 const fmt = std.fmt;
 const ArrayList = std.ArrayList;
-const Mode = std.builtin.Mode;
+const OptimizeMode = std.builtin.OptimizeMode;
 const LibExeObjStep = build.LibExeObjStep;
 const Allocator = mem.Allocator;
 const ExecError = build.Builder.ExecError;
@@ -30,7 +30,7 @@ pub const CompareOutputContext = @import("src/compare_output.zig").CompareOutput
 
 const TestTarget = struct {
     target: CrossTarget = @as(CrossTarget, .{}),
-    mode: std.builtin.Mode = .Debug,
+    optimize_mode: std.builtin.OptimizeMode = .Debug,
     link_libc: bool = false,
     single_threaded: bool = false,
     disable_native: bool = false,
@@ -423,38 +423,38 @@ const test_targets = blk: {
 
         // Do the release tests last because they take a long time
         .{
-            .mode = .ReleaseFast,
+            .optimize_mode = .ReleaseFast,
         },
         .{
             .link_libc = true,
-            .mode = .ReleaseFast,
+            .optimize_mode = .ReleaseFast,
         },
         .{
-            .mode = .ReleaseFast,
+            .optimize_mode = .ReleaseFast,
             .single_threaded = true,
         },
 
         .{
-            .mode = .ReleaseSafe,
+            .optimize_mode = .ReleaseSafe,
         },
         .{
             .link_libc = true,
-            .mode = .ReleaseSafe,
+            .optimize_mode = .ReleaseSafe,
         },
         .{
-            .mode = .ReleaseSafe,
+            .optimize_mode = .ReleaseSafe,
             .single_threaded = true,
         },
 
         .{
-            .mode = .ReleaseSmall,
+            .optimize_mode = .ReleaseSmall,
         },
         .{
             .link_libc = true,
-            .mode = .ReleaseSmall,
+            .optimize_mode = .ReleaseSmall,
         },
         .{
-            .mode = .ReleaseSmall,
+            .optimize_mode = .ReleaseSmall,
             .single_threaded = true,
         },
     };
@@ -462,14 +462,14 @@ const test_targets = blk: {
 
 const max_stdout_size = 1 * 1024 * 1024; // 1 MB
 
-pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step {
+pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode) *build.Step {
     const cases = b.allocator.create(CompareOutputContext) catch unreachable;
     cases.* = CompareOutputContext{
         .b = b,
         .step = b.step("test-compare-output", "Run the compare output tests"),
         .test_index = 0,
         .test_filter = test_filter,
-        .modes = modes,
+        .optimize_modes = optimize_modes,
     };
 
     compare_output.addCases(cases);
@@ -477,14 +477,14 @@ pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8, modes:
     return cases.step;
 }
 
-pub fn addStackTraceTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step {
+pub fn addStackTraceTests(b: *build.Builder, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode) *build.Step {
     const cases = b.allocator.create(StackTracesContext) catch unreachable;
     cases.* = StackTracesContext{
         .b = b,
         .step = b.step("test-stack-traces", "Run the stack trace tests"),
         .test_index = 0,
         .test_filter = test_filter,
-        .modes = modes,
+        .optimize_modes = optimize_modes,
     };
 
     stack_traces.addCases(cases);
@@ -495,7 +495,7 @@ pub fn addStackTraceTests(b: *build.Builder, test_filter: ?[]const u8, modes: []
 pub fn addStandaloneTests(
     b: *build.Builder,
     test_filter: ?[]const u8,
-    modes: []const Mode,
+    optimize_modes: []const OptimizeMode,
     skip_non_native: bool,
     enable_macos_sdk: bool,
     target: std.zig.CrossTarget,
@@ -513,7 +513,7 @@ pub fn addStandaloneTests(
         .step = b.step("test-standalone", "Run the standalone tests"),
         .test_index = 0,
         .test_filter = test_filter,
-        .modes = modes,
+        .optimize_modes = optimize_modes,
         .skip_non_native = skip_non_native,
         .enable_macos_sdk = enable_macos_sdk,
         .target = target,
@@ -534,7 +534,7 @@ pub fn addStandaloneTests(
 pub fn addLinkTests(
     b: *build.Builder,
     test_filter: ?[]const u8,
-    modes: []const Mode,
+    optimize_modes: []const OptimizeMode,
     enable_macos_sdk: bool,
     omit_stage2: bool,
     enable_symlinks_windows: bool,
@@ -545,7 +545,7 @@ pub fn addLinkTests(
         .step = b.step("test-link", "Run the linker tests"),
         .test_index = 0,
         .test_filter = test_filter,
-        .modes = modes,
+        .optimize_modes = optimize_modes,
         .skip_non_native = true,
         .enable_macos_sdk = enable_macos_sdk,
         .target = .{},
@@ -556,12 +556,17 @@ pub fn addLinkTests(
     return cases.step;
 }
 
-pub fn addCliTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step {
+pub fn addCliTests(b: *build.Builder, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode) *build.Step {
     _ = test_filter;
-    _ = modes;
+    _ = optimize_modes;
     const step = b.step("test-cli", "Test the command line interface");
 
-    const exe = b.addExecutable("test-cli", "test/cli.zig");
+    const exe = b.addExecutable(.{
+        .name = "test-cli",
+        .root_source_file = .{ .path = "test/cli.zig" },
+        .target = .{},
+        .optimize = .Debug,
+    });
     const run_cmd = exe.run();
     run_cmd.addArgs(&[_][]const u8{
         fs.realpathAlloc(b.allocator, b.zig_exe) catch unreachable,
@@ -572,14 +577,14 @@ pub fn addCliTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const M
     return step;
 }
 
-pub fn addAssembleAndLinkTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step {
+pub fn addAssembleAndLinkTests(b: *build.Builder, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode) *build.Step {
     const cases = b.allocator.create(CompareOutputContext) catch unreachable;
     cases.* = CompareOutputContext{
         .b = b,
         .step = b.step("test-asm-link", "Run the assemble and link tests"),
         .test_index = 0,
         .test_filter = test_filter,
-        .modes = modes,
+        .optimize_modes = optimize_modes,
     };
 
     assemble_and_link.addCases(cases);
@@ -640,7 +645,7 @@ pub fn addPkgTests(
     root_src: []const u8,
     name: []const u8,
     desc: []const u8,
-    modes: []const Mode,
+    optimize_modes: []const OptimizeMode,
     skip_single_threaded: bool,
     skip_non_native: bool,
     skip_libc: bool,
@@ -677,8 +682,8 @@ pub fn addPkgTests(
             else => if (skip_stage2) continue,
         };
 
-        const want_this_mode = for (modes) |m| {
-            if (m == test_target.mode) break true;
+        const want_this_mode = for (optimize_modes) |m| {
+            if (m == test_target.optimize_mode) break true;
         } else false;
         if (!want_this_mode) continue;
 
@@ -691,21 +696,23 @@ pub fn addPkgTests(
 
         const triple_prefix = test_target.target.zigTriple(b.allocator) catch unreachable;
 
-        const these_tests = b.addTest(root_src);
+        const these_tests = b.addTest(.{
+            .root_source_file = .{ .path = root_src },
+            .optimize = test_target.optimize_mode,
+            .target = test_target.target,
+        });
         const single_threaded_txt = if (test_target.single_threaded) "single" else "multi";
         const backend_txt = if (test_target.backend) |backend| @tagName(backend) else "default";
         these_tests.setNamePrefix(b.fmt("{s}-{s}-{s}-{s}-{s}-{s} ", .{
             name,
             triple_prefix,
-            @tagName(test_target.mode),
+            @tagName(test_target.optimize_mode),
             libc_prefix,
             single_threaded_txt,
             backend_txt,
         }));
         these_tests.single_threaded = test_target.single_threaded;
         these_tests.setFilter(test_filter);
-        these_tests.setBuildMode(test_target.mode);
-        these_tests.setTarget(test_target.target);
         if (test_target.link_libc) {
             these_tests.linkSystemLibrary("c");
         }
@@ -739,9 +746,9 @@ pub const StackTracesContext = struct {
     step: *build.Step,
     test_index: usize,
     test_filter: ?[]const u8,
-    modes: []const Mode,
+    optimize_modes: []const OptimizeMode,
 
-    const Expect = [@typeInfo(Mode).Enum.fields.len][]const u8;
+    const Expect = [@typeInfo(OptimizeMode).Enum.fields.len][]const u8;
 
     pub fn addCase(self: *StackTracesContext, config: anytype) void {
         if (@hasField(@TypeOf(config), "exclude")) {
@@ -755,26 +762,26 @@ pub const StackTracesContext = struct {
             const exclude_os: []const std.Target.Os.Tag = &config.exclude_os;
             for (exclude_os) |os| if (os == builtin.os.tag) return;
         }
-        for (self.modes) |mode| {
-            switch (mode) {
+        for (self.optimize_modes) |optimize_mode| {
+            switch (optimize_mode) {
                 .Debug => {
                     if (@hasField(@TypeOf(config), "Debug")) {
-                        self.addExpect(config.name, config.source, mode, config.Debug);
+                        self.addExpect(config.name, config.source, optimize_mode, config.Debug);
                     }
                 },
                 .ReleaseSafe => {
                     if (@hasField(@TypeOf(config), "ReleaseSafe")) {
-                        self.addExpect(config.name, config.source, mode, config.ReleaseSafe);
+                        self.addExpect(config.name, config.source, optimize_mode, config.ReleaseSafe);
                     }
                 },
                 .ReleaseFast => {
                     if (@hasField(@TypeOf(config), "ReleaseFast")) {
-                        self.addExpect(config.name, config.source, mode, config.ReleaseFast);
+                        self.addExpect(config.name, config.source, optimize_mode, config.ReleaseFast);
                     }
                 },
                 .ReleaseSmall => {
                     if (@hasField(@TypeOf(config), "ReleaseSmall")) {
-                        self.addExpect(config.name, config.source, mode, config.ReleaseSmall);
+                        self.addExpect(config.name, config.source, optimize_mode, config.ReleaseSmall);
                     }
                 },
             }
@@ -785,7 +792,7 @@ pub const StackTracesContext = struct {
         self: *StackTracesContext,
         name: []const u8,
         source: []const u8,
-        mode: Mode,
+        optimize_mode: OptimizeMode,
         mode_config: anytype,
     ) void {
         if (@hasField(@TypeOf(mode_config), "exclude")) {
@@ -803,7 +810,7 @@ pub const StackTracesContext = struct {
         const annotated_case_name = fmt.allocPrint(self.b.allocator, "{s} {s} ({s})", .{
             "stack-trace",
             name,
-            @tagName(mode),
+            @tagName(optimize_mode),
         }) catch unreachable;
         if (self.test_filter) |filter| {
             if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
@@ -812,14 +819,18 @@ pub const StackTracesContext = struct {
         const b = self.b;
         const src_basename = "source.zig";
         const write_src = b.addWriteFile(src_basename, source);
-        const exe = b.addExecutableSource("test", write_src.getFileSource(src_basename).?);
-        exe.setBuildMode(mode);
+        const exe = b.addExecutable(.{
+            .name = "test",
+            .root_source_file = write_src.getFileSource(src_basename).?,
+            .optimize = optimize_mode,
+            .target = .{},
+        });
 
         const run_and_compare = RunAndCompareStep.create(
             self,
             exe,
             annotated_case_name,
-            mode,
+            optimize_mode,
             mode_config.expect,
         );
 
@@ -833,7 +844,7 @@ pub const StackTracesContext = struct {
         context: *StackTracesContext,
         exe: *LibExeObjStep,
         name: []const u8,
-        mode: Mode,
+        optimize_mode: OptimizeMode,
         expect_output: []const u8,
         test_index: usize,
 
@@ -841,7 +852,7 @@ pub const StackTracesContext = struct {
             context: *StackTracesContext,
             exe: *LibExeObjStep,
             name: []const u8,
-            mode: Mode,
+            optimize_mode: OptimizeMode,
             expect_output: []const u8,
         ) *RunAndCompareStep {
             const allocator = context.b.allocator;
@@ -851,7 +862,7 @@ pub const StackTracesContext = struct {
                 .context = context,
                 .exe = exe,
                 .name = name,
-                .mode = mode,
+                .optimize_mode = optimize_mode,
                 .expect_output = expect_output,
                 .test_index = context.test_index,
             };
@@ -932,7 +943,7 @@ pub const StackTracesContext = struct {
             // process result
             // - keep only basename of source file path
             // - replace address with symbolic string
-            // - replace function name with symbolic string when mode != .Debug
+            // - replace function name with symbolic string when optimize_mode != .Debug
             // - skip empty lines
             const got: []const u8 = got_result: {
                 var buf = ArrayList(u8).init(b.allocator);
@@ -968,7 +979,7 @@ pub const StackTracesContext = struct {
                     // emit substituted line
                     try buf.appendSlice(line[pos + 1 .. marks[2] + delims[2].len]);
                     try buf.appendSlice(" [address]");
-                    if (self.mode == .Debug) {
+                    if (self.optimize_mode == .Debug) {
                         // On certain platforms (windows) or possibly depending on how we choose to link main
                         // the object file extension may be present so we simply strip any extension.
                         if (mem.indexOfScalar(u8, line[marks[4]..marks[5]], '.')) |idot| {
@@ -1007,7 +1018,7 @@ pub const StandaloneContext = struct {
     step: *build.Step,
     test_index: usize,
     test_filter: ?[]const u8,
-    modes: []const Mode,
+    optimize_modes: []const OptimizeMode,
     skip_non_native: bool,
     enable_macos_sdk: bool,
     target: std.zig.CrossTarget,
@@ -1087,13 +1098,13 @@ pub const StandaloneContext = struct {
             }
         }
 
-        const modes = if (features.build_modes) self.modes else &[1]Mode{.Debug};
-        for (modes) |mode| {
-            const arg = switch (mode) {
+        const optimize_modes = if (features.build_modes) self.optimize_modes else &[1]OptimizeMode{.Debug};
+        for (optimize_modes) |optimize_mode| {
+            const arg = switch (optimize_mode) {
                 .Debug => "",
-                .ReleaseFast => "-Drelease-fast",
-                .ReleaseSafe => "-Drelease-safe",
-                .ReleaseSmall => "-Drelease-small",
+                .ReleaseFast => "-Doptimize=ReleaseFast",
+                .ReleaseSafe => "-Doptimize=ReleaseSafe",
+                .ReleaseSmall => "-Doptimize=ReleaseSmall",
             };
             const zig_args_base_len = zig_args.items.len;
             if (arg.len > 0)
@@ -1101,7 +1112,7 @@ pub const StandaloneContext = struct {
             defer zig_args.resize(zig_args_base_len) catch unreachable;
 
             const run_cmd = b.addSystemCommand(zig_args.items);
-            const log_step = b.addLog("PASS {s} ({s})", .{ annotated_case_name, @tagName(mode) });
+            const log_step = b.addLog("PASS {s} ({s})", .{ annotated_case_name, @tagName(optimize_mode) });
             log_step.step.dependOn(&run_cmd.step);
 
             self.step.dependOn(&log_step.step);
@@ -1111,17 +1122,21 @@ pub const StandaloneContext = struct {
     pub fn addAllArgs(self: *StandaloneContext, root_src: []const u8, link_libc: bool) void {
         const b = self.b;
 
-        for (self.modes) |mode| {
+        for (self.optimize_modes) |optimize| {
             const annotated_case_name = fmt.allocPrint(self.b.allocator, "build {s} ({s})", .{
                 root_src,
-                @tagName(mode),
+                @tagName(optimize),
             }) catch unreachable;
             if (self.test_filter) |filter| {
                 if (mem.indexOf(u8, annotated_case_name, filter) == null) continue;
             }
 
-            const exe = b.addExecutable("test", root_src);
-            exe.setBuildMode(mode);
+            const exe = b.addExecutable(.{
+                .name = "test",
+                .root_source_file = .{ .path = root_src },
+                .optimize = optimize,
+                .target = .{},
+            });
             if (link_libc) {
                 exe.linkSystemLibrary("c");
             }
@@ -1247,8 +1262,8 @@ pub const GenHContext = struct {
     pub fn addCase(self: *GenHContext, case: *const TestCase) void {
         const b = self.b;
 
-        const mode = std.builtin.Mode.Debug;
-        const annotated_case_name = fmt.allocPrint(self.b.allocator, "gen-h {s} ({s})", .{ case.name, @tagName(mode) }) catch unreachable;
+        const optimize_mode = std.builtin.OptimizeMode.Debug;
+        const annotated_case_name = fmt.allocPrint(self.b.allocator, "gen-h {s} ({s})", .{ case.name, @tagName(optimize_mode) }) catch unreachable;
         if (self.test_filter) |filter| {
             if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
         }
@@ -1259,7 +1274,7 @@ pub const GenHContext = struct {
         }
 
         const obj = b.addObjectFromWriteFileStep("test", write_src, case.sources.items[0].filename);
-        obj.setBuildMode(mode);
+        obj.setBuildMode(optimize_mode);
 
         const cmp_h = GenHCmpOutputStep.create(self, obj, annotated_case_name, case);
 
@@ -1336,14 +1351,16 @@ const c_abi_targets = [_]CrossTarget{
 pub fn addCAbiTests(b: *build.Builder, skip_non_native: bool, skip_release: bool) *build.Step {
     const step = b.step("test-c-abi", "Run the C ABI tests");
 
-    const modes: [2]Mode = .{ .Debug, .ReleaseFast };
+    const optimize_modes: [2]OptimizeMode = .{ .Debug, .ReleaseFast };
 
-    for (modes[0 .. @as(u8, 1) + @boolToInt(!skip_release)]) |mode| for (c_abi_targets) |c_abi_target| {
+    for (optimize_modes[0 .. @as(u8, 1) + @boolToInt(!skip_release)]) |optimize_mode| for (c_abi_targets) |c_abi_target| {
         if (skip_non_native and !c_abi_target.isNative())
             continue;
 
-        const test_step = b.addTest("test/c_abi/main.zig");
-        test_step.setTarget(c_abi_target);
+        const test_step = b.addTest(.{
+            .root_source_file = .{ .path = "test/c_abi/main.zig" },
+            .optimize = optimize_mode,
+        });
         if (c_abi_target.abi != null and c_abi_target.abi.?.isMusl()) {
             // TODO NativeTargetInfo insists on dynamically linking musl
             // for some reason?
@@ -1351,7 +1368,6 @@ pub fn addCAbiTests(b: *build.Builder, skip_non_native: bool, skip_release: bool
         }
         test_step.linkLibC();
         test_step.addCSourceFile("test/c_abi/cfuncs.c", &.{"-std=c99"});
-        test_step.setBuildMode(mode);
 
         if (c_abi_target.isWindows() and (c_abi_target.getCpuArch() == .x86 or builtin.target.os.tag == .linux)) {
             // LTO currently incorrectly strips stdcall name-mangled functions
@@ -1363,7 +1379,7 @@ pub fn addCAbiTests(b: *build.Builder, skip_non_native: bool, skip_release: bool
         test_step.setNamePrefix(b.fmt("{s}-{s}-{s} ", .{
             "test-c-abi",
             triple_prefix,
-            @tagName(mode),
+            @tagName(optimize_mode),
         }));
 
         step.dependOn(&test_step.step);
build.zig
@@ -23,7 +23,7 @@ pub fn build(b: *Builder) !void {
         }
         break :t b.standardTargetOptions(.{ .default_target = default_target });
     };
-    const mode: std.builtin.Mode = if (release) switch (target.getCpuArch()) {
+    const optimize: std.builtin.OptimizeMode = if (release) switch (target.getCpuArch()) {
         .wasm32 => .ReleaseSmall,
         else => .ReleaseFast,
     } else .Debug;
@@ -33,7 +33,12 @@ pub fn build(b: *Builder) !void {
 
     const test_step = b.step("test", "Run all the tests");
 
-    const docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
+    const docgen_exe = b.addExecutable(.{
+        .name = "docgen",
+        .root_source_file = .{ .path = "doc/docgen.zig" },
+        .target = .{},
+        .optimize = .Debug,
+    });
     docgen_exe.single_threaded = single_threaded;
 
     const rel_zig_exe = try fs.path.relative(b.allocator, b.build_root, b.zig_exe);
@@ -53,10 +58,12 @@ pub fn build(b: *Builder) !void {
     const docs_step = b.step("docs", "Build documentation");
     docs_step.dependOn(&docgen_cmd.step);
 
-    const test_cases = b.addTest("src/test.zig");
+    const test_cases = b.addTest(.{
+        .root_source_file = .{ .path = "src/test.zig" },
+        .optimize = optimize,
+    });
     test_cases.main_pkg_path = ".";
     test_cases.stack_size = stack_size;
-    test_cases.setBuildMode(mode);
     test_cases.single_threaded = single_threaded;
 
     const fmt_build_zig = b.addFmt(&[_][]const u8{"build.zig"});
@@ -149,17 +156,15 @@ pub fn build(b: *Builder) !void {
 
     const mem_leak_frames: u32 = b.option(u32, "mem-leak-frames", "How many stack frames to print when a memory leak occurs. Tests get 2x this amount.") orelse blk: {
         if (strip == true) break :blk @as(u32, 0);
-        if (mode != .Debug) break :blk 0;
+        if (optimize != .Debug) break :blk 0;
         break :blk 4;
     };
 
-    const exe = addCompilerStep(b);
+    const exe = addCompilerStep(b, optimize, target);
     exe.strip = strip;
     exe.sanitize_thread = sanitize_thread;
     exe.build_id = b.option(bool, "build-id", "Include a build id note") orelse false;
     exe.install();
-    exe.setBuildMode(mode);
-    exe.setTarget(target);
 
     const compile_step = b.step("compile", "Build the self-hosted compiler");
     compile_step.dependOn(&exe.step);
@@ -195,7 +200,7 @@ pub fn build(b: *Builder) !void {
         test_cases.linkLibC();
     }
 
-    const is_debug = mode == .Debug;
+    const is_debug = optimize == .Debug;
     const enable_logging = b.option(bool, "log", "Enable debug logging with --debug-log") orelse is_debug;
     const enable_link_snapshots = b.option(bool, "link-snapshot", "Whether to enable linker state snapshots") orelse false;
 
@@ -360,25 +365,25 @@ pub fn build(b: *Builder) !void {
         test_step.dependOn(test_cases_step);
     }
 
-    var chosen_modes: [4]builtin.Mode = undefined;
+    var chosen_opt_modes_buf: [4]builtin.Mode = undefined;
     var chosen_mode_index: usize = 0;
     if (!skip_debug) {
-        chosen_modes[chosen_mode_index] = builtin.Mode.Debug;
+        chosen_opt_modes_buf[chosen_mode_index] = builtin.Mode.Debug;
         chosen_mode_index += 1;
     }
     if (!skip_release_safe) {
-        chosen_modes[chosen_mode_index] = builtin.Mode.ReleaseSafe;
+        chosen_opt_modes_buf[chosen_mode_index] = builtin.Mode.ReleaseSafe;
         chosen_mode_index += 1;
     }
     if (!skip_release_fast) {
-        chosen_modes[chosen_mode_index] = builtin.Mode.ReleaseFast;
+        chosen_opt_modes_buf[chosen_mode_index] = builtin.Mode.ReleaseFast;
         chosen_mode_index += 1;
     }
     if (!skip_release_small) {
-        chosen_modes[chosen_mode_index] = builtin.Mode.ReleaseSmall;
+        chosen_opt_modes_buf[chosen_mode_index] = builtin.Mode.ReleaseSmall;
         chosen_mode_index += 1;
     }
-    const modes = chosen_modes[0..chosen_mode_index];
+    const optimization_modes = chosen_opt_modes_buf[0..chosen_mode_index];
 
     // run stage1 `zig fmt` on this build.zig file just to make sure it works
     test_step.dependOn(&fmt_build_zig.step);
@@ -391,7 +396,7 @@ pub fn build(b: *Builder) !void {
         "test/behavior.zig",
         "behavior",
         "Run the behavior tests",
-        modes,
+        optimization_modes,
         skip_single_threaded,
         skip_non_native,
         skip_libc,
@@ -405,7 +410,7 @@ pub fn build(b: *Builder) !void {
         "lib/compiler_rt.zig",
         "compiler-rt",
         "Run the compiler_rt tests",
-        modes,
+        optimization_modes,
         true, // skip_single_threaded
         skip_non_native,
         true, // skip_libc
@@ -419,7 +424,7 @@ pub fn build(b: *Builder) !void {
         "lib/c.zig",
         "universal-libc",
         "Run the universal libc tests",
-        modes,
+        optimization_modes,
         true, // skip_single_threaded
         skip_non_native,
         true, // skip_libc
@@ -427,11 +432,11 @@ pub fn build(b: *Builder) !void {
         skip_stage2_tests or true, // TODO get these all passing
     ));
 
-    test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes));
+    test_step.dependOn(tests.addCompareOutputTests(b, test_filter, optimization_modes));
     test_step.dependOn(tests.addStandaloneTests(
         b,
         test_filter,
-        modes,
+        optimization_modes,
         skip_non_native,
         enable_macos_sdk,
         target,
@@ -444,10 +449,10 @@ pub fn build(b: *Builder) !void {
         enable_symlinks_windows,
     ));
     test_step.dependOn(tests.addCAbiTests(b, skip_non_native, skip_release));
-    test_step.dependOn(tests.addLinkTests(b, test_filter, modes, enable_macos_sdk, skip_stage2_tests, enable_symlinks_windows));
-    test_step.dependOn(tests.addStackTraceTests(b, test_filter, modes));
-    test_step.dependOn(tests.addCliTests(b, test_filter, modes));
-    test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes));
+    test_step.dependOn(tests.addLinkTests(b, test_filter, optimization_modes, enable_macos_sdk, skip_stage2_tests, enable_symlinks_windows));
+    test_step.dependOn(tests.addStackTraceTests(b, test_filter, optimization_modes));
+    test_step.dependOn(tests.addCliTests(b, test_filter, optimization_modes));
+    test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, optimization_modes));
     test_step.dependOn(tests.addTranslateCTests(b, test_filter));
     if (!skip_run_translated_c) {
         test_step.dependOn(tests.addRunTranslatedCTests(b, test_filter, target));
@@ -461,7 +466,7 @@ pub fn build(b: *Builder) !void {
         "lib/std/std.zig",
         "std",
         "Run the standard library tests",
-        modes,
+        optimization_modes,
         skip_single_threaded,
         skip_non_native,
         skip_libc,
@@ -481,9 +486,7 @@ fn addWasiUpdateStep(b: *Builder, version: [:0]const u8) !void {
     };
     target.cpu_features_add.addFeature(@enumToInt(std.Target.wasm.Feature.bulk_memory));
 
-    const exe = addCompilerStep(b);
-    exe.setBuildMode(.ReleaseSmall);
-    exe.setTarget(target);
+    const exe = addCompilerStep(b, .ReleaseSmall, target);
 
     const exe_options = b.addOptions();
     exe.addOptions("build_options", exe_options);
@@ -510,8 +513,17 @@ fn addWasiUpdateStep(b: *Builder, version: [:0]const u8) !void {
     update_zig1_step.dependOn(&run_opt.step);
 }
 
-fn addCompilerStep(b: *Builder) *std.build.LibExeObjStep {
-    const exe = b.addExecutable("zig", "src/main.zig");
+fn addCompilerStep(
+    b: *Builder,
+    optimize: std.builtin.OptimizeMode,
+    target: std.zig.CrossTarget,
+) *std.build.LibExeObjStep {
+    const exe = b.addExecutable(.{
+        .name = "zig",
+        .root_source_file = .{ .path = "src/main.zig" },
+        .target = target,
+        .optimize = optimize,
+    });
     exe.stack_size = stack_size;
     return exe;
 }