Commit 36e2d992dd

Andrew Kelley <andrew@ziglang.org>
2023-01-31 08:19:51
combine std.build and std.build.Builder into std.Build
I've been wanting to do this for along time.
1 parent 73cf7b6
Changed files (97)
doc
lib
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
@@ -9528,9 +9528,9 @@ fn foo(comptime T: type, ptr: *T) T {
       To add standard build options to a <code class="file">build.zig</code> file:
       </p>
       {#code_begin|syntax|build#}
-const Builder = @import("std").build.Builder;
+const std = @import("std");
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
     const exe = b.addExecutable(.{
         .name = "example",
@@ -10551,9 +10551,9 @@ const separator = if (builtin.os.tag == .windows) '\\' else '/';
       <p>This <code class="file">build.zig</code> file is automatically generated
         by <kbd>zig init-exe</kbd>.</p>
       {#code_begin|syntax|build_executable#}
-const Builder = @import("std").build.Builder;
+const std = @import("std");
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) 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
     // means any target is allowed, and the default is native. Other options
@@ -10588,9 +10588,9 @@ pub fn build(b: *Builder) void {
       <p>This <code class="file">build.zig</code> file is automatically generated
         by <kbd>zig init-lib</kbd>.</p>
       {#code_begin|syntax|build_library#}
-const Builder = @import("std").build.Builder;
+const std = @import("std");
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
     const lib = b.addStaticLibrary(.{
         .name = "example",
@@ -10961,9 +10961,9 @@ int main(int argc, char **argv) {
 }
       {#end_syntax_block#}
       {#code_begin|syntax|build_c#}
-const Builder = @import("std").build.Builder;
+const std = @import("std");
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));
 
     const exe = b.addExecutable(.{
@@ -11025,9 +11025,9 @@ int main(int argc, char **argv) {
 }
       {#end_syntax_block#}
       {#code_begin|syntax|build_object#}
-const Builder = @import("std").build.Builder;
+const std = @import("std");
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const obj = b.addObject("base64", "base64.zig");
 
     const exe = b.addExecutable(.{
lib/init-exe/build.zig
@@ -3,7 +3,7 @@ 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 {
+pub fn build(b: *std.Build) 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
     // means any target is allowed, and the default is native. Other options
lib/init-lib/build.zig
@@ -3,7 +3,7 @@ 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 {
+pub fn build(b: *std.Build) 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
     // means any target is allowed, and the default is native. Other options
lib/std/build/CheckFileStep.zig โ†’ lib/std/Build/CheckFileStep.zig
@@ -1,7 +1,5 @@
 const std = @import("../std.zig");
-const build = std.build;
-const Step = build.Step;
-const Builder = build.Builder;
+const Step = std.Build.Step;
 const fs = std.fs;
 const mem = std.mem;
 
@@ -10,14 +8,14 @@ const CheckFileStep = @This();
 pub const base_id = .check_file;
 
 step: Step,
-builder: *Builder,
+builder: *std.Build,
 expected_matches: []const []const u8,
-source: build.FileSource,
+source: std.Build.FileSource,
 max_bytes: usize = 20 * 1024 * 1024,
 
 pub fn create(
-    builder: *Builder,
-    source: build.FileSource,
+    builder: *std.Build,
+    source: std.Build.FileSource,
     expected_matches: []const []const u8,
 ) *CheckFileStep {
     const self = builder.allocator.create(CheckFileStep) catch unreachable;
lib/std/build/CheckObjectStep.zig โ†’ lib/std/Build/CheckObjectStep.zig
@@ -1,6 +1,5 @@
 const std = @import("../std.zig");
 const assert = std.debug.assert;
-const build = std.build;
 const fs = std.fs;
 const macho = std.macho;
 const math = std.math;
@@ -10,21 +9,20 @@ const testing = std.testing;
 const CheckObjectStep = @This();
 
 const Allocator = mem.Allocator;
-const Builder = build.Builder;
-const Step = build.Step;
-const EmulatableRunStep = build.EmulatableRunStep;
+const Step = std.Build.Step;
+const EmulatableRunStep = std.Build.EmulatableRunStep;
 
 pub const base_id = .check_object;
 
 step: Step,
-builder: *Builder,
-source: build.FileSource,
+builder: *std.Build,
+source: std.Build.FileSource,
 max_bytes: usize = 20 * 1024 * 1024,
 checks: std.ArrayList(Check),
 dump_symtab: bool = false,
 obj_format: std.Target.ObjectFormat,
 
-pub fn create(builder: *Builder, source: build.FileSource, obj_format: std.Target.ObjectFormat) *CheckObjectStep {
+pub fn create(builder: *std.Build, source: std.Build.FileSource, obj_format: std.Target.ObjectFormat) *CheckObjectStep {
     const gpa = builder.allocator;
     const self = gpa.create(CheckObjectStep) catch unreachable;
     self.* = .{
@@ -44,7 +42,7 @@ pub fn runAndCompare(self: *CheckObjectStep) *EmulatableRunStep {
     const dependencies_len = self.step.dependencies.items.len;
     assert(dependencies_len > 0);
     const exe_step = self.step.dependencies.items[dependencies_len - 1];
-    const exe = exe_step.cast(std.build.LibExeObjStep).?;
+    const exe = exe_step.cast(std.Build.LibExeObjStep).?;
     const emulatable_step = EmulatableRunStep.create(self.builder, "EmulatableRun", exe);
     emulatable_step.step.dependOn(&self.step);
     return emulatable_step;
@@ -216,10 +214,10 @@ const ComputeCompareExpected = struct {
 };
 
 const Check = struct {
-    builder: *Builder,
+    builder: *std.Build,
     actions: std.ArrayList(Action),
 
-    fn create(b: *Builder) Check {
+    fn create(b: *std.Build) Check {
         return .{
             .builder = b,
             .actions = std.ArrayList(Action).init(b.allocator),
lib/std/build/ConfigHeaderStep.zig โ†’ lib/std/Build/ConfigHeaderStep.zig
@@ -1,7 +1,6 @@
 const std = @import("../std.zig");
 const ConfigHeaderStep = @This();
-const Step = std.build.Step;
-const Builder = std.build.Builder;
+const Step = std.Build.Step;
 
 pub const base_id: Step.Id = .config_header;
 
@@ -24,15 +23,15 @@ pub const Value = union(enum) {
 };
 
 step: Step,
-builder: *Builder,
-source: std.build.FileSource,
+builder: *std.Build,
+source: std.Build.FileSource,
 style: Style,
 values: std.StringHashMap(Value),
 max_bytes: usize = 2 * 1024 * 1024,
 output_dir: []const u8,
 output_basename: []const u8,
 
-pub fn create(builder: *Builder, source: std.build.FileSource, style: Style) *ConfigHeaderStep {
+pub fn create(builder: *std.Build, source: std.Build.FileSource, style: Style) *ConfigHeaderStep {
     const self = builder.allocator.create(ConfigHeaderStep) catch @panic("OOM");
     const name = builder.fmt("configure header {s}", .{source.getDisplayName()});
     self.* = .{
lib/std/build/EmulatableRunStep.zig โ†’ lib/std/Build/EmulatableRunStep.zig
@@ -5,11 +5,9 @@
 //! without having to verify if it's possible to be ran against.
 
 const std = @import("../std.zig");
-const build = std.build;
-const Step = std.build.Step;
-const Builder = std.build.Builder;
-const LibExeObjStep = std.build.LibExeObjStep;
-const RunStep = std.build.RunStep;
+const Step = std.Build.Step;
+const LibExeObjStep = std.Build.LibExeObjStep;
+const RunStep = std.Build.RunStep;
 
 const fs = std.fs;
 const process = std.process;
@@ -22,7 +20,7 @@ pub const base_id = .emulatable_run;
 const max_stdout_size = 1 * 1024 * 1024; // 1 MiB
 
 step: Step,
-builder: *Builder,
+builder: *std.Build,
 
 /// The artifact (executable) to be run by this step
 exe: *LibExeObjStep,
@@ -47,7 +45,7 @@ hide_foreign_binaries_warning: bool,
 /// binary through emulation when any of the emulation options such as `enable_rosetta` are set to true.
 /// When set to false, and the binary is foreign, running the executable is skipped.
 /// Asserts given artifact is an executable.
-pub fn create(builder: *Builder, name: []const u8, artifact: *LibExeObjStep) *EmulatableRunStep {
+pub fn create(builder: *std.Build, name: []const u8, artifact: *LibExeObjStep) *EmulatableRunStep {
     std.debug.assert(artifact.kind == .exe or artifact.kind == .test_exe);
     const self = builder.allocator.create(EmulatableRunStep) catch unreachable;
 
lib/std/build/FmtStep.zig โ†’ lib/std/Build/FmtStep.zig
@@ -1,19 +1,14 @@
 const std = @import("../std.zig");
-const build = @import("../build.zig");
-const Step = build.Step;
-const Builder = build.Builder;
-const BufMap = std.BufMap;
-const mem = std.mem;
-
+const Step = std.Build.Step;
 const FmtStep = @This();
 
 pub const base_id = .fmt;
 
 step: Step,
-builder: *Builder,
+builder: *std.Build,
 argv: [][]const u8,
 
-pub fn create(builder: *Builder, paths: []const []const u8) *FmtStep {
+pub fn create(builder: *std.Build, paths: []const []const u8) *FmtStep {
     const self = builder.allocator.create(FmtStep) catch unreachable;
     const name = "zig fmt";
     self.* = FmtStep{
lib/std/build/InstallArtifactStep.zig โ†’ lib/std/Build/InstallArtifactStep.zig
@@ -1,26 +1,23 @@
 const std = @import("../std.zig");
-const build = @import("../build.zig");
-const Step = build.Step;
-const Builder = build.Builder;
-const LibExeObjStep = std.build.LibExeObjStep;
-const InstallDir = std.build.InstallDir;
+const Step = std.Build.Step;
+const LibExeObjStep = std.Build.LibExeObjStep;
+const InstallDir = std.Build.InstallDir;
+const InstallArtifactStep = @This();
 
 pub const base_id = .install_artifact;
 
 step: Step,
-builder: *Builder,
+builder: *std.Build,
 artifact: *LibExeObjStep,
 dest_dir: InstallDir,
 pdb_dir: ?InstallDir,
 h_dir: ?InstallDir,
 
-const Self = @This();
-
-pub fn create(builder: *Builder, artifact: *LibExeObjStep) *Self {
+pub fn create(builder: *std.Build, artifact: *LibExeObjStep) *InstallArtifactStep {
     if (artifact.install_step) |s| return s;
 
-    const self = builder.allocator.create(Self) catch unreachable;
-    self.* = Self{
+    const self = builder.allocator.create(InstallArtifactStep) catch unreachable;
+    self.* = InstallArtifactStep{
         .builder = builder,
         .step = Step.init(.install_artifact, builder.fmt("install {s}", .{artifact.step.name}), builder.allocator, make),
         .artifact = artifact,
@@ -64,7 +61,7 @@ pub fn create(builder: *Builder, artifact: *LibExeObjStep) *Self {
 }
 
 fn make(step: *Step) !void {
-    const self = @fieldParentPtr(Self, "step", step);
+    const self = @fieldParentPtr(InstallArtifactStep, "step", step);
     const builder = self.builder;
 
     const full_dest_path = builder.getInstallPath(self.dest_dir, self.artifact.out_filename);
lib/std/build/InstallDirStep.zig โ†’ lib/std/Build/InstallDirStep.zig
@@ -1,19 +1,17 @@
 const std = @import("../std.zig");
 const mem = std.mem;
 const fs = std.fs;
-const build = @import("../build.zig");
-const Step = build.Step;
-const Builder = build.Builder;
-const InstallDir = std.build.InstallDir;
+const Step = std.Build.Step;
+const InstallDir = std.Build.InstallDir;
 const InstallDirStep = @This();
 const log = std.log;
 
 step: Step,
-builder: *Builder,
+builder: *std.Build,
 options: Options,
 /// This is used by the build system when a file being installed comes from one
 /// package but is being installed by another.
-override_source_builder: ?*Builder = null,
+override_source_builder: ?*std.Build = null,
 
 pub const base_id = .install_dir;
 
@@ -31,7 +29,7 @@ pub const Options = struct {
     /// `@import("test.zig")` would be a compile error.
     blank_extensions: []const []const u8 = &.{},
 
-    fn dupe(self: Options, b: *Builder) Options {
+    fn dupe(self: Options, b: *std.Build) Options {
         return .{
             .source_dir = b.dupe(self.source_dir),
             .install_dir = self.install_dir.dupe(b),
@@ -43,7 +41,7 @@ pub const Options = struct {
 };
 
 pub fn init(
-    builder: *Builder,
+    builder: *std.Build,
     options: Options,
 ) InstallDirStep {
     builder.pushInstalledFile(options.install_dir, options.install_subdir);
lib/std/build/InstallFileStep.zig โ†’ lib/std/Build/InstallFileStep.zig
@@ -1,24 +1,22 @@
 const std = @import("../std.zig");
-const build = @import("../build.zig");
-const Step = build.Step;
-const Builder = build.Builder;
-const FileSource = std.build.FileSource;
-const InstallDir = std.build.InstallDir;
+const Step = std.Build.Step;
+const FileSource = std.Build.FileSource;
+const InstallDir = std.Build.InstallDir;
 const InstallFileStep = @This();
 
 pub const base_id = .install_file;
 
 step: Step,
-builder: *Builder,
+builder: *std.Build,
 source: FileSource,
 dir: InstallDir,
 dest_rel_path: []const u8,
 /// This is used by the build system when a file being installed comes from one
 /// package but is being installed by another.
-override_source_builder: ?*Builder = null,
+override_source_builder: ?*std.Build = null,
 
 pub fn init(
-    builder: *Builder,
+    builder: *std.Build,
     source: FileSource,
     dir: InstallDir,
     dest_rel_path: []const u8,
lib/std/build/InstallRawStep.zig โ†’ lib/std/Build/InstallRawStep.zig
@@ -7,11 +7,10 @@ const InstallRawStep = @This();
 const Allocator = std.mem.Allocator;
 const ArenaAllocator = std.heap.ArenaAllocator;
 const ArrayListUnmanaged = std.ArrayListUnmanaged;
-const Builder = std.build.Builder;
 const File = std.fs.File;
-const InstallDir = std.build.InstallDir;
-const LibExeObjStep = std.build.LibExeObjStep;
-const Step = std.build.Step;
+const InstallDir = std.Build.InstallDir;
+const LibExeObjStep = std.Build.LibExeObjStep;
+const Step = std.Build.Step;
 const elf = std.elf;
 const fs = std.fs;
 const io = std.io;
@@ -25,12 +24,12 @@ pub const RawFormat = enum {
 };
 
 step: Step,
-builder: *Builder,
+builder: *std.Build,
 artifact: *LibExeObjStep,
 dest_dir: InstallDir,
 dest_filename: []const u8,
 options: CreateOptions,
-output_file: std.build.GeneratedFile,
+output_file: std.Build.GeneratedFile,
 
 pub const CreateOptions = struct {
     format: ?RawFormat = null,
@@ -39,7 +38,12 @@ pub const CreateOptions = struct {
     pad_to: ?u64 = null,
 };
 
-pub fn create(builder: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8, options: CreateOptions) *InstallRawStep {
+pub fn create(
+    builder: *std.Build,
+    artifact: *LibExeObjStep,
+    dest_filename: []const u8,
+    options: CreateOptions,
+) *InstallRawStep {
     const self = builder.allocator.create(InstallRawStep) catch unreachable;
     self.* = InstallRawStep{
         .step = Step.init(.install_raw, builder.fmt("install raw binary {s}", .{artifact.step.name}), builder.allocator, make),
@@ -53,7 +57,7 @@ pub fn create(builder: *Builder, artifact: *LibExeObjStep, dest_filename: []cons
         },
         .dest_filename = dest_filename,
         .options = options,
-        .output_file = std.build.GeneratedFile{ .step = &self.step },
+        .output_file = std.Build.GeneratedFile{ .step = &self.step },
     };
     self.step.dependOn(&artifact.step);
 
@@ -61,8 +65,8 @@ pub fn create(builder: *Builder, artifact: *LibExeObjStep, dest_filename: []cons
     return self;
 }
 
-pub fn getOutputSource(self: *const InstallRawStep) std.build.FileSource {
-    return std.build.FileSource{ .generated = &self.output_file };
+pub fn getOutputSource(self: *const InstallRawStep) std.Build.FileSource {
+    return std.Build.FileSource{ .generated = &self.output_file };
 }
 
 fn make(step: *Step) !void {
lib/std/build/LibExeObjStep.zig โ†’ lib/std/Build/LibExeObjStep.zig
@@ -9,32 +9,30 @@ const ArrayList = std.ArrayList;
 const StringHashMap = std.StringHashMap;
 const Sha256 = std.crypto.hash.sha2.Sha256;
 const Allocator = mem.Allocator;
-const build = @import("../build.zig");
-const Step = build.Step;
-const Builder = build.Builder;
+const Step = std.Build.Step;
 const CrossTarget = std.zig.CrossTarget;
 const NativeTargetInfo = std.zig.system.NativeTargetInfo;
-const FileSource = std.build.FileSource;
-const PkgConfigPkg = Builder.PkgConfigPkg;
-const PkgConfigError = Builder.PkgConfigError;
-const ExecError = Builder.ExecError;
-const Pkg = std.build.Pkg;
-const VcpkgRoot = std.build.VcpkgRoot;
-const InstallDir = std.build.InstallDir;
-const InstallArtifactStep = std.build.InstallArtifactStep;
-const GeneratedFile = std.build.GeneratedFile;
-const InstallRawStep = std.build.InstallRawStep;
-const EmulatableRunStep = std.build.EmulatableRunStep;
-const CheckObjectStep = std.build.CheckObjectStep;
-const RunStep = std.build.RunStep;
-const OptionsStep = std.build.OptionsStep;
-const ConfigHeaderStep = std.build.ConfigHeaderStep;
+const FileSource = std.Build.FileSource;
+const PkgConfigPkg = std.Build.PkgConfigPkg;
+const PkgConfigError = std.Build.PkgConfigError;
+const ExecError = std.Build.ExecError;
+const Pkg = std.Build.Pkg;
+const VcpkgRoot = std.Build.VcpkgRoot;
+const InstallDir = std.Build.InstallDir;
+const InstallArtifactStep = std.Build.InstallArtifactStep;
+const GeneratedFile = std.Build.GeneratedFile;
+const InstallRawStep = std.Build.InstallRawStep;
+const EmulatableRunStep = std.Build.EmulatableRunStep;
+const CheckObjectStep = std.Build.CheckObjectStep;
+const RunStep = std.Build.RunStep;
+const OptionsStep = std.Build.OptionsStep;
+const ConfigHeaderStep = std.Build.ConfigHeaderStep;
 const LibExeObjStep = @This();
 
 pub const base_id = .lib_exe_obj;
 
 step: Step,
-builder: *Builder,
+builder: *std.Build,
 name: []const u8,
 target: CrossTarget,
 target_info: NativeTargetInfo,
@@ -84,7 +82,7 @@ initial_memory: ?u64 = null,
 max_memory: ?u64 = null,
 shared_memory: bool = false,
 global_base: ?u64 = null,
-c_std: Builder.CStd,
+c_std: std.Build.CStd,
 override_lib_dir: ?[]const u8,
 main_pkg_path: ?[]const u8,
 exec_cmd_args: ?[]const ?[]const u8,
@@ -108,7 +106,7 @@ object_src: []const u8,
 link_objects: ArrayList(LinkObject),
 include_dirs: ArrayList(IncludeDir),
 c_macros: ArrayList([]const u8),
-installed_headers: ArrayList(*std.build.Step),
+installed_headers: ArrayList(*Step),
 output_dir: ?[]const u8,
 is_linking_libc: bool = false,
 is_linking_libcpp: bool = false,
@@ -226,7 +224,7 @@ pub const CSourceFile = struct {
     source: FileSource,
     args: []const []const u8,
 
-    pub fn dupe(self: CSourceFile, b: *Builder) CSourceFile {
+    pub fn dupe(self: CSourceFile, b: *std.Build) CSourceFile {
         return .{
             .source = self.source.dupe(b),
             .args = b.dupeStrings(self.args),
@@ -297,7 +295,7 @@ pub const EmitOption = union(enum) {
     emit: void,
     emit_to: []const u8,
 
-    fn getArg(self: @This(), b: *Builder, arg_name: []const u8) ?[]const u8 {
+    fn getArg(self: @This(), b: *std.Build, arg_name: []const u8) ?[]const u8 {
         return switch (self) {
             .no_emit => b.fmt("-fno-{s}", .{arg_name}),
             .default => null,
@@ -307,7 +305,7 @@ pub const EmitOption = union(enum) {
     }
 };
 
-pub fn create(builder: *Builder, options: Options) *LibExeObjStep {
+pub fn create(builder: *std.Build, options: Options) *LibExeObjStep {
     const name = builder.dupe(options.name);
     const root_src: ?FileSource = if (options.root_source_file) |rsrc| rsrc.dupe(builder) else null;
     if (mem.indexOf(u8, name, "/") != null or mem.indexOf(u8, name, "\\") != null) {
@@ -343,9 +341,9 @@ pub fn create(builder: *Builder, options: Options) *LibExeObjStep {
         .lib_paths = ArrayList([]const u8).init(builder.allocator),
         .rpaths = ArrayList([]const u8).init(builder.allocator),
         .framework_dirs = ArrayList([]const u8).init(builder.allocator),
-        .installed_headers = ArrayList(*std.build.Step).init(builder.allocator),
+        .installed_headers = ArrayList(*Step).init(builder.allocator),
         .object_src = undefined,
-        .c_std = Builder.CStd.C99,
+        .c_std = std.Build.CStd.C99,
         .override_lib_dir = null,
         .main_pkg_path = null,
         .exec_cmd_args = null,
@@ -461,7 +459,7 @@ pub fn installHeadersDirectory(
 
 pub fn installHeadersDirectoryOptions(
     a: *LibExeObjStep,
-    options: std.build.InstallDirStep.Options,
+    options: std.Build.InstallDirStep.Options,
 ) void {
     const install_dir = a.builder.addInstallDirectory(options);
     a.builder.getInstallStep().dependOn(&install_dir.step);
@@ -600,7 +598,7 @@ pub fn linkLibCpp(self: *LibExeObjStep) void {
 /// If the value is omitted, it is set to 1.
 /// `name` and `value` need not live longer than the function call.
 pub fn defineCMacro(self: *LibExeObjStep, name: []const u8, value: ?[]const u8) void {
-    const macro = std.build.constructCMacro(self.builder.allocator, name, value);
+    const macro = std.Build.constructCMacro(self.builder.allocator, name, value);
     self.c_macros.append(macro) catch unreachable;
 }
 
@@ -1460,7 +1458,7 @@ fn make(step: *Step) !void {
     if (!self.target.isNative()) {
         try zig_args.appendSlice(&.{
             "-target", try self.target.zigTriple(builder.allocator),
-            "-mcpu",   try build.serializeCpu(builder.allocator, self.target.getCpu()),
+            "-mcpu",   try std.Build.serializeCpu(builder.allocator, self.target.getCpu()),
         });
 
         if (self.target.dynamic_linker.get()) |dynamic_linker| {
@@ -1902,7 +1900,7 @@ pub fn doAtomicSymLinks(allocator: Allocator, output_path: []const u8, filename_
     };
 }
 
-fn execPkgConfigList(self: *Builder, out_code: *u8) (PkgConfigError || ExecError)![]const PkgConfigPkg {
+fn execPkgConfigList(self: *std.Build, out_code: *u8) (PkgConfigError || ExecError)![]const PkgConfigPkg {
     const stdout = try self.execAllowFail(&[_][]const u8{ "pkg-config", "--list-all" }, out_code, .Ignore);
     var list = ArrayList(PkgConfigPkg).init(self.allocator);
     errdefer list.deinit();
@@ -1918,7 +1916,7 @@ fn execPkgConfigList(self: *Builder, out_code: *u8) (PkgConfigError || ExecError
     return list.toOwnedSlice();
 }
 
-fn getPkgConfigList(self: *Builder) ![]const PkgConfigPkg {
+fn getPkgConfigList(self: *std.Build) ![]const PkgConfigPkg {
     if (self.pkg_config_pkg_list) |res| {
         return res;
     }
@@ -1948,7 +1946,7 @@ test "addPackage" {
     var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
     defer arena.deinit();
 
-    var builder = try Builder.create(
+    var builder = try std.Build.create(
         arena.allocator(),
         "test",
         "test",
lib/std/build/LogStep.zig โ†’ lib/std/Build/LogStep.zig
@@ -1,17 +1,15 @@
 const std = @import("../std.zig");
 const log = std.log;
-const build = @import("../build.zig");
-const Step = build.Step;
-const Builder = build.Builder;
+const Step = std.Build.Step;
 const LogStep = @This();
 
 pub const base_id = .log;
 
 step: Step,
-builder: *Builder,
+builder: *std.Build,
 data: []const u8,
 
-pub fn init(builder: *Builder, data: []const u8) LogStep {
+pub fn init(builder: *std.Build, data: []const u8) LogStep {
     return LogStep{
         .builder = builder,
         .step = Step.init(.log, builder.fmt("log {s}", .{data}), builder.allocator, make),
lib/std/build/OptionsStep.zig โ†’ lib/std/Build/OptionsStep.zig
@@ -1,12 +1,10 @@
 const std = @import("../std.zig");
 const builtin = @import("builtin");
-const build = std.build;
 const fs = std.fs;
-const Step = build.Step;
-const Builder = build.Builder;
-const GeneratedFile = build.GeneratedFile;
-const LibExeObjStep = build.LibExeObjStep;
-const FileSource = build.FileSource;
+const Step = std.Build.Step;
+const GeneratedFile = std.Build.GeneratedFile;
+const LibExeObjStep = std.Build.LibExeObjStep;
+const FileSource = std.Build.FileSource;
 
 const OptionsStep = @This();
 
@@ -14,13 +12,13 @@ pub const base_id = .options;
 
 step: Step,
 generated_file: GeneratedFile,
-builder: *Builder,
+builder: *std.Build,
 
 contents: std.ArrayList(u8),
 artifact_args: std.ArrayList(OptionArtifactArg),
 file_source_args: std.ArrayList(OptionFileSourceArg),
 
-pub fn create(builder: *Builder) *OptionsStep {
+pub fn create(builder: *std.Build) *OptionsStep {
     const self = builder.allocator.create(OptionsStep) catch unreachable;
     self.* = .{
         .builder = builder,
@@ -202,7 +200,7 @@ pub fn addOptionArtifact(self: *OptionsStep, name: []const u8, artifact: *LibExe
     self.step.dependOn(&artifact.step);
 }
 
-pub fn getPackage(self: *OptionsStep, package_name: []const u8) build.Pkg {
+pub fn getPackage(self: *OptionsStep, package_name: []const u8) std.Build.Pkg {
     return .{ .name = package_name, .source = self.getSource() };
 }
 
@@ -281,7 +279,7 @@ test "OptionsStep" {
 
     var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
     defer arena.deinit();
-    var builder = try Builder.create(
+    var builder = try std.Build.create(
         arena.allocator(),
         "test",
         "test",
lib/std/build/RemoveDirStep.zig โ†’ lib/std/Build/RemoveDirStep.zig
@@ -1,18 +1,16 @@
 const std = @import("../std.zig");
 const log = std.log;
 const fs = std.fs;
-const build = @import("../build.zig");
-const Step = build.Step;
-const Builder = build.Builder;
+const Step = std.Build.Step;
 const RemoveDirStep = @This();
 
 pub const base_id = .remove_dir;
 
 step: Step,
-builder: *Builder,
+builder: *std.Build,
 dir_path: []const u8,
 
-pub fn init(builder: *Builder, dir_path: []const u8) RemoveDirStep {
+pub fn init(builder: *std.Build, dir_path: []const u8) RemoveDirStep {
     return RemoveDirStep{
         .builder = builder,
         .step = Step.init(.remove_dir, builder.fmt("RemoveDir {s}", .{dir_path}), builder.allocator, make),
lib/std/build/RunStep.zig โ†’ lib/std/Build/RunStep.zig
@@ -1,17 +1,15 @@
 const std = @import("../std.zig");
 const builtin = @import("builtin");
-const build = std.build;
-const Step = build.Step;
-const Builder = build.Builder;
-const LibExeObjStep = build.LibExeObjStep;
-const WriteFileStep = build.WriteFileStep;
+const Step = std.Build.Step;
+const LibExeObjStep = std.Build.LibExeObjStep;
+const WriteFileStep = std.Build.WriteFileStep;
 const fs = std.fs;
 const mem = std.mem;
 const process = std.process;
 const ArrayList = std.ArrayList;
 const EnvMap = process.EnvMap;
 const Allocator = mem.Allocator;
-const ExecError = build.Builder.ExecError;
+const ExecError = std.Build.ExecError;
 
 const max_stdout_size = 1 * 1024 * 1024; // 1 MiB
 
@@ -20,7 +18,7 @@ const RunStep = @This();
 pub const base_id: Step.Id = .run;
 
 step: Step,
-builder: *Builder,
+builder: *std.Build,
 
 /// See also addArg and addArgs to modifying this directly
 argv: ArrayList(Arg),
@@ -51,11 +49,11 @@ pub const StdIoAction = union(enum) {
 
 pub const Arg = union(enum) {
     artifact: *LibExeObjStep,
-    file_source: build.FileSource,
+    file_source: std.Build.FileSource,
     bytes: []u8,
 };
 
-pub fn create(builder: *Builder, name: []const u8) *RunStep {
+pub fn create(builder: *std.Build, name: []const u8) *RunStep {
     const self = builder.allocator.create(RunStep) catch unreachable;
     self.* = RunStep{
         .builder = builder,
@@ -73,7 +71,7 @@ pub fn addArtifactArg(self: *RunStep, artifact: *LibExeObjStep) void {
     self.step.dependOn(&artifact.step);
 }
 
-pub fn addFileSourceArg(self: *RunStep, file_source: build.FileSource) void {
+pub fn addFileSourceArg(self: *RunStep, file_source: std.Build.FileSource) void {
     self.argv.append(Arg{
         .file_source = file_source.dupe(self.builder),
     }) catch unreachable;
@@ -101,7 +99,7 @@ pub fn addPathDir(self: *RunStep, search_path: []const u8) void {
 }
 
 /// For internal use only, users of `RunStep` should use `addPathDir` directly.
-pub fn addPathDirInternal(step: *Step, builder: *Builder, search_path: []const u8) void {
+pub fn addPathDirInternal(step: *Step, builder: *std.Build, search_path: []const u8) void {
     const env_map = getEnvMapInternal(step, builder.allocator);
 
     const key = "PATH";
@@ -122,7 +120,7 @@ pub fn getEnvMap(self: *RunStep) *EnvMap {
 fn getEnvMapInternal(step: *Step, allocator: Allocator) *EnvMap {
     const maybe_env_map = switch (step.id) {
         .run => step.cast(RunStep).?.env_map,
-        .emulatable_run => step.cast(build.EmulatableRunStep).?.env_map,
+        .emulatable_run => step.cast(std.Build.EmulatableRunStep).?.env_map,
         else => unreachable,
     };
     return maybe_env_map orelse {
@@ -195,7 +193,7 @@ fn make(step: *Step) !void {
 
 pub fn runCommand(
     argv: []const []const u8,
-    builder: *Builder,
+    builder: *std.Build,
     expected_exit_code: ?u8,
     stdout_action: StdIoAction,
     stderr_action: StdIoAction,
@@ -363,7 +361,7 @@ fn addPathForDynLibs(self: *RunStep, artifact: *LibExeObjStep) void {
 
 /// This should only be used for internal usage, this is called automatically
 /// for the user.
-pub fn addPathForDynLibsInternal(step: *Step, builder: *Builder, artifact: *LibExeObjStep) void {
+pub fn addPathForDynLibsInternal(step: *Step, builder: *std.Build, artifact: *LibExeObjStep) void {
     for (artifact.link_objects.items) |link_object| {
         switch (link_object) {
             .other_step => |other| {
lib/std/Build/Step.zig
@@ -0,0 +1,97 @@
+id: Id,
+name: []const u8,
+makeFn: *const fn (self: *Step) anyerror!void,
+dependencies: std.ArrayList(*Step),
+loop_flag: bool,
+done_flag: bool,
+
+pub const Id = enum {
+    top_level,
+    lib_exe_obj,
+    install_artifact,
+    install_file,
+    install_dir,
+    log,
+    remove_dir,
+    fmt,
+    translate_c,
+    write_file,
+    run,
+    emulatable_run,
+    check_file,
+    check_object,
+    config_header,
+    install_raw,
+    options,
+    custom,
+
+    pub fn Type(comptime id: Id) type {
+        return switch (id) {
+            .top_level => Build.TopLevelStep,
+            .lib_exe_obj => Build.LibExeObjStep,
+            .install_artifact => Build.InstallArtifactStep,
+            .install_file => Build.InstallFileStep,
+            .install_dir => Build.InstallDirStep,
+            .log => Build.LogStep,
+            .remove_dir => Build.RemoveDirStep,
+            .fmt => Build.FmtStep,
+            .translate_c => Build.TranslateCStep,
+            .write_file => Build.WriteFileStep,
+            .run => Build.RunStep,
+            .emulatable_run => Build.EmulatableRunStep,
+            .check_file => Build.CheckFileStep,
+            .check_object => Build.CheckObjectStep,
+            .config_header => Build.ConfigHeaderStep,
+            .install_raw => Build.InstallRawStep,
+            .options => Build.OptionsStep,
+            .custom => @compileError("no type available for custom step"),
+        };
+    }
+};
+
+pub fn init(
+    id: Id,
+    name: []const u8,
+    allocator: Allocator,
+    makeFn: *const fn (self: *Step) anyerror!void,
+) Step {
+    return Step{
+        .id = id,
+        .name = allocator.dupe(u8, name) catch unreachable,
+        .makeFn = makeFn,
+        .dependencies = std.ArrayList(*Step).init(allocator),
+        .loop_flag = false,
+        .done_flag = false,
+    };
+}
+
+pub fn initNoOp(id: Id, name: []const u8, allocator: Allocator) Step {
+    return init(id, name, allocator, makeNoOp);
+}
+
+pub fn make(self: *Step) !void {
+    if (self.done_flag) return;
+
+    try self.makeFn(self);
+    self.done_flag = true;
+}
+
+pub fn dependOn(self: *Step, other: *Step) void {
+    self.dependencies.append(other) catch unreachable;
+}
+
+fn makeNoOp(self: *Step) anyerror!void {
+    _ = self;
+}
+
+pub fn cast(step: *Step, comptime T: type) ?*T {
+    if (step.id == T.base_id) {
+        return @fieldParentPtr(T, "step", step);
+    }
+    return null;
+}
+
+const Step = @This();
+const std = @import("../std.zig");
+const Build = std.Build;
+const Allocator = std.mem.Allocator;
lib/std/build/TranslateCStep.zig โ†’ lib/std/Build/TranslateCStep.zig
@@ -1,9 +1,7 @@
 const std = @import("../std.zig");
-const build = std.build;
-const Step = build.Step;
-const Builder = build.Builder;
-const LibExeObjStep = build.LibExeObjStep;
-const CheckFileStep = build.CheckFileStep;
+const Step = std.Build.Step;
+const LibExeObjStep = std.Build.LibExeObjStep;
+const CheckFileStep = std.Build.CheckFileStep;
 const fs = std.fs;
 const mem = std.mem;
 const CrossTarget = std.zig.CrossTarget;
@@ -13,23 +11,23 @@ const TranslateCStep = @This();
 pub const base_id = .translate_c;
 
 step: Step,
-builder: *Builder,
-source: build.FileSource,
+builder: *std.Build,
+source: std.Build.FileSource,
 include_dirs: std.ArrayList([]const u8),
 c_macros: std.ArrayList([]const u8),
 output_dir: ?[]const u8,
 out_basename: []const u8,
 target: CrossTarget,
 optimize: std.builtin.OptimizeMode,
-output_file: build.GeneratedFile,
+output_file: std.Build.GeneratedFile,
 
 pub const Options = struct {
-    source_file: build.FileSource,
+    source_file: std.Build.FileSource,
     target: CrossTarget,
     optimize: std.builtin.OptimizeMode,
 };
 
-pub fn create(builder: *Builder, options: Options) *TranslateCStep {
+pub fn create(builder: *std.Build, options: Options) *TranslateCStep {
     const self = builder.allocator.create(TranslateCStep) catch unreachable;
     const source = options.source_file.dupe(builder);
     self.* = TranslateCStep{
@@ -42,7 +40,7 @@ pub fn create(builder: *Builder, options: Options) *TranslateCStep {
         .out_basename = undefined,
         .target = options.target,
         .optimize = options.optimize,
-        .output_file = build.GeneratedFile{ .step = &self.step },
+        .output_file = std.Build.GeneratedFile{ .step = &self.step },
     };
     source.addStepDependencies(&self.step);
     return self;
@@ -79,7 +77,7 @@ pub fn addCheckFile(self: *TranslateCStep, expected_matches: []const []const u8)
 /// If the value is omitted, it is set to 1.
 /// `name` and `value` need not live longer than the function call.
 pub fn defineCMacro(self: *TranslateCStep, name: []const u8, value: ?[]const u8) void {
-    const macro = build.constructCMacro(self.builder.allocator, name, value);
+    const macro = std.Build.constructCMacro(self.builder.allocator, name, value);
     self.c_macros.append(macro) catch unreachable;
 }
 
lib/std/build/WriteFileStep.zig โ†’ lib/std/Build/WriteFileStep.zig
@@ -1,7 +1,5 @@
 const std = @import("../std.zig");
-const build = @import("../build.zig");
-const Step = build.Step;
-const Builder = build.Builder;
+const Step = std.Build.Step;
 const fs = std.fs;
 const ArrayList = std.ArrayList;
 
@@ -10,17 +8,17 @@ const WriteFileStep = @This();
 pub const base_id = .write_file;
 
 step: Step,
-builder: *Builder,
+builder: *std.Build,
 output_dir: []const u8,
 files: std.TailQueue(File),
 
 pub const File = struct {
-    source: build.GeneratedFile,
+    source: std.Build.GeneratedFile,
     basename: []const u8,
     bytes: []const u8,
 };
 
-pub fn init(builder: *Builder) WriteFileStep {
+pub fn init(builder: *std.Build) WriteFileStep {
     return WriteFileStep{
         .builder = builder,
         .step = Step.init(.write_file, "writefile", builder.allocator, make),
@@ -33,7 +31,7 @@ pub fn add(self: *WriteFileStep, basename: []const u8, bytes: []const u8) void {
     const node = self.builder.allocator.create(std.TailQueue(File).Node) catch unreachable;
     node.* = .{
         .data = .{
-            .source = build.GeneratedFile{ .step = &self.step },
+            .source = std.Build.GeneratedFile{ .step = &self.step },
             .basename = self.builder.dupePath(basename),
             .bytes = self.builder.dupe(bytes),
         },
@@ -43,11 +41,11 @@ pub fn add(self: *WriteFileStep, basename: []const u8, bytes: []const u8) void {
 }
 
 /// Gets a file source for the given basename. If the file does not exist, returns `null`.
-pub fn getFileSource(step: *WriteFileStep, basename: []const u8) ?build.FileSource {
+pub fn getFileSource(step: *WriteFileStep, basename: []const u8) ?std.Build.FileSource {
     var it = step.files.first;
     while (it) |node| : (it = node.next) {
         if (std.mem.eql(u8, node.data.basename, basename))
-            return build.FileSource{ .generated = &node.data.source };
+            return std.Build.FileSource{ .generated = &node.data.source };
     }
     return null;
 }
lib/std/Build.zig
@@ -0,0 +1,1771 @@
+const std = @import("std.zig");
+const builtin = @import("builtin");
+const io = std.io;
+const fs = std.fs;
+const mem = std.mem;
+const debug = std.debug;
+const panic = std.debug.panic;
+const assert = debug.assert;
+const log = std.log;
+const ArrayList = std.ArrayList;
+const StringHashMap = std.StringHashMap;
+const Allocator = mem.Allocator;
+const process = std.process;
+const EnvMap = std.process.EnvMap;
+const fmt_lib = std.fmt;
+const File = std.fs.File;
+const CrossTarget = std.zig.CrossTarget;
+const NativeTargetInfo = std.zig.system.NativeTargetInfo;
+const Sha256 = std.crypto.hash.sha2.Sha256;
+const Build = @This();
+
+pub const Step = @import("Build/Step.zig");
+pub const CheckFileStep = @import("Build/CheckFileStep.zig");
+pub const CheckObjectStep = @import("Build/CheckObjectStep.zig");
+pub const ConfigHeaderStep = @import("Build/ConfigHeaderStep.zig");
+pub const EmulatableRunStep = @import("Build/EmulatableRunStep.zig");
+pub const FmtStep = @import("Build/FmtStep.zig");
+pub const InstallArtifactStep = @import("Build/InstallArtifactStep.zig");
+pub const InstallDirStep = @import("Build/InstallDirStep.zig");
+pub const InstallFileStep = @import("Build/InstallFileStep.zig");
+pub const InstallRawStep = @import("Build/InstallRawStep.zig");
+pub const LibExeObjStep = @import("Build/LibExeObjStep.zig");
+pub const LogStep = @import("Build/LogStep.zig");
+pub const OptionsStep = @import("Build/OptionsStep.zig");
+pub const RemoveDirStep = @import("Build/RemoveDirStep.zig");
+pub const RunStep = @import("Build/RunStep.zig");
+pub const TranslateCStep = @import("Build/TranslateCStep.zig");
+pub const WriteFileStep = @import("Build/WriteFileStep.zig");
+
+install_tls: TopLevelStep,
+uninstall_tls: TopLevelStep,
+allocator: Allocator,
+user_input_options: UserInputOptionsMap,
+available_options_map: AvailableOptionsMap,
+available_options_list: ArrayList(AvailableOption),
+verbose: bool,
+verbose_link: bool,
+verbose_cc: bool,
+verbose_air: bool,
+verbose_llvm_ir: bool,
+verbose_cimport: bool,
+verbose_llvm_cpu_features: bool,
+/// The purpose of executing the command is for a human to read compile errors from the terminal
+prominent_compile_errors: bool,
+color: enum { auto, on, off } = .auto,
+reference_trace: ?u32 = null,
+invalid_user_input: bool,
+zig_exe: []const u8,
+default_step: *Step,
+env_map: *EnvMap,
+top_level_steps: ArrayList(*TopLevelStep),
+install_prefix: []const u8,
+dest_dir: ?[]const u8,
+lib_dir: []const u8,
+exe_dir: []const u8,
+h_dir: []const u8,
+install_path: []const u8,
+sysroot: ?[]const u8 = null,
+search_prefixes: ArrayList([]const u8),
+libc_file: ?[]const u8 = null,
+installed_files: ArrayList(InstalledFile),
+/// Path to the directory containing build.zig.
+build_root: []const u8,
+cache_root: []const u8,
+global_cache_root: []const u8,
+/// zig lib dir
+override_lib_dir: ?[]const u8,
+vcpkg_root: VcpkgRoot = .unattempted,
+pkg_config_pkg_list: ?(PkgConfigError![]const PkgConfigPkg) = null,
+args: ?[][]const u8 = null,
+debug_log_scopes: []const []const u8 = &.{},
+debug_compile_errors: bool = false,
+
+/// Experimental. Use system Darling installation to run cross compiled macOS build artifacts.
+enable_darling: bool = false,
+/// Use system QEMU installation to run cross compiled foreign architecture build artifacts.
+enable_qemu: bool = false,
+/// Darwin. Use Rosetta to run x86_64 macOS build artifacts on arm64 macOS.
+enable_rosetta: bool = false,
+/// Use system Wasmtime installation to run cross compiled wasm/wasi build artifacts.
+enable_wasmtime: bool = false,
+/// Use system Wine installation to run cross compiled Windows build artifacts.
+enable_wine: bool = false,
+/// After following the steps in https://github.com/ziglang/zig/wiki/Updating-libc#glibc,
+/// this will be the directory $glibc-build-dir/install/glibcs
+/// Given the example of the aarch64 target, this is the directory
+/// that contains the path `aarch64-linux-gnu/lib/ld-linux-aarch64.so.1`.
+glibc_runtimes_dir: ?[]const u8 = null,
+
+/// Information about the native target. Computed before build() is invoked.
+host: NativeTargetInfo,
+
+dep_prefix: []const u8 = "",
+
+pub const ExecError = error{
+    ReadFailure,
+    ExitCodeFailure,
+    ProcessTerminated,
+    ExecNotSupported,
+} || std.ChildProcess.SpawnError;
+
+pub const PkgConfigError = error{
+    PkgConfigCrashed,
+    PkgConfigFailed,
+    PkgConfigNotInstalled,
+    PkgConfigInvalidOutput,
+};
+
+pub const PkgConfigPkg = struct {
+    name: []const u8,
+    desc: []const u8,
+};
+
+pub const CStd = enum {
+    C89,
+    C99,
+    C11,
+};
+
+const UserInputOptionsMap = StringHashMap(UserInputOption);
+const AvailableOptionsMap = StringHashMap(AvailableOption);
+
+const AvailableOption = struct {
+    name: []const u8,
+    type_id: TypeId,
+    description: []const u8,
+    /// If the `type_id` is `enum` this provides the list of enum options
+    enum_options: ?[]const []const u8,
+};
+
+const UserInputOption = struct {
+    name: []const u8,
+    value: UserValue,
+    used: bool,
+};
+
+const UserValue = union(enum) {
+    flag: void,
+    scalar: []const u8,
+    list: ArrayList([]const u8),
+    map: StringHashMap(*const UserValue),
+};
+
+const TypeId = enum {
+    bool,
+    int,
+    float,
+    @"enum",
+    string,
+    list,
+};
+
+const TopLevelStep = struct {
+    pub const base_id = .top_level;
+
+    step: Step,
+    description: []const u8,
+};
+
+pub const DirList = struct {
+    lib_dir: ?[]const u8 = null,
+    exe_dir: ?[]const u8 = null,
+    include_dir: ?[]const u8 = null,
+};
+
+pub fn create(
+    allocator: Allocator,
+    zig_exe: []const u8,
+    build_root: []const u8,
+    cache_root: []const u8,
+    global_cache_root: []const u8,
+) !*Build {
+    const env_map = try allocator.create(EnvMap);
+    env_map.* = try process.getEnvMap(allocator);
+
+    const host = try NativeTargetInfo.detect(.{});
+
+    const self = try allocator.create(Build);
+    self.* = Build{
+        .zig_exe = zig_exe,
+        .build_root = build_root,
+        .cache_root = try fs.path.relative(allocator, build_root, cache_root),
+        .global_cache_root = global_cache_root,
+        .verbose = false,
+        .verbose_link = false,
+        .verbose_cc = false,
+        .verbose_air = false,
+        .verbose_llvm_ir = false,
+        .verbose_cimport = false,
+        .verbose_llvm_cpu_features = false,
+        .prominent_compile_errors = false,
+        .invalid_user_input = false,
+        .allocator = allocator,
+        .user_input_options = UserInputOptionsMap.init(allocator),
+        .available_options_map = AvailableOptionsMap.init(allocator),
+        .available_options_list = ArrayList(AvailableOption).init(allocator),
+        .top_level_steps = ArrayList(*TopLevelStep).init(allocator),
+        .default_step = undefined,
+        .env_map = env_map,
+        .search_prefixes = ArrayList([]const u8).init(allocator),
+        .install_prefix = undefined,
+        .lib_dir = undefined,
+        .exe_dir = undefined,
+        .h_dir = undefined,
+        .dest_dir = env_map.get("DESTDIR"),
+        .installed_files = ArrayList(InstalledFile).init(allocator),
+        .install_tls = TopLevelStep{
+            .step = Step.initNoOp(.top_level, "install", allocator),
+            .description = "Copy build artifacts to prefix path",
+        },
+        .uninstall_tls = TopLevelStep{
+            .step = Step.init(.top_level, "uninstall", allocator, makeUninstall),
+            .description = "Remove build artifacts from prefix path",
+        },
+        .override_lib_dir = null,
+        .install_path = undefined,
+        .args = null,
+        .host = host,
+    };
+    try self.top_level_steps.append(&self.install_tls);
+    try self.top_level_steps.append(&self.uninstall_tls);
+    self.default_step = &self.install_tls.step;
+    return self;
+}
+
+fn createChild(
+    parent: *Build,
+    dep_name: []const u8,
+    build_root: []const u8,
+    args: anytype,
+) !*Build {
+    const child = try createChildOnly(parent, dep_name, build_root);
+    try applyArgs(child, args);
+    return child;
+}
+
+fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: []const u8) !*Build {
+    const allocator = parent.allocator;
+    const child = try allocator.create(Build);
+    child.* = .{
+        .allocator = allocator,
+        .install_tls = .{
+            .step = Step.initNoOp(.top_level, "install", allocator),
+            .description = "Copy build artifacts to prefix path",
+        },
+        .uninstall_tls = .{
+            .step = Step.init(.top_level, "uninstall", allocator, makeUninstall),
+            .description = "Remove build artifacts from prefix path",
+        },
+        .user_input_options = UserInputOptionsMap.init(allocator),
+        .available_options_map = AvailableOptionsMap.init(allocator),
+        .available_options_list = ArrayList(AvailableOption).init(allocator),
+        .verbose = parent.verbose,
+        .verbose_link = parent.verbose_link,
+        .verbose_cc = parent.verbose_cc,
+        .verbose_air = parent.verbose_air,
+        .verbose_llvm_ir = parent.verbose_llvm_ir,
+        .verbose_cimport = parent.verbose_cimport,
+        .verbose_llvm_cpu_features = parent.verbose_llvm_cpu_features,
+        .prominent_compile_errors = parent.prominent_compile_errors,
+        .color = parent.color,
+        .reference_trace = parent.reference_trace,
+        .invalid_user_input = false,
+        .zig_exe = parent.zig_exe,
+        .default_step = undefined,
+        .env_map = parent.env_map,
+        .top_level_steps = ArrayList(*TopLevelStep).init(allocator),
+        .install_prefix = undefined,
+        .dest_dir = parent.dest_dir,
+        .lib_dir = parent.lib_dir,
+        .exe_dir = parent.exe_dir,
+        .h_dir = parent.h_dir,
+        .install_path = parent.install_path,
+        .sysroot = parent.sysroot,
+        .search_prefixes = ArrayList([]const u8).init(allocator),
+        .libc_file = parent.libc_file,
+        .installed_files = ArrayList(InstalledFile).init(allocator),
+        .build_root = build_root,
+        .cache_root = parent.cache_root,
+        .global_cache_root = parent.global_cache_root,
+        .override_lib_dir = parent.override_lib_dir,
+        .debug_log_scopes = parent.debug_log_scopes,
+        .debug_compile_errors = parent.debug_compile_errors,
+        .enable_darling = parent.enable_darling,
+        .enable_qemu = parent.enable_qemu,
+        .enable_rosetta = parent.enable_rosetta,
+        .enable_wasmtime = parent.enable_wasmtime,
+        .enable_wine = parent.enable_wine,
+        .glibc_runtimes_dir = parent.glibc_runtimes_dir,
+        .host = parent.host,
+        .dep_prefix = parent.fmt("{s}{s}.", .{ parent.dep_prefix, dep_name }),
+    };
+    try child.top_level_steps.append(&child.install_tls);
+    try child.top_level_steps.append(&child.uninstall_tls);
+    child.default_step = &child.install_tls.step;
+    return child;
+}
+
+fn applyArgs(b: *Build, args: anytype) !void {
+    inline for (@typeInfo(@TypeOf(args)).Struct.fields) |field| {
+        const v = @field(args, field.name);
+        const T = @TypeOf(v);
+        switch (T) {
+            CrossTarget => {
+                try b.user_input_options.put(field.name, .{
+                    .name = field.name,
+                    .value = .{ .scalar = try v.zigTriple(b.allocator) },
+                    .used = false,
+                });
+                try b.user_input_options.put("cpu", .{
+                    .name = "cpu",
+                    .value = .{ .scalar = try serializeCpu(b.allocator, v.getCpu()) },
+                    .used = false,
+                });
+            },
+            []const u8 => {
+                try b.user_input_options.put(field.name, .{
+                    .name = field.name,
+                    .value = .{ .scalar = v },
+                    .used = false,
+                });
+            },
+            else => switch (@typeInfo(T)) {
+                .Bool => {
+                    try b.user_input_options.put(field.name, .{
+                        .name = field.name,
+                        .value = .{ .scalar = if (v) "true" else "false" },
+                        .used = false,
+                    });
+                },
+                .Enum => {
+                    try b.user_input_options.put(field.name, .{
+                        .name = field.name,
+                        .value = .{ .scalar = @tagName(v) },
+                        .used = false,
+                    });
+                },
+                .Int => {
+                    try b.user_input_options.put(field.name, .{
+                        .name = field.name,
+                        .value = .{ .scalar = try std.fmt.allocPrint(b.allocator, "{d}", .{v}) },
+                        .used = false,
+                    });
+                },
+                else => @compileError("option '" ++ field.name ++ "' has unsupported type: " ++ @typeName(T)),
+            },
+        }
+    }
+    const Hasher = std.crypto.auth.siphash.SipHash128(1, 3);
+    // Random bytes to make unique. Refresh this with new random bytes when
+    // implementation is modified in a non-backwards-compatible way.
+    var hash = Hasher.init("ZaEsvQ5ClaA2IdH9");
+    hash.update(b.dep_prefix);
+    // TODO additionally update the hash with `args`.
+
+    var digest: [16]u8 = undefined;
+    hash.final(&digest);
+    var hash_basename: [digest.len * 2]u8 = undefined;
+    _ = std.fmt.bufPrint(&hash_basename, "{s}", .{std.fmt.fmtSliceHexLower(&digest)}) catch
+        unreachable;
+
+    const install_prefix = b.pathJoin(&.{ b.cache_root, "i", &hash_basename });
+    b.resolveInstallPrefix(install_prefix, .{});
+}
+
+pub fn destroy(self: *Build) void {
+    self.env_map.deinit();
+    self.top_level_steps.deinit();
+    self.allocator.destroy(self);
+}
+
+/// This function is intended to be called by lib/build_runner.zig, not a build.zig file.
+pub fn resolveInstallPrefix(self: *Build, install_prefix: ?[]const u8, dir_list: DirList) void {
+    if (self.dest_dir) |dest_dir| {
+        self.install_prefix = install_prefix orelse "/usr";
+        self.install_path = self.pathJoin(&.{ dest_dir, self.install_prefix });
+    } else {
+        self.install_prefix = install_prefix orelse
+            (self.pathJoin(&.{ self.build_root, "zig-out" }));
+        self.install_path = self.install_prefix;
+    }
+
+    var lib_list = [_][]const u8{ self.install_path, "lib" };
+    var exe_list = [_][]const u8{ self.install_path, "bin" };
+    var h_list = [_][]const u8{ self.install_path, "include" };
+
+    if (dir_list.lib_dir) |dir| {
+        if (std.fs.path.isAbsolute(dir)) lib_list[0] = self.dest_dir orelse "";
+        lib_list[1] = dir;
+    }
+
+    if (dir_list.exe_dir) |dir| {
+        if (std.fs.path.isAbsolute(dir)) exe_list[0] = self.dest_dir orelse "";
+        exe_list[1] = dir;
+    }
+
+    if (dir_list.include_dir) |dir| {
+        if (std.fs.path.isAbsolute(dir)) h_list[0] = self.dest_dir orelse "";
+        h_list[1] = dir;
+    }
+
+    self.lib_dir = self.pathJoin(&lib_list);
+    self.exe_dir = self.pathJoin(&exe_list);
+    self.h_dir = self.pathJoin(&h_list);
+}
+
+pub fn addOptions(self: *Build) *OptionsStep {
+    return OptionsStep.create(self);
+}
+
+pub const ExecutableOptions = struct {
+    name: []const u8,
+    root_source_file: ?FileSource = null,
+    version: ?std.builtin.Version = null,
+    target: CrossTarget = .{},
+    optimize: std.builtin.Mode = .Debug,
+    linkage: ?LibExeObjStep.Linkage = null,
+};
+
+pub fn addExecutable(b: *Build, options: ExecutableOptions) *LibExeObjStep {
+    return LibExeObjStep.create(b, .{
+        .name = options.name,
+        .root_source_file = options.root_source_file,
+        .version = options.version,
+        .target = options.target,
+        .optimize = options.optimize,
+        .kind = .exe,
+        .linkage = options.linkage,
+    });
+}
+
+pub const ObjectOptions = struct {
+    name: []const u8,
+    root_source_file: ?FileSource = null,
+    target: CrossTarget,
+    optimize: std.builtin.Mode,
+};
+
+pub fn addObject(b: *Build, options: ObjectOptions) *LibExeObjStep {
+    return LibExeObjStep.create(b, .{
+        .name = options.name,
+        .root_source_file = options.root_source_file,
+        .target = options.target,
+        .optimize = options.optimize,
+        .kind = .obj,
+    });
+}
+
+pub const SharedLibraryOptions = struct {
+    name: []const u8,
+    root_source_file: ?FileSource = null,
+    version: ?std.builtin.Version = null,
+    target: CrossTarget,
+    optimize: std.builtin.Mode,
+};
+
+pub fn addSharedLibrary(b: *Build, options: SharedLibraryOptions) *LibExeObjStep {
+    return LibExeObjStep.create(b, .{
+        .name = options.name,
+        .root_source_file = options.root_source_file,
+        .kind = .lib,
+        .linkage = .dynamic,
+        .version = options.version,
+        .target = options.target,
+        .optimize = options.optimize,
+    });
+}
+
+pub const StaticLibraryOptions = struct {
+    name: []const u8,
+    root_source_file: ?FileSource = null,
+    target: CrossTarget,
+    optimize: std.builtin.Mode,
+    version: ?std.builtin.Version = null,
+};
+
+pub fn addStaticLibrary(b: *Build, options: StaticLibraryOptions) *LibExeObjStep {
+    return LibExeObjStep.create(b, .{
+        .name = options.name,
+        .root_source_file = options.root_source_file,
+        .kind = .lib,
+        .linkage = .static,
+        .version = options.version,
+        .target = options.target,
+        .optimize = options.optimize,
+    });
+}
+
+pub const TestOptions = struct {
+    name: []const u8 = "test",
+    kind: LibExeObjStep.Kind = .@"test",
+    root_source_file: FileSource,
+    target: CrossTarget = .{},
+    optimize: std.builtin.Mode = .Debug,
+    version: ?std.builtin.Version = null,
+};
+
+pub fn addTest(b: *Build, options: TestOptions) *LibExeObjStep {
+    return LibExeObjStep.create(b, .{
+        .name = options.name,
+        .kind = options.kind,
+        .root_source_file = options.root_source_file,
+        .target = options.target,
+        .optimize = options.optimize,
+    });
+}
+
+pub const AssemblyOptions = struct {
+    name: []const u8,
+    source_file: FileSource,
+    target: CrossTarget,
+    optimize: std.builtin.Mode,
+};
+
+pub fn addAssembly(b: *Build, options: AssemblyOptions) *LibExeObjStep {
+    const obj_step = LibExeObjStep.create(b, .{
+        .name = options.name,
+        .root_source_file = null,
+        .target = options.target,
+        .optimize = options.optimize,
+    });
+    obj_step.addAssemblyFileSource(options.source_file.dupe(b));
+    return obj_step;
+}
+
+/// Initializes a RunStep with argv, which must at least have the path to the
+/// executable. More command line arguments can be added with `addArg`,
+/// `addArgs`, and `addArtifactArg`.
+/// Be careful using this function, as it introduces a system dependency.
+/// To run an executable built with zig build, see `LibExeObjStep.run`.
+pub fn addSystemCommand(self: *Build, argv: []const []const u8) *RunStep {
+    assert(argv.len >= 1);
+    const run_step = RunStep.create(self, self.fmt("run {s}", .{argv[0]}));
+    run_step.addArgs(argv);
+    return run_step;
+}
+
+pub fn addConfigHeader(
+    b: *Build,
+    source: FileSource,
+    style: ConfigHeaderStep.Style,
+    values: anytype,
+) *ConfigHeaderStep {
+    const config_header_step = ConfigHeaderStep.create(b, source, style);
+    config_header_step.addValues(values);
+    return config_header_step;
+}
+
+/// Allocator.dupe without the need to handle out of memory.
+pub fn dupe(self: *Build, bytes: []const u8) []u8 {
+    return self.allocator.dupe(u8, bytes) catch unreachable;
+}
+
+/// Duplicates an array of strings without the need to handle out of memory.
+pub fn dupeStrings(self: *Build, strings: []const []const u8) [][]u8 {
+    const array = self.allocator.alloc([]u8, strings.len) catch unreachable;
+    for (strings) |s, i| {
+        array[i] = self.dupe(s);
+    }
+    return array;
+}
+
+/// Duplicates a path and converts all slashes to the OS's canonical path separator.
+pub fn dupePath(self: *Build, bytes: []const u8) []u8 {
+    const the_copy = self.dupe(bytes);
+    for (the_copy) |*byte| {
+        switch (byte.*) {
+            '/', '\\' => byte.* = fs.path.sep,
+            else => {},
+        }
+    }
+    return the_copy;
+}
+
+/// Duplicates a package recursively.
+pub fn dupePkg(self: *Build, package: Pkg) Pkg {
+    var the_copy = Pkg{
+        .name = self.dupe(package.name),
+        .source = package.source.dupe(self),
+    };
+
+    if (package.dependencies) |dependencies| {
+        const new_dependencies = self.allocator.alloc(Pkg, dependencies.len) catch unreachable;
+        the_copy.dependencies = new_dependencies;
+
+        for (dependencies) |dep_package, i| {
+            new_dependencies[i] = self.dupePkg(dep_package);
+        }
+    }
+    return the_copy;
+}
+
+pub fn addWriteFile(self: *Build, file_path: []const u8, data: []const u8) *WriteFileStep {
+    const write_file_step = self.addWriteFiles();
+    write_file_step.add(file_path, data);
+    return write_file_step;
+}
+
+pub fn addWriteFiles(self: *Build) *WriteFileStep {
+    const write_file_step = self.allocator.create(WriteFileStep) catch unreachable;
+    write_file_step.* = WriteFileStep.init(self);
+    return write_file_step;
+}
+
+pub fn addLog(self: *Build, comptime format: []const u8, args: anytype) *LogStep {
+    const data = self.fmt(format, args);
+    const log_step = self.allocator.create(LogStep) catch unreachable;
+    log_step.* = LogStep.init(self, data);
+    return log_step;
+}
+
+pub fn addRemoveDirTree(self: *Build, dir_path: []const u8) *RemoveDirStep {
+    const remove_dir_step = self.allocator.create(RemoveDirStep) catch unreachable;
+    remove_dir_step.* = RemoveDirStep.init(self, dir_path);
+    return remove_dir_step;
+}
+
+pub fn addFmt(self: *Build, paths: []const []const u8) *FmtStep {
+    return FmtStep.create(self, paths);
+}
+
+pub fn addTranslateC(self: *Build, options: TranslateCStep.Options) *TranslateCStep {
+    return TranslateCStep.create(self, options);
+}
+
+pub fn make(self: *Build, step_names: []const []const u8) !void {
+    try self.makePath(self.cache_root);
+
+    var wanted_steps = ArrayList(*Step).init(self.allocator);
+    defer wanted_steps.deinit();
+
+    if (step_names.len == 0) {
+        try wanted_steps.append(self.default_step);
+    } else {
+        for (step_names) |step_name| {
+            const s = try self.getTopLevelStepByName(step_name);
+            try wanted_steps.append(s);
+        }
+    }
+
+    for (wanted_steps.items) |s| {
+        try self.makeOneStep(s);
+    }
+}
+
+pub fn getInstallStep(self: *Build) *Step {
+    return &self.install_tls.step;
+}
+
+pub fn getUninstallStep(self: *Build) *Step {
+    return &self.uninstall_tls.step;
+}
+
+fn makeUninstall(uninstall_step: *Step) anyerror!void {
+    const uninstall_tls = @fieldParentPtr(TopLevelStep, "step", uninstall_step);
+    const self = @fieldParentPtr(Build, "uninstall_tls", uninstall_tls);
+
+    for (self.installed_files.items) |installed_file| {
+        const full_path = self.getInstallPath(installed_file.dir, installed_file.path);
+        if (self.verbose) {
+            log.info("rm {s}", .{full_path});
+        }
+        fs.cwd().deleteTree(full_path) catch {};
+    }
+
+    // TODO remove empty directories
+}
+
+fn makeOneStep(self: *Build, s: *Step) anyerror!void {
+    if (s.loop_flag) {
+        log.err("Dependency loop detected:\n  {s}", .{s.name});
+        return error.DependencyLoopDetected;
+    }
+    s.loop_flag = true;
+
+    for (s.dependencies.items) |dep| {
+        self.makeOneStep(dep) catch |err| {
+            if (err == error.DependencyLoopDetected) {
+                log.err("  {s}", .{s.name});
+            }
+            return err;
+        };
+    }
+
+    s.loop_flag = false;
+
+    try s.make();
+}
+
+fn getTopLevelStepByName(self: *Build, name: []const u8) !*Step {
+    for (self.top_level_steps.items) |top_level_step| {
+        if (mem.eql(u8, top_level_step.step.name, name)) {
+            return &top_level_step.step;
+        }
+    }
+    log.err("Cannot run step '{s}' because it does not exist", .{name});
+    return error.InvalidStepName;
+}
+
+pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_raw: []const u8) ?T {
+    const name = self.dupe(name_raw);
+    const description = self.dupe(description_raw);
+    const type_id = comptime typeToEnum(T);
+    const enum_options = if (type_id == .@"enum") blk: {
+        const fields = comptime std.meta.fields(T);
+        var options = ArrayList([]const u8).initCapacity(self.allocator, fields.len) catch unreachable;
+
+        inline for (fields) |field| {
+            options.appendAssumeCapacity(field.name);
+        }
+
+        break :blk options.toOwnedSlice() catch unreachable;
+    } else null;
+    const available_option = AvailableOption{
+        .name = name,
+        .type_id = type_id,
+        .description = description,
+        .enum_options = enum_options,
+    };
+    if ((self.available_options_map.fetchPut(name, available_option) catch unreachable) != null) {
+        panic("Option '{s}' declared twice", .{name});
+    }
+    self.available_options_list.append(available_option) catch unreachable;
+
+    const option_ptr = self.user_input_options.getPtr(name) orelse return null;
+    option_ptr.used = true;
+    switch (type_id) {
+        .bool => switch (option_ptr.value) {
+            .flag => return true,
+            .scalar => |s| {
+                if (mem.eql(u8, s, "true")) {
+                    return true;
+                } else if (mem.eql(u8, s, "false")) {
+                    return false;
+                } else {
+                    log.err("Expected -D{s} to be a boolean, but received '{s}'\n", .{ name, s });
+                    self.markInvalidUserInput();
+                    return null;
+                }
+            },
+            .list, .map => {
+                log.err("Expected -D{s} to be a boolean, but received a {s}.\n", .{
+                    name, @tagName(option_ptr.value),
+                });
+                self.markInvalidUserInput();
+                return null;
+            },
+        },
+        .int => switch (option_ptr.value) {
+            .flag, .list, .map => {
+                log.err("Expected -D{s} to be an integer, but received a {s}.\n", .{
+                    name, @tagName(option_ptr.value),
+                });
+                self.markInvalidUserInput();
+                return null;
+            },
+            .scalar => |s| {
+                const n = std.fmt.parseInt(T, s, 10) catch |err| switch (err) {
+                    error.Overflow => {
+                        log.err("-D{s} value {s} cannot fit into type {s}.\n", .{ name, s, @typeName(T) });
+                        self.markInvalidUserInput();
+                        return null;
+                    },
+                    else => {
+                        log.err("Expected -D{s} to be an integer of type {s}.\n", .{ name, @typeName(T) });
+                        self.markInvalidUserInput();
+                        return null;
+                    },
+                };
+                return n;
+            },
+        },
+        .float => switch (option_ptr.value) {
+            .flag, .map, .list => {
+                log.err("Expected -D{s} to be a float, but received a {s}.\n", .{
+                    name, @tagName(option_ptr.value),
+                });
+                self.markInvalidUserInput();
+                return null;
+            },
+            .scalar => |s| {
+                const n = std.fmt.parseFloat(T, s) catch {
+                    log.err("Expected -D{s} to be a float of type {s}.\n", .{ name, @typeName(T) });
+                    self.markInvalidUserInput();
+                    return null;
+                };
+                return n;
+            },
+        },
+        .@"enum" => switch (option_ptr.value) {
+            .flag, .map, .list => {
+                log.err("Expected -D{s} to be an enum, but received a {s}.\n", .{
+                    name, @tagName(option_ptr.value),
+                });
+                self.markInvalidUserInput();
+                return null;
+            },
+            .scalar => |s| {
+                if (std.meta.stringToEnum(T, s)) |enum_lit| {
+                    return enum_lit;
+                } else {
+                    log.err("Expected -D{s} to be of type {s}.\n", .{ name, @typeName(T) });
+                    self.markInvalidUserInput();
+                    return null;
+                }
+            },
+        },
+        .string => switch (option_ptr.value) {
+            .flag, .list, .map => {
+                log.err("Expected -D{s} to be a string, but received a {s}.\n", .{
+                    name, @tagName(option_ptr.value),
+                });
+                self.markInvalidUserInput();
+                return null;
+            },
+            .scalar => |s| return s,
+        },
+        .list => switch (option_ptr.value) {
+            .flag, .map => {
+                log.err("Expected -D{s} to be a list, but received a {s}.\n", .{
+                    name, @tagName(option_ptr.value),
+                });
+                self.markInvalidUserInput();
+                return null;
+            },
+            .scalar => |s| {
+                return self.allocator.dupe([]const u8, &[_][]const u8{s}) catch unreachable;
+            },
+            .list => |lst| return lst.items,
+        },
+    }
+}
+
+pub fn step(self: *Build, name: []const u8, description: []const u8) *Step {
+    const step_info = self.allocator.create(TopLevelStep) catch unreachable;
+    step_info.* = TopLevelStep{
+        .step = Step.initNoOp(.top_level, name, self.allocator),
+        .description = self.dupe(description),
+    };
+    self.top_level_steps.append(step_info) catch unreachable;
+    return &step_info.step;
+}
+
+pub const StandardOptimizeOptionOptions = struct {
+    preferred_optimize_mode: ?std.builtin.Mode = null,
+};
+
+pub fn standardOptimizeOption(self: *Build, options: StandardOptimizeOptionOptions) std.builtin.Mode {
+    if (options.preferred_optimize_mode) |mode| {
+        if (self.option(bool, "release", "optimize for end users") orelse false) {
+            return mode;
+        } else {
+            return .Debug;
+        }
+    } else {
+        return self.option(
+            std.builtin.Mode,
+            "optimize",
+            "prioritize performance, safety, or binary size (-O flag)",
+        ) orelse .Debug;
+    }
+}
+
+pub const StandardTargetOptionsArgs = struct {
+    whitelist: ?[]const CrossTarget = null,
+
+    default_target: CrossTarget = CrossTarget{},
+};
+
+/// Exposes standard `zig build` options for choosing a target.
+pub fn standardTargetOptions(self: *Build, args: StandardTargetOptionsArgs) CrossTarget {
+    const maybe_triple = self.option(
+        []const u8,
+        "target",
+        "The CPU architecture, OS, and ABI to build for",
+    );
+    const mcpu = self.option([]const u8, "cpu", "Target CPU features to add or subtract");
+
+    if (maybe_triple == null and mcpu == null) {
+        return args.default_target;
+    }
+
+    const triple = maybe_triple orelse "native";
+
+    var diags: CrossTarget.ParseOptions.Diagnostics = .{};
+    const selected_target = CrossTarget.parse(.{
+        .arch_os_abi = triple,
+        .cpu_features = mcpu,
+        .diagnostics = &diags,
+    }) catch |err| switch (err) {
+        error.UnknownCpuModel => {
+            log.err("Unknown CPU: '{s}'\nAvailable CPUs for architecture '{s}':", .{
+                diags.cpu_name.?,
+                @tagName(diags.arch.?),
+            });
+            for (diags.arch.?.allCpuModels()) |cpu| {
+                log.err(" {s}", .{cpu.name});
+            }
+            self.markInvalidUserInput();
+            return args.default_target;
+        },
+        error.UnknownCpuFeature => {
+            log.err(
+                \\Unknown CPU feature: '{s}'
+                \\Available CPU features for architecture '{s}':
+                \\
+            , .{
+                diags.unknown_feature_name.?,
+                @tagName(diags.arch.?),
+            });
+            for (diags.arch.?.allFeaturesList()) |feature| {
+                log.err(" {s}: {s}", .{ feature.name, feature.description });
+            }
+            self.markInvalidUserInput();
+            return args.default_target;
+        },
+        error.UnknownOperatingSystem => {
+            log.err(
+                \\Unknown OS: '{s}'
+                \\Available operating systems:
+                \\
+            , .{diags.os_name.?});
+            inline for (std.meta.fields(std.Target.Os.Tag)) |field| {
+                log.err(" {s}", .{field.name});
+            }
+            self.markInvalidUserInput();
+            return args.default_target;
+        },
+        else => |e| {
+            log.err("Unable to parse target '{s}': {s}\n", .{ triple, @errorName(e) });
+            self.markInvalidUserInput();
+            return args.default_target;
+        },
+    };
+
+    const selected_canonicalized_triple = selected_target.zigTriple(self.allocator) catch unreachable;
+
+    if (args.whitelist) |list| whitelist_check: {
+        // Make sure it's a match of one of the list.
+        var mismatch_triple = true;
+        var mismatch_cpu_features = true;
+        var whitelist_item = CrossTarget{};
+        for (list) |t| {
+            mismatch_cpu_features = true;
+            mismatch_triple = true;
+
+            const t_triple = t.zigTriple(self.allocator) catch unreachable;
+            if (mem.eql(u8, t_triple, selected_canonicalized_triple)) {
+                mismatch_triple = false;
+                whitelist_item = t;
+                if (t.getCpuFeatures().isSuperSetOf(selected_target.getCpuFeatures())) {
+                    mismatch_cpu_features = false;
+                    break :whitelist_check;
+                } else {
+                    break;
+                }
+            }
+        }
+        if (mismatch_triple) {
+            log.err("Chosen target '{s}' does not match one of the supported targets:", .{
+                selected_canonicalized_triple,
+            });
+            for (list) |t| {
+                const t_triple = t.zigTriple(self.allocator) catch unreachable;
+                log.err(" {s}", .{t_triple});
+            }
+        } else {
+            assert(mismatch_cpu_features);
+            const whitelist_cpu = whitelist_item.getCpu();
+            const selected_cpu = selected_target.getCpu();
+            log.err("Chosen CPU model '{s}' does not match one of the supported targets:", .{
+                selected_cpu.model.name,
+            });
+            log.err("  Supported feature Set: ", .{});
+            const all_features = whitelist_cpu.arch.allFeaturesList();
+            var populated_cpu_features = whitelist_cpu.model.features;
+            populated_cpu_features.populateDependencies(all_features);
+            for (all_features) |feature, i_usize| {
+                const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize);
+                const in_cpu_set = populated_cpu_features.isEnabled(i);
+                if (in_cpu_set) {
+                    log.err("{s} ", .{feature.name});
+                }
+            }
+            log.err("  Remove: ", .{});
+            for (all_features) |feature, i_usize| {
+                const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize);
+                const in_cpu_set = populated_cpu_features.isEnabled(i);
+                const in_actual_set = selected_cpu.features.isEnabled(i);
+                if (in_actual_set and !in_cpu_set) {
+                    log.err("{s} ", .{feature.name});
+                }
+            }
+        }
+        self.markInvalidUserInput();
+        return args.default_target;
+    }
+
+    return selected_target;
+}
+
+pub fn addUserInputOption(self: *Build, name_raw: []const u8, value_raw: []const u8) !bool {
+    const name = self.dupe(name_raw);
+    const value = self.dupe(value_raw);
+    const gop = try self.user_input_options.getOrPut(name);
+    if (!gop.found_existing) {
+        gop.value_ptr.* = UserInputOption{
+            .name = name,
+            .value = .{ .scalar = value },
+            .used = false,
+        };
+        return false;
+    }
+
+    // option already exists
+    switch (gop.value_ptr.value) {
+        .scalar => |s| {
+            // turn it into a list
+            var list = ArrayList([]const u8).init(self.allocator);
+            list.append(s) catch unreachable;
+            list.append(value) catch unreachable;
+            self.user_input_options.put(name, .{
+                .name = name,
+                .value = .{ .list = list },
+                .used = false,
+            }) catch unreachable;
+        },
+        .list => |*list| {
+            // append to the list
+            list.append(value) catch unreachable;
+            self.user_input_options.put(name, .{
+                .name = name,
+                .value = .{ .list = list.* },
+                .used = false,
+            }) catch unreachable;
+        },
+        .flag => {
+            log.warn("Option '-D{s}={s}' conflicts with flag '-D{s}'.", .{ name, value, name });
+            return true;
+        },
+        .map => |*map| {
+            _ = map;
+            log.warn("TODO maps as command line arguments is not implemented yet.", .{});
+            return true;
+        },
+    }
+    return false;
+}
+
+pub fn addUserInputFlag(self: *Build, name_raw: []const u8) !bool {
+    const name = self.dupe(name_raw);
+    const gop = try self.user_input_options.getOrPut(name);
+    if (!gop.found_existing) {
+        gop.value_ptr.* = .{
+            .name = name,
+            .value = .{ .flag = {} },
+            .used = false,
+        };
+        return false;
+    }
+
+    // option already exists
+    switch (gop.value_ptr.value) {
+        .scalar => |s| {
+            log.err("Flag '-D{s}' conflicts with option '-D{s}={s}'.", .{ name, name, s });
+            return true;
+        },
+        .list, .map => {
+            log.err("Flag '-D{s}' conflicts with multiple options of the same name.", .{name});
+            return true;
+        },
+        .flag => {},
+    }
+    return false;
+}
+
+fn typeToEnum(comptime T: type) TypeId {
+    return switch (@typeInfo(T)) {
+        .Int => .int,
+        .Float => .float,
+        .Bool => .bool,
+        .Enum => .@"enum",
+        else => switch (T) {
+            []const u8 => .string,
+            []const []const u8 => .list,
+            else => @compileError("Unsupported type: " ++ @typeName(T)),
+        },
+    };
+}
+
+fn markInvalidUserInput(self: *Build) void {
+    self.invalid_user_input = true;
+}
+
+pub fn validateUserInputDidItFail(self: *Build) bool {
+    // make sure all args are used
+    var it = self.user_input_options.iterator();
+    while (it.next()) |entry| {
+        if (!entry.value_ptr.used) {
+            log.err("Invalid option: -D{s}", .{entry.key_ptr.*});
+            self.markInvalidUserInput();
+        }
+    }
+
+    return self.invalid_user_input;
+}
+
+pub fn spawnChild(self: *Build, argv: []const []const u8) !void {
+    return self.spawnChildEnvMap(null, self.env_map, argv);
+}
+
+fn printCmd(cwd: ?[]const u8, argv: []const []const u8) void {
+    if (cwd) |yes_cwd| std.debug.print("cd {s} && ", .{yes_cwd});
+    for (argv) |arg| {
+        std.debug.print("{s} ", .{arg});
+    }
+    std.debug.print("\n", .{});
+}
+
+pub fn spawnChildEnvMap(self: *Build, cwd: ?[]const u8, env_map: *const EnvMap, argv: []const []const u8) !void {
+    if (self.verbose) {
+        printCmd(cwd, argv);
+    }
+
+    if (!std.process.can_spawn)
+        return error.ExecNotSupported;
+
+    var child = std.ChildProcess.init(argv, self.allocator);
+    child.cwd = cwd;
+    child.env_map = env_map;
+
+    const term = child.spawnAndWait() catch |err| {
+        log.err("Unable to spawn {s}: {s}", .{ argv[0], @errorName(err) });
+        return err;
+    };
+
+    switch (term) {
+        .Exited => |code| {
+            if (code != 0) {
+                log.err("The following command exited with error code {}:", .{code});
+                printCmd(cwd, argv);
+                return error.UncleanExit;
+            }
+        },
+        else => {
+            log.err("The following command terminated unexpectedly:", .{});
+            printCmd(cwd, argv);
+
+            return error.UncleanExit;
+        },
+    }
+}
+
+pub fn makePath(self: *Build, path: []const u8) !void {
+    fs.cwd().makePath(self.pathFromRoot(path)) catch |err| {
+        log.err("Unable to create path {s}: {s}", .{ path, @errorName(err) });
+        return err;
+    };
+}
+
+pub fn installArtifact(self: *Build, artifact: *LibExeObjStep) void {
+    self.getInstallStep().dependOn(&self.addInstallArtifact(artifact).step);
+}
+
+pub fn addInstallArtifact(self: *Build, artifact: *LibExeObjStep) *InstallArtifactStep {
+    return InstallArtifactStep.create(self, artifact);
+}
+
+///`dest_rel_path` is relative to prefix path
+pub fn installFile(self: *Build, src_path: []const u8, dest_rel_path: []const u8) void {
+    self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .prefix, dest_rel_path).step);
+}
+
+pub fn installDirectory(self: *Build, options: InstallDirectoryOptions) void {
+    self.getInstallStep().dependOn(&self.addInstallDirectory(options).step);
+}
+
+///`dest_rel_path` is relative to bin path
+pub fn installBinFile(self: *Build, src_path: []const u8, dest_rel_path: []const u8) void {
+    self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .bin, dest_rel_path).step);
+}
+
+///`dest_rel_path` is relative to lib path
+pub fn installLibFile(self: *Build, src_path: []const u8, dest_rel_path: []const u8) void {
+    self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .lib, dest_rel_path).step);
+}
+
+/// Output format (BIN vs Intel HEX) determined by filename
+pub fn installRaw(self: *Build, artifact: *LibExeObjStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep {
+    const raw = self.addInstallRaw(artifact, dest_filename, options);
+    self.getInstallStep().dependOn(&raw.step);
+    return raw;
+}
+
+///`dest_rel_path` is relative to install prefix path
+pub fn addInstallFile(self: *Build, source: FileSource, dest_rel_path: []const u8) *InstallFileStep {
+    return self.addInstallFileWithDir(source.dupe(self), .prefix, dest_rel_path);
+}
+
+///`dest_rel_path` is relative to bin path
+pub fn addInstallBinFile(self: *Build, source: FileSource, dest_rel_path: []const u8) *InstallFileStep {
+    return self.addInstallFileWithDir(source.dupe(self), .bin, dest_rel_path);
+}
+
+///`dest_rel_path` is relative to lib path
+pub fn addInstallLibFile(self: *Build, source: FileSource, dest_rel_path: []const u8) *InstallFileStep {
+    return self.addInstallFileWithDir(source.dupe(self), .lib, dest_rel_path);
+}
+
+pub fn addInstallHeaderFile(b: *Build, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep {
+    return b.addInstallFileWithDir(.{ .path = src_path }, .header, dest_rel_path);
+}
+
+pub fn addInstallRaw(self: *Build, artifact: *LibExeObjStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep {
+    return InstallRawStep.create(self, artifact, dest_filename, options);
+}
+
+pub fn addInstallFileWithDir(
+    self: *Build,
+    source: FileSource,
+    install_dir: InstallDir,
+    dest_rel_path: []const u8,
+) *InstallFileStep {
+    if (dest_rel_path.len == 0) {
+        panic("dest_rel_path must be non-empty", .{});
+    }
+    const install_step = self.allocator.create(InstallFileStep) catch unreachable;
+    install_step.* = InstallFileStep.init(self, source.dupe(self), install_dir, dest_rel_path);
+    return install_step;
+}
+
+pub fn addInstallDirectory(self: *Build, options: InstallDirectoryOptions) *InstallDirStep {
+    const install_step = self.allocator.create(InstallDirStep) catch unreachable;
+    install_step.* = InstallDirStep.init(self, options);
+    return install_step;
+}
+
+pub fn pushInstalledFile(self: *Build, dir: InstallDir, dest_rel_path: []const u8) void {
+    const file = InstalledFile{
+        .dir = dir,
+        .path = dest_rel_path,
+    };
+    self.installed_files.append(file.dupe(self)) catch unreachable;
+}
+
+pub fn updateFile(self: *Build, source_path: []const u8, dest_path: []const u8) !void {
+    if (self.verbose) {
+        log.info("cp {s} {s} ", .{ source_path, dest_path });
+    }
+    const cwd = fs.cwd();
+    const prev_status = try fs.Dir.updateFile(cwd, source_path, cwd, dest_path, .{});
+    if (self.verbose) switch (prev_status) {
+        .stale => log.info("# installed", .{}),
+        .fresh => log.info("# up-to-date", .{}),
+    };
+}
+
+pub fn truncateFile(self: *Build, dest_path: []const u8) !void {
+    if (self.verbose) {
+        log.info("truncate {s}", .{dest_path});
+    }
+    const cwd = fs.cwd();
+    var src_file = cwd.createFile(dest_path, .{}) catch |err| switch (err) {
+        error.FileNotFound => blk: {
+            if (fs.path.dirname(dest_path)) |dirname| {
+                try cwd.makePath(dirname);
+            }
+            break :blk try cwd.createFile(dest_path, .{});
+        },
+        else => |e| return e,
+    };
+    src_file.close();
+}
+
+pub fn pathFromRoot(self: *Build, rel_path: []const u8) []u8 {
+    return fs.path.resolve(self.allocator, &[_][]const u8{ self.build_root, rel_path }) catch unreachable;
+}
+
+/// Shorthand for `std.fs.path.join(Build.allocator, paths) catch unreachable`
+pub fn pathJoin(self: *Build, paths: []const []const u8) []u8 {
+    return fs.path.join(self.allocator, paths) catch unreachable;
+}
+
+pub fn fmt(self: *Build, comptime format: []const u8, args: anytype) []u8 {
+    return fmt_lib.allocPrint(self.allocator, format, args) catch unreachable;
+}
+
+pub fn findProgram(self: *Build, names: []const []const u8, paths: []const []const u8) ![]const u8 {
+    // TODO report error for ambiguous situations
+    const exe_extension = @as(CrossTarget, .{}).exeFileExt();
+    for (self.search_prefixes.items) |search_prefix| {
+        for (names) |name| {
+            if (fs.path.isAbsolute(name)) {
+                return name;
+            }
+            const full_path = self.pathJoin(&.{
+                search_prefix,
+                "bin",
+                self.fmt("{s}{s}", .{ name, exe_extension }),
+            });
+            return fs.realpathAlloc(self.allocator, full_path) catch continue;
+        }
+    }
+    if (self.env_map.get("PATH")) |PATH| {
+        for (names) |name| {
+            if (fs.path.isAbsolute(name)) {
+                return name;
+            }
+            var it = mem.tokenize(u8, PATH, &[_]u8{fs.path.delimiter});
+            while (it.next()) |path| {
+                const full_path = self.pathJoin(&.{
+                    path,
+                    self.fmt("{s}{s}", .{ name, exe_extension }),
+                });
+                return fs.realpathAlloc(self.allocator, full_path) catch continue;
+            }
+        }
+    }
+    for (names) |name| {
+        if (fs.path.isAbsolute(name)) {
+            return name;
+        }
+        for (paths) |path| {
+            const full_path = self.pathJoin(&.{
+                path,
+                self.fmt("{s}{s}", .{ name, exe_extension }),
+            });
+            return fs.realpathAlloc(self.allocator, full_path) catch continue;
+        }
+    }
+    return error.FileNotFound;
+}
+
+pub fn execAllowFail(
+    self: *Build,
+    argv: []const []const u8,
+    out_code: *u8,
+    stderr_behavior: std.ChildProcess.StdIo,
+) ExecError![]u8 {
+    assert(argv.len != 0);
+
+    if (!std.process.can_spawn)
+        return error.ExecNotSupported;
+
+    const max_output_size = 400 * 1024;
+    var child = std.ChildProcess.init(argv, self.allocator);
+    child.stdin_behavior = .Ignore;
+    child.stdout_behavior = .Pipe;
+    child.stderr_behavior = stderr_behavior;
+    child.env_map = self.env_map;
+
+    try child.spawn();
+
+    const stdout = child.stdout.?.reader().readAllAlloc(self.allocator, max_output_size) catch {
+        return error.ReadFailure;
+    };
+    errdefer self.allocator.free(stdout);
+
+    const term = try child.wait();
+    switch (term) {
+        .Exited => |code| {
+            if (code != 0) {
+                out_code.* = @truncate(u8, code);
+                return error.ExitCodeFailure;
+            }
+            return stdout;
+        },
+        .Signal, .Stopped, .Unknown => |code| {
+            out_code.* = @truncate(u8, code);
+            return error.ProcessTerminated;
+        },
+    }
+}
+
+pub fn execFromStep(self: *Build, argv: []const []const u8, src_step: ?*Step) ![]u8 {
+    assert(argv.len != 0);
+
+    if (self.verbose) {
+        printCmd(null, argv);
+    }
+
+    if (!std.process.can_spawn) {
+        if (src_step) |s| log.err("{s}...", .{s.name});
+        log.err("Unable to spawn the following command: cannot spawn child process", .{});
+        printCmd(null, argv);
+        std.os.abort();
+    }
+
+    var code: u8 = undefined;
+    return self.execAllowFail(argv, &code, .Inherit) catch |err| switch (err) {
+        error.ExecNotSupported => {
+            if (src_step) |s| log.err("{s}...", .{s.name});
+            log.err("Unable to spawn the following command: cannot spawn child process", .{});
+            printCmd(null, argv);
+            std.os.abort();
+        },
+        error.FileNotFound => {
+            if (src_step) |s| log.err("{s}...", .{s.name});
+            log.err("Unable to spawn the following command: file not found", .{});
+            printCmd(null, argv);
+            std.os.exit(@truncate(u8, code));
+        },
+        error.ExitCodeFailure => {
+            if (src_step) |s| log.err("{s}...", .{s.name});
+            if (self.prominent_compile_errors) {
+                log.err("The step exited with error code {d}", .{code});
+            } else {
+                log.err("The following command exited with error code {d}:", .{code});
+                printCmd(null, argv);
+            }
+
+            std.os.exit(@truncate(u8, code));
+        },
+        error.ProcessTerminated => {
+            if (src_step) |s| log.err("{s}...", .{s.name});
+            log.err("The following command terminated unexpectedly:", .{});
+            printCmd(null, argv);
+            std.os.exit(@truncate(u8, code));
+        },
+        else => |e| return e,
+    };
+}
+
+pub fn exec(self: *Build, argv: []const []const u8) ![]u8 {
+    return self.execFromStep(argv, null);
+}
+
+pub fn addSearchPrefix(self: *Build, search_prefix: []const u8) void {
+    self.search_prefixes.append(self.dupePath(search_prefix)) catch unreachable;
+}
+
+pub fn getInstallPath(self: *Build, dir: InstallDir, dest_rel_path: []const u8) []const u8 {
+    assert(!fs.path.isAbsolute(dest_rel_path)); // Install paths must be relative to the prefix
+    const base_dir = switch (dir) {
+        .prefix => self.install_path,
+        .bin => self.exe_dir,
+        .lib => self.lib_dir,
+        .header => self.h_dir,
+        .custom => |path| self.pathJoin(&.{ self.install_path, path }),
+    };
+    return fs.path.resolve(
+        self.allocator,
+        &[_][]const u8{ base_dir, dest_rel_path },
+    ) catch unreachable;
+}
+
+pub const Dependency = struct {
+    builder: *Build,
+
+    pub fn artifact(d: *Dependency, name: []const u8) *LibExeObjStep {
+        var found: ?*LibExeObjStep = null;
+        for (d.builder.install_tls.step.dependencies.items) |dep_step| {
+            const inst = dep_step.cast(InstallArtifactStep) orelse continue;
+            if (mem.eql(u8, inst.artifact.name, name)) {
+                if (found != null) panic("artifact name '{s}' is ambiguous", .{name});
+                found = inst.artifact;
+            }
+        }
+        return found orelse {
+            for (d.builder.install_tls.step.dependencies.items) |dep_step| {
+                const inst = dep_step.cast(InstallArtifactStep) orelse continue;
+                log.info("available artifact: '{s}'", .{inst.artifact.name});
+            }
+            panic("unable to find artifact '{s}'", .{name});
+        };
+    }
+};
+
+pub fn dependency(b: *Build, name: []const u8, args: anytype) *Dependency {
+    const build_runner = @import("root");
+    const deps = build_runner.dependencies;
+
+    inline for (@typeInfo(deps.imports).Struct.decls) |decl| {
+        if (mem.startsWith(u8, decl.name, b.dep_prefix) and
+            mem.endsWith(u8, decl.name, name) and
+            decl.name.len == b.dep_prefix.len + name.len)
+        {
+            const build_zig = @field(deps.imports, decl.name);
+            const build_root = @field(deps.build_root, decl.name);
+            return dependencyInner(b, name, build_root, build_zig, args);
+        }
+    }
+
+    const full_path = b.pathFromRoot("build.zig.ini");
+    std.debug.print("no dependency named '{s}' in '{s}'\n", .{ name, full_path });
+    std.process.exit(1);
+}
+
+fn dependencyInner(
+    b: *Build,
+    name: []const u8,
+    build_root: []const u8,
+    comptime build_zig: type,
+    args: anytype,
+) *Dependency {
+    const sub_builder = b.createChild(name, build_root, args) catch unreachable;
+    sub_builder.runBuild(build_zig) catch unreachable;
+
+    if (sub_builder.validateUserInputDidItFail()) {
+        std.debug.dumpCurrentStackTrace(@returnAddress());
+    }
+
+    const dep = b.allocator.create(Dependency) catch unreachable;
+    dep.* = .{ .builder = sub_builder };
+    return dep;
+}
+
+pub fn runBuild(b: *Build, build_zig: anytype) anyerror!void {
+    switch (@typeInfo(@typeInfo(@TypeOf(build_zig.build)).Fn.return_type.?)) {
+        .Void => build_zig.build(b),
+        .ErrorUnion => try build_zig.build(b),
+        else => @compileError("expected return type of build to be 'void' or '!void'"),
+    }
+}
+
+test "builder.findProgram compiles" {
+    if (builtin.os.tag == .wasi) return error.SkipZigTest;
+
+    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
+    defer arena.deinit();
+
+    const builder = try Build.create(
+        arena.allocator(),
+        "zig",
+        "zig-cache",
+        "zig-cache",
+        "zig-cache",
+    );
+    defer builder.destroy();
+    _ = builder.findProgram(&[_][]const u8{}, &[_][]const u8{}) catch null;
+}
+
+pub const Pkg = struct {
+    name: []const u8,
+    source: FileSource,
+    dependencies: ?[]const Pkg = null,
+};
+
+/// A file that is generated by a build step.
+/// This struct is an interface that is meant to be used with `@fieldParentPtr` to implement the actual path logic.
+pub const GeneratedFile = struct {
+    /// The step that generates the file
+    step: *Step,
+
+    /// The path to the generated file. Must be either absolute or relative to the build root.
+    /// This value must be set in the `fn make()` of the `step` and must not be `null` afterwards.
+    path: ?[]const u8 = null,
+
+    pub fn getPath(self: GeneratedFile) []const u8 {
+        return self.path orelse std.debug.panic(
+            "getPath() was called on a GeneratedFile that wasn't build yet. Is there a missing Step dependency on step '{s}'?",
+            .{self.step.name},
+        );
+    }
+};
+
+/// A file source is a reference to an existing or future file.
+///
+pub const FileSource = union(enum) {
+    /// A plain file path, relative to build root or absolute.
+    path: []const u8,
+
+    /// A file that is generated by an interface. Those files usually are
+    /// not available until built by a build step.
+    generated: *const GeneratedFile,
+
+    /// Returns a new file source that will have a relative path to the build root guaranteed.
+    /// This should be preferred over setting `.path` directly as it documents that the files are in the project directory.
+    pub fn relative(path: []const u8) FileSource {
+        std.debug.assert(!std.fs.path.isAbsolute(path));
+        return FileSource{ .path = path };
+    }
+
+    /// Returns a string that can be shown to represent the file source.
+    /// Either returns the path or `"generated"`.
+    pub fn getDisplayName(self: FileSource) []const u8 {
+        return switch (self) {
+            .path => self.path,
+            .generated => "generated",
+        };
+    }
+
+    /// Adds dependencies this file source implies to the given step.
+    pub fn addStepDependencies(self: FileSource, other_step: *Step) void {
+        switch (self) {
+            .path => {},
+            .generated => |gen| other_step.dependOn(gen.step),
+        }
+    }
+
+    /// Should only be called during make(), returns a path relative to the build root or absolute.
+    pub fn getPath(self: FileSource, builder: *Build) []const u8 {
+        const path = switch (self) {
+            .path => |p| builder.pathFromRoot(p),
+            .generated => |gen| gen.getPath(),
+        };
+        return path;
+    }
+
+    /// Duplicates the file source for a given builder.
+    pub fn dupe(self: FileSource, b: *Build) FileSource {
+        return switch (self) {
+            .path => |p| .{ .path = b.dupePath(p) },
+            .generated => |gen| .{ .generated = gen },
+        };
+    }
+};
+
+/// Allocates a new string for assigning a value to a named macro.
+/// If the value is omitted, it is set to 1.
+/// `name` and `value` need not live longer than the function call.
+pub fn constructCMacro(allocator: Allocator, name: []const u8, value: ?[]const u8) []const u8 {
+    var macro = allocator.alloc(
+        u8,
+        name.len + if (value) |value_slice| value_slice.len + 1 else 0,
+    ) catch |err| if (err == error.OutOfMemory) @panic("Out of memory") else unreachable;
+    mem.copy(u8, macro, name);
+    if (value) |value_slice| {
+        macro[name.len] = '=';
+        mem.copy(u8, macro[name.len + 1 ..], value_slice);
+    }
+    return macro;
+}
+
+/// deprecated: use `InstallDirStep.Options`
+pub const InstallDirectoryOptions = InstallDirStep.Options;
+
+pub const VcpkgRoot = union(VcpkgRootStatus) {
+    unattempted: void,
+    not_found: void,
+    found: []const u8,
+};
+
+pub const VcpkgRootStatus = enum {
+    unattempted,
+    not_found,
+    found,
+};
+
+pub const InstallDir = union(enum) {
+    prefix: void,
+    lib: void,
+    bin: void,
+    header: void,
+    /// A path relative to the prefix
+    custom: []const u8,
+
+    /// Duplicates the install directory including the path if set to custom.
+    pub fn dupe(self: InstallDir, builder: *Build) InstallDir {
+        if (self == .custom) {
+            // Written with this temporary to avoid RLS problems
+            const duped_path = builder.dupe(self.custom);
+            return .{ .custom = duped_path };
+        } else {
+            return self;
+        }
+    }
+};
+
+pub const InstalledFile = struct {
+    dir: InstallDir,
+    path: []const u8,
+
+    /// Duplicates the installed file path and directory.
+    pub fn dupe(self: InstalledFile, builder: *Build) InstalledFile {
+        return .{
+            .dir = self.dir.dupe(builder),
+            .path = builder.dupe(self.path),
+        };
+    }
+};
+
+pub fn serializeCpu(allocator: Allocator, cpu: std.Target.Cpu) ![]const u8 {
+    // TODO this logic can disappear if cpu model + features becomes part of the target triple
+    const all_features = cpu.arch.allFeaturesList();
+    var populated_cpu_features = cpu.model.features;
+    populated_cpu_features.populateDependencies(all_features);
+
+    if (populated_cpu_features.eql(cpu.features)) {
+        // The CPU name alone is sufficient.
+        return cpu.model.name;
+    } else {
+        var mcpu_buffer = ArrayList(u8).init(allocator);
+        try mcpu_buffer.appendSlice(cpu.model.name);
+
+        for (all_features) |feature, i_usize| {
+            const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize);
+            const in_cpu_set = populated_cpu_features.isEnabled(i);
+            const in_actual_set = cpu.features.isEnabled(i);
+            if (in_cpu_set and !in_actual_set) {
+                try mcpu_buffer.writer().print("-{s}", .{feature.name});
+            } else if (!in_cpu_set and in_actual_set) {
+                try mcpu_buffer.writer().print("+{s}", .{feature.name});
+            }
+        }
+
+        return try mcpu_buffer.toOwnedSlice();
+    }
+}
+
+test "dupePkg()" {
+    if (builtin.os.tag == .wasi) return error.SkipZigTest;
+
+    var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
+    defer arena.deinit();
+    var builder = try Build.create(
+        arena.allocator(),
+        "test",
+        "test",
+        "test",
+        "test",
+    );
+    defer builder.destroy();
+
+    var pkg_dep = Pkg{
+        .name = "pkg_dep",
+        .source = .{ .path = "/not/a/pkg_dep.zig" },
+    };
+    var pkg_top = Pkg{
+        .name = "pkg_top",
+        .source = .{ .path = "/not/a/pkg_top.zig" },
+        .dependencies = &[_]Pkg{pkg_dep},
+    };
+    const duped = builder.dupePkg(pkg_top);
+
+    const original_deps = pkg_top.dependencies.?;
+    const dupe_deps = duped.dependencies.?;
+
+    // probably the same top level package details
+    try std.testing.expectEqualStrings(pkg_top.name, duped.name);
+
+    // probably the same dependencies
+    try std.testing.expectEqual(original_deps.len, dupe_deps.len);
+    try std.testing.expectEqual(original_deps[0].name, pkg_dep.name);
+
+    // could segfault otherwise if pointers in duplicated package's fields are
+    // the same as those in stack allocated package's fields
+    try std.testing.expect(dupe_deps.ptr != original_deps.ptr);
+    try std.testing.expect(duped.name.ptr != pkg_top.name.ptr);
+    try std.testing.expect(duped.source.path.ptr != pkg_top.source.path.ptr);
+    try std.testing.expect(dupe_deps[0].name.ptr != pkg_dep.name.ptr);
+    try std.testing.expect(dupe_deps[0].source.path.ptr != pkg_dep.source.path.ptr);
+}
+
+test {
+    _ = CheckFileStep;
+    _ = CheckObjectStep;
+    _ = EmulatableRunStep;
+    _ = FmtStep;
+    _ = InstallArtifactStep;
+    _ = InstallDirStep;
+    _ = InstallFileStep;
+    _ = InstallRawStep;
+    _ = LibExeObjStep;
+    _ = LogStep;
+    _ = OptionsStep;
+    _ = RemoveDirStep;
+    _ = RunStep;
+    _ = TranslateCStep;
+    _ = WriteFileStep;
+}
lib/std/build.zig
@@ -1,1863 +0,0 @@
-const std = @import("std.zig");
-const builtin = @import("builtin");
-const io = std.io;
-const fs = std.fs;
-const mem = std.mem;
-const debug = std.debug;
-const panic = std.debug.panic;
-const assert = debug.assert;
-const log = std.log;
-const ArrayList = std.ArrayList;
-const StringHashMap = std.StringHashMap;
-const Allocator = mem.Allocator;
-const process = std.process;
-const EnvMap = std.process.EnvMap;
-const fmt_lib = std.fmt;
-const File = std.fs.File;
-const CrossTarget = std.zig.CrossTarget;
-const NativeTargetInfo = std.zig.system.NativeTargetInfo;
-const Sha256 = std.crypto.hash.sha2.Sha256;
-const ThisModule = @This();
-
-pub const CheckFileStep = @import("build/CheckFileStep.zig");
-pub const CheckObjectStep = @import("build/CheckObjectStep.zig");
-pub const ConfigHeaderStep = @import("build/ConfigHeaderStep.zig");
-pub const EmulatableRunStep = @import("build/EmulatableRunStep.zig");
-pub const FmtStep = @import("build/FmtStep.zig");
-pub const InstallArtifactStep = @import("build/InstallArtifactStep.zig");
-pub const InstallDirStep = @import("build/InstallDirStep.zig");
-pub const InstallFileStep = @import("build/InstallFileStep.zig");
-pub const InstallRawStep = @import("build/InstallRawStep.zig");
-pub const LibExeObjStep = @import("build/LibExeObjStep.zig");
-pub const LogStep = @import("build/LogStep.zig");
-pub const OptionsStep = @import("build/OptionsStep.zig");
-pub const RemoveDirStep = @import("build/RemoveDirStep.zig");
-pub const RunStep = @import("build/RunStep.zig");
-pub const TranslateCStep = @import("build/TranslateCStep.zig");
-pub const WriteFileStep = @import("build/WriteFileStep.zig");
-
-pub const Builder = struct {
-    install_tls: TopLevelStep,
-    uninstall_tls: TopLevelStep,
-    allocator: Allocator,
-    user_input_options: UserInputOptionsMap,
-    available_options_map: AvailableOptionsMap,
-    available_options_list: ArrayList(AvailableOption),
-    verbose: bool,
-    verbose_link: bool,
-    verbose_cc: bool,
-    verbose_air: bool,
-    verbose_llvm_ir: bool,
-    verbose_cimport: bool,
-    verbose_llvm_cpu_features: bool,
-    /// The purpose of executing the command is for a human to read compile errors from the terminal
-    prominent_compile_errors: bool,
-    color: enum { auto, on, off } = .auto,
-    reference_trace: ?u32 = null,
-    invalid_user_input: bool,
-    zig_exe: []const u8,
-    default_step: *Step,
-    env_map: *EnvMap,
-    top_level_steps: ArrayList(*TopLevelStep),
-    install_prefix: []const u8,
-    dest_dir: ?[]const u8,
-    lib_dir: []const u8,
-    exe_dir: []const u8,
-    h_dir: []const u8,
-    install_path: []const u8,
-    sysroot: ?[]const u8 = null,
-    search_prefixes: ArrayList([]const u8),
-    libc_file: ?[]const u8 = null,
-    installed_files: ArrayList(InstalledFile),
-    /// Path to the directory containing build.zig.
-    build_root: []const u8,
-    cache_root: []const u8,
-    global_cache_root: []const u8,
-    /// zig lib dir
-    override_lib_dir: ?[]const u8,
-    vcpkg_root: VcpkgRoot = .unattempted,
-    pkg_config_pkg_list: ?(PkgConfigError![]const PkgConfigPkg) = null,
-    args: ?[][]const u8 = null,
-    debug_log_scopes: []const []const u8 = &.{},
-    debug_compile_errors: bool = false,
-
-    /// Experimental. Use system Darling installation to run cross compiled macOS build artifacts.
-    enable_darling: bool = false,
-    /// Use system QEMU installation to run cross compiled foreign architecture build artifacts.
-    enable_qemu: bool = false,
-    /// Darwin. Use Rosetta to run x86_64 macOS build artifacts on arm64 macOS.
-    enable_rosetta: bool = false,
-    /// Use system Wasmtime installation to run cross compiled wasm/wasi build artifacts.
-    enable_wasmtime: bool = false,
-    /// Use system Wine installation to run cross compiled Windows build artifacts.
-    enable_wine: bool = false,
-    /// After following the steps in https://github.com/ziglang/zig/wiki/Updating-libc#glibc,
-    /// this will be the directory $glibc-build-dir/install/glibcs
-    /// Given the example of the aarch64 target, this is the directory
-    /// that contains the path `aarch64-linux-gnu/lib/ld-linux-aarch64.so.1`.
-    glibc_runtimes_dir: ?[]const u8 = null,
-
-    /// Information about the native target. Computed before build() is invoked.
-    host: NativeTargetInfo,
-
-    dep_prefix: []const u8 = "",
-
-    pub const ExecError = error{
-        ReadFailure,
-        ExitCodeFailure,
-        ProcessTerminated,
-        ExecNotSupported,
-    } || std.ChildProcess.SpawnError;
-
-    pub const PkgConfigError = error{
-        PkgConfigCrashed,
-        PkgConfigFailed,
-        PkgConfigNotInstalled,
-        PkgConfigInvalidOutput,
-    };
-
-    pub const PkgConfigPkg = struct {
-        name: []const u8,
-        desc: []const u8,
-    };
-
-    pub const CStd = enum {
-        C89,
-        C99,
-        C11,
-    };
-
-    const UserInputOptionsMap = StringHashMap(UserInputOption);
-    const AvailableOptionsMap = StringHashMap(AvailableOption);
-
-    const AvailableOption = struct {
-        name: []const u8,
-        type_id: TypeId,
-        description: []const u8,
-        /// If the `type_id` is `enum` this provides the list of enum options
-        enum_options: ?[]const []const u8,
-    };
-
-    const UserInputOption = struct {
-        name: []const u8,
-        value: UserValue,
-        used: bool,
-    };
-
-    const UserValue = union(enum) {
-        flag: void,
-        scalar: []const u8,
-        list: ArrayList([]const u8),
-        map: StringHashMap(*const UserValue),
-    };
-
-    const TypeId = enum {
-        bool,
-        int,
-        float,
-        @"enum",
-        string,
-        list,
-    };
-
-    const TopLevelStep = struct {
-        pub const base_id = .top_level;
-
-        step: Step,
-        description: []const u8,
-    };
-
-    pub const DirList = struct {
-        lib_dir: ?[]const u8 = null,
-        exe_dir: ?[]const u8 = null,
-        include_dir: ?[]const u8 = null,
-    };
-
-    pub fn create(
-        allocator: Allocator,
-        zig_exe: []const u8,
-        build_root: []const u8,
-        cache_root: []const u8,
-        global_cache_root: []const u8,
-    ) !*Builder {
-        const env_map = try allocator.create(EnvMap);
-        env_map.* = try process.getEnvMap(allocator);
-
-        const host = try NativeTargetInfo.detect(.{});
-
-        const self = try allocator.create(Builder);
-        self.* = Builder{
-            .zig_exe = zig_exe,
-            .build_root = build_root,
-            .cache_root = try fs.path.relative(allocator, build_root, cache_root),
-            .global_cache_root = global_cache_root,
-            .verbose = false,
-            .verbose_link = false,
-            .verbose_cc = false,
-            .verbose_air = false,
-            .verbose_llvm_ir = false,
-            .verbose_cimport = false,
-            .verbose_llvm_cpu_features = false,
-            .prominent_compile_errors = false,
-            .invalid_user_input = false,
-            .allocator = allocator,
-            .user_input_options = UserInputOptionsMap.init(allocator),
-            .available_options_map = AvailableOptionsMap.init(allocator),
-            .available_options_list = ArrayList(AvailableOption).init(allocator),
-            .top_level_steps = ArrayList(*TopLevelStep).init(allocator),
-            .default_step = undefined,
-            .env_map = env_map,
-            .search_prefixes = ArrayList([]const u8).init(allocator),
-            .install_prefix = undefined,
-            .lib_dir = undefined,
-            .exe_dir = undefined,
-            .h_dir = undefined,
-            .dest_dir = env_map.get("DESTDIR"),
-            .installed_files = ArrayList(InstalledFile).init(allocator),
-            .install_tls = TopLevelStep{
-                .step = Step.initNoOp(.top_level, "install", allocator),
-                .description = "Copy build artifacts to prefix path",
-            },
-            .uninstall_tls = TopLevelStep{
-                .step = Step.init(.top_level, "uninstall", allocator, makeUninstall),
-                .description = "Remove build artifacts from prefix path",
-            },
-            .override_lib_dir = null,
-            .install_path = undefined,
-            .args = null,
-            .host = host,
-        };
-        try self.top_level_steps.append(&self.install_tls);
-        try self.top_level_steps.append(&self.uninstall_tls);
-        self.default_step = &self.install_tls.step;
-        return self;
-    }
-
-    fn createChild(
-        parent: *Builder,
-        dep_name: []const u8,
-        build_root: []const u8,
-        args: anytype,
-    ) !*Builder {
-        const child = try createChildOnly(parent, dep_name, build_root);
-        try applyArgs(child, args);
-        return child;
-    }
-
-    fn createChildOnly(parent: *Builder, dep_name: []const u8, build_root: []const u8) !*Builder {
-        const allocator = parent.allocator;
-        const child = try allocator.create(Builder);
-        child.* = .{
-            .allocator = allocator,
-            .install_tls = .{
-                .step = Step.initNoOp(.top_level, "install", allocator),
-                .description = "Copy build artifacts to prefix path",
-            },
-            .uninstall_tls = .{
-                .step = Step.init(.top_level, "uninstall", allocator, makeUninstall),
-                .description = "Remove build artifacts from prefix path",
-            },
-            .user_input_options = UserInputOptionsMap.init(allocator),
-            .available_options_map = AvailableOptionsMap.init(allocator),
-            .available_options_list = ArrayList(AvailableOption).init(allocator),
-            .verbose = parent.verbose,
-            .verbose_link = parent.verbose_link,
-            .verbose_cc = parent.verbose_cc,
-            .verbose_air = parent.verbose_air,
-            .verbose_llvm_ir = parent.verbose_llvm_ir,
-            .verbose_cimport = parent.verbose_cimport,
-            .verbose_llvm_cpu_features = parent.verbose_llvm_cpu_features,
-            .prominent_compile_errors = parent.prominent_compile_errors,
-            .color = parent.color,
-            .reference_trace = parent.reference_trace,
-            .invalid_user_input = false,
-            .zig_exe = parent.zig_exe,
-            .default_step = undefined,
-            .env_map = parent.env_map,
-            .top_level_steps = ArrayList(*TopLevelStep).init(allocator),
-            .install_prefix = undefined,
-            .dest_dir = parent.dest_dir,
-            .lib_dir = parent.lib_dir,
-            .exe_dir = parent.exe_dir,
-            .h_dir = parent.h_dir,
-            .install_path = parent.install_path,
-            .sysroot = parent.sysroot,
-            .search_prefixes = ArrayList([]const u8).init(allocator),
-            .libc_file = parent.libc_file,
-            .installed_files = ArrayList(InstalledFile).init(allocator),
-            .build_root = build_root,
-            .cache_root = parent.cache_root,
-            .global_cache_root = parent.global_cache_root,
-            .override_lib_dir = parent.override_lib_dir,
-            .debug_log_scopes = parent.debug_log_scopes,
-            .debug_compile_errors = parent.debug_compile_errors,
-            .enable_darling = parent.enable_darling,
-            .enable_qemu = parent.enable_qemu,
-            .enable_rosetta = parent.enable_rosetta,
-            .enable_wasmtime = parent.enable_wasmtime,
-            .enable_wine = parent.enable_wine,
-            .glibc_runtimes_dir = parent.glibc_runtimes_dir,
-            .host = parent.host,
-            .dep_prefix = parent.fmt("{s}{s}.", .{ parent.dep_prefix, dep_name }),
-        };
-        try child.top_level_steps.append(&child.install_tls);
-        try child.top_level_steps.append(&child.uninstall_tls);
-        child.default_step = &child.install_tls.step;
-        return child;
-    }
-
-    fn applyArgs(b: *Builder, args: anytype) !void {
-        inline for (@typeInfo(@TypeOf(args)).Struct.fields) |field| {
-            const v = @field(args, field.name);
-            const T = @TypeOf(v);
-            switch (T) {
-                CrossTarget => {
-                    try b.user_input_options.put(field.name, .{
-                        .name = field.name,
-                        .value = .{ .scalar = try v.zigTriple(b.allocator) },
-                        .used = false,
-                    });
-                    try b.user_input_options.put("cpu", .{
-                        .name = "cpu",
-                        .value = .{ .scalar = try serializeCpu(b.allocator, v.getCpu()) },
-                        .used = false,
-                    });
-                },
-                []const u8 => {
-                    try b.user_input_options.put(field.name, .{
-                        .name = field.name,
-                        .value = .{ .scalar = v },
-                        .used = false,
-                    });
-                },
-                else => switch (@typeInfo(T)) {
-                    .Bool => {
-                        try b.user_input_options.put(field.name, .{
-                            .name = field.name,
-                            .value = .{ .scalar = if (v) "true" else "false" },
-                            .used = false,
-                        });
-                    },
-                    .Enum => {
-                        try b.user_input_options.put(field.name, .{
-                            .name = field.name,
-                            .value = .{ .scalar = @tagName(v) },
-                            .used = false,
-                        });
-                    },
-                    .Int => {
-                        try b.user_input_options.put(field.name, .{
-                            .name = field.name,
-                            .value = .{ .scalar = try std.fmt.allocPrint(b.allocator, "{d}", .{v}) },
-                            .used = false,
-                        });
-                    },
-                    else => @compileError("option '" ++ field.name ++ "' has unsupported type: " ++ @typeName(T)),
-                },
-            }
-        }
-        const Hasher = std.crypto.auth.siphash.SipHash128(1, 3);
-        // Random bytes to make unique. Refresh this with new random bytes when
-        // implementation is modified in a non-backwards-compatible way.
-        var hash = Hasher.init("ZaEsvQ5ClaA2IdH9");
-        hash.update(b.dep_prefix);
-        // TODO additionally update the hash with `args`.
-
-        var digest: [16]u8 = undefined;
-        hash.final(&digest);
-        var hash_basename: [digest.len * 2]u8 = undefined;
-        _ = std.fmt.bufPrint(&hash_basename, "{s}", .{std.fmt.fmtSliceHexLower(&digest)}) catch
-            unreachable;
-
-        const install_prefix = b.pathJoin(&.{ b.cache_root, "i", &hash_basename });
-        b.resolveInstallPrefix(install_prefix, .{});
-    }
-
-    pub fn destroy(self: *Builder) void {
-        self.env_map.deinit();
-        self.top_level_steps.deinit();
-        self.allocator.destroy(self);
-    }
-
-    /// This function is intended to be called by lib/build_runner.zig, not a build.zig file.
-    pub fn resolveInstallPrefix(self: *Builder, install_prefix: ?[]const u8, dir_list: DirList) void {
-        if (self.dest_dir) |dest_dir| {
-            self.install_prefix = install_prefix orelse "/usr";
-            self.install_path = self.pathJoin(&.{ dest_dir, self.install_prefix });
-        } else {
-            self.install_prefix = install_prefix orelse
-                (self.pathJoin(&.{ self.build_root, "zig-out" }));
-            self.install_path = self.install_prefix;
-        }
-
-        var lib_list = [_][]const u8{ self.install_path, "lib" };
-        var exe_list = [_][]const u8{ self.install_path, "bin" };
-        var h_list = [_][]const u8{ self.install_path, "include" };
-
-        if (dir_list.lib_dir) |dir| {
-            if (std.fs.path.isAbsolute(dir)) lib_list[0] = self.dest_dir orelse "";
-            lib_list[1] = dir;
-        }
-
-        if (dir_list.exe_dir) |dir| {
-            if (std.fs.path.isAbsolute(dir)) exe_list[0] = self.dest_dir orelse "";
-            exe_list[1] = dir;
-        }
-
-        if (dir_list.include_dir) |dir| {
-            if (std.fs.path.isAbsolute(dir)) h_list[0] = self.dest_dir orelse "";
-            h_list[1] = dir;
-        }
-
-        self.lib_dir = self.pathJoin(&lib_list);
-        self.exe_dir = self.pathJoin(&exe_list);
-        self.h_dir = self.pathJoin(&h_list);
-    }
-
-    pub fn addOptions(self: *Builder) *OptionsStep {
-        return OptionsStep.create(self);
-    }
-
-    pub const ExecutableOptions = struct {
-        name: []const u8,
-        root_source_file: ?FileSource = null,
-        version: ?std.builtin.Version = null,
-        target: CrossTarget = .{},
-        optimize: std.builtin.Mode = .Debug,
-        linkage: ?LibExeObjStep.Linkage = null,
-    };
-
-    pub fn addExecutable(b: *Builder, options: ExecutableOptions) *LibExeObjStep {
-        return LibExeObjStep.create(b, .{
-            .name = options.name,
-            .root_source_file = options.root_source_file,
-            .version = options.version,
-            .target = options.target,
-            .optimize = options.optimize,
-            .kind = .exe,
-            .linkage = options.linkage,
-        });
-    }
-
-    pub const ObjectOptions = struct {
-        name: []const u8,
-        root_source_file: ?FileSource = null,
-        target: CrossTarget,
-        optimize: std.builtin.Mode,
-    };
-
-    pub fn addObject(b: *Builder, options: ObjectOptions) *LibExeObjStep {
-        return LibExeObjStep.create(b, .{
-            .name = options.name,
-            .root_source_file = options.root_source_file,
-            .target = options.target,
-            .optimize = options.optimize,
-            .kind = .obj,
-        });
-    }
-
-    pub const SharedLibraryOptions = struct {
-        name: []const u8,
-        root_source_file: ?FileSource = null,
-        version: ?std.builtin.Version = null,
-        target: CrossTarget,
-        optimize: std.builtin.Mode,
-    };
-
-    pub fn addSharedLibrary(b: *Builder, options: SharedLibraryOptions) *LibExeObjStep {
-        return LibExeObjStep.create(b, .{
-            .name = options.name,
-            .root_source_file = options.root_source_file,
-            .kind = .lib,
-            .linkage = .dynamic,
-            .version = options.version,
-            .target = options.target,
-            .optimize = options.optimize,
-        });
-    }
-
-    pub const StaticLibraryOptions = struct {
-        name: []const u8,
-        root_source_file: ?FileSource = null,
-        target: CrossTarget,
-        optimize: std.builtin.Mode,
-        version: ?std.builtin.Version = null,
-    };
-
-    pub fn addStaticLibrary(b: *Builder, options: StaticLibraryOptions) *LibExeObjStep {
-        return LibExeObjStep.create(b, .{
-            .name = options.name,
-            .root_source_file = options.root_source_file,
-            .kind = .lib,
-            .linkage = .static,
-            .version = options.version,
-            .target = options.target,
-            .optimize = options.optimize,
-        });
-    }
-
-    pub const TestOptions = struct {
-        name: []const u8 = "test",
-        kind: LibExeObjStep.Kind = .@"test",
-        root_source_file: FileSource,
-        target: CrossTarget = .{},
-        optimize: std.builtin.Mode = .Debug,
-        version: ?std.builtin.Version = null,
-    };
-
-    pub fn addTest(b: *Builder, options: TestOptions) *LibExeObjStep {
-        return LibExeObjStep.create(b, .{
-            .name = options.name,
-            .kind = options.kind,
-            .root_source_file = options.root_source_file,
-            .target = options.target,
-            .optimize = options.optimize,
-        });
-    }
-
-    pub const AssemblyOptions = struct {
-        name: []const u8,
-        source_file: FileSource,
-        target: CrossTarget,
-        optimize: std.builtin.Mode,
-    };
-
-    pub fn addAssembly(b: *Builder, options: AssemblyOptions) *LibExeObjStep {
-        const obj_step = LibExeObjStep.create(b, .{
-            .name = options.name,
-            .root_source_file = null,
-            .target = options.target,
-            .optimize = options.optimize,
-        });
-        obj_step.addAssemblyFileSource(options.source_file.dupe(b));
-        return obj_step;
-    }
-
-    /// Initializes a RunStep with argv, which must at least have the path to the
-    /// executable. More command line arguments can be added with `addArg`,
-    /// `addArgs`, and `addArtifactArg`.
-    /// Be careful using this function, as it introduces a system dependency.
-    /// To run an executable built with zig build, see `LibExeObjStep.run`.
-    pub fn addSystemCommand(self: *Builder, argv: []const []const u8) *RunStep {
-        assert(argv.len >= 1);
-        const run_step = RunStep.create(self, self.fmt("run {s}", .{argv[0]}));
-        run_step.addArgs(argv);
-        return run_step;
-    }
-
-    pub fn addConfigHeader(
-        b: *Builder,
-        source: FileSource,
-        style: ConfigHeaderStep.Style,
-        values: anytype,
-    ) *ConfigHeaderStep {
-        const config_header_step = ConfigHeaderStep.create(b, source, style);
-        config_header_step.addValues(values);
-        return config_header_step;
-    }
-
-    /// Allocator.dupe without the need to handle out of memory.
-    pub fn dupe(self: *Builder, bytes: []const u8) []u8 {
-        return self.allocator.dupe(u8, bytes) catch unreachable;
-    }
-
-    /// Duplicates an array of strings without the need to handle out of memory.
-    pub fn dupeStrings(self: *Builder, strings: []const []const u8) [][]u8 {
-        const array = self.allocator.alloc([]u8, strings.len) catch unreachable;
-        for (strings) |s, i| {
-            array[i] = self.dupe(s);
-        }
-        return array;
-    }
-
-    /// Duplicates a path and converts all slashes to the OS's canonical path separator.
-    pub fn dupePath(self: *Builder, bytes: []const u8) []u8 {
-        const the_copy = self.dupe(bytes);
-        for (the_copy) |*byte| {
-            switch (byte.*) {
-                '/', '\\' => byte.* = fs.path.sep,
-                else => {},
-            }
-        }
-        return the_copy;
-    }
-
-    /// Duplicates a package recursively.
-    pub fn dupePkg(self: *Builder, package: Pkg) Pkg {
-        var the_copy = Pkg{
-            .name = self.dupe(package.name),
-            .source = package.source.dupe(self),
-        };
-
-        if (package.dependencies) |dependencies| {
-            const new_dependencies = self.allocator.alloc(Pkg, dependencies.len) catch unreachable;
-            the_copy.dependencies = new_dependencies;
-
-            for (dependencies) |dep_package, i| {
-                new_dependencies[i] = self.dupePkg(dep_package);
-            }
-        }
-        return the_copy;
-    }
-
-    pub fn addWriteFile(self: *Builder, file_path: []const u8, data: []const u8) *WriteFileStep {
-        const write_file_step = self.addWriteFiles();
-        write_file_step.add(file_path, data);
-        return write_file_step;
-    }
-
-    pub fn addWriteFiles(self: *Builder) *WriteFileStep {
-        const write_file_step = self.allocator.create(WriteFileStep) catch unreachable;
-        write_file_step.* = WriteFileStep.init(self);
-        return write_file_step;
-    }
-
-    pub fn addLog(self: *Builder, comptime format: []const u8, args: anytype) *LogStep {
-        const data = self.fmt(format, args);
-        const log_step = self.allocator.create(LogStep) catch unreachable;
-        log_step.* = LogStep.init(self, data);
-        return log_step;
-    }
-
-    pub fn addRemoveDirTree(self: *Builder, dir_path: []const u8) *RemoveDirStep {
-        const remove_dir_step = self.allocator.create(RemoveDirStep) catch unreachable;
-        remove_dir_step.* = RemoveDirStep.init(self, dir_path);
-        return remove_dir_step;
-    }
-
-    pub fn addFmt(self: *Builder, paths: []const []const u8) *FmtStep {
-        return FmtStep.create(self, paths);
-    }
-
-    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 {
-        try self.makePath(self.cache_root);
-
-        var wanted_steps = ArrayList(*Step).init(self.allocator);
-        defer wanted_steps.deinit();
-
-        if (step_names.len == 0) {
-            try wanted_steps.append(self.default_step);
-        } else {
-            for (step_names) |step_name| {
-                const s = try self.getTopLevelStepByName(step_name);
-                try wanted_steps.append(s);
-            }
-        }
-
-        for (wanted_steps.items) |s| {
-            try self.makeOneStep(s);
-        }
-    }
-
-    pub fn getInstallStep(self: *Builder) *Step {
-        return &self.install_tls.step;
-    }
-
-    pub fn getUninstallStep(self: *Builder) *Step {
-        return &self.uninstall_tls.step;
-    }
-
-    fn makeUninstall(uninstall_step: *Step) anyerror!void {
-        const uninstall_tls = @fieldParentPtr(TopLevelStep, "step", uninstall_step);
-        const self = @fieldParentPtr(Builder, "uninstall_tls", uninstall_tls);
-
-        for (self.installed_files.items) |installed_file| {
-            const full_path = self.getInstallPath(installed_file.dir, installed_file.path);
-            if (self.verbose) {
-                log.info("rm {s}", .{full_path});
-            }
-            fs.cwd().deleteTree(full_path) catch {};
-        }
-
-        // TODO remove empty directories
-    }
-
-    fn makeOneStep(self: *Builder, s: *Step) anyerror!void {
-        if (s.loop_flag) {
-            log.err("Dependency loop detected:\n  {s}", .{s.name});
-            return error.DependencyLoopDetected;
-        }
-        s.loop_flag = true;
-
-        for (s.dependencies.items) |dep| {
-            self.makeOneStep(dep) catch |err| {
-                if (err == error.DependencyLoopDetected) {
-                    log.err("  {s}", .{s.name});
-                }
-                return err;
-            };
-        }
-
-        s.loop_flag = false;
-
-        try s.make();
-    }
-
-    fn getTopLevelStepByName(self: *Builder, name: []const u8) !*Step {
-        for (self.top_level_steps.items) |top_level_step| {
-            if (mem.eql(u8, top_level_step.step.name, name)) {
-                return &top_level_step.step;
-            }
-        }
-        log.err("Cannot run step '{s}' because it does not exist", .{name});
-        return error.InvalidStepName;
-    }
-
-    pub fn option(self: *Builder, comptime T: type, name_raw: []const u8, description_raw: []const u8) ?T {
-        const name = self.dupe(name_raw);
-        const description = self.dupe(description_raw);
-        const type_id = comptime typeToEnum(T);
-        const enum_options = if (type_id == .@"enum") blk: {
-            const fields = comptime std.meta.fields(T);
-            var options = ArrayList([]const u8).initCapacity(self.allocator, fields.len) catch unreachable;
-
-            inline for (fields) |field| {
-                options.appendAssumeCapacity(field.name);
-            }
-
-            break :blk options.toOwnedSlice() catch unreachable;
-        } else null;
-        const available_option = AvailableOption{
-            .name = name,
-            .type_id = type_id,
-            .description = description,
-            .enum_options = enum_options,
-        };
-        if ((self.available_options_map.fetchPut(name, available_option) catch unreachable) != null) {
-            panic("Option '{s}' declared twice", .{name});
-        }
-        self.available_options_list.append(available_option) catch unreachable;
-
-        const option_ptr = self.user_input_options.getPtr(name) orelse return null;
-        option_ptr.used = true;
-        switch (type_id) {
-            .bool => switch (option_ptr.value) {
-                .flag => return true,
-                .scalar => |s| {
-                    if (mem.eql(u8, s, "true")) {
-                        return true;
-                    } else if (mem.eql(u8, s, "false")) {
-                        return false;
-                    } else {
-                        log.err("Expected -D{s} to be a boolean, but received '{s}'\n", .{ name, s });
-                        self.markInvalidUserInput();
-                        return null;
-                    }
-                },
-                .list, .map => {
-                    log.err("Expected -D{s} to be a boolean, but received a {s}.\n", .{
-                        name, @tagName(option_ptr.value),
-                    });
-                    self.markInvalidUserInput();
-                    return null;
-                },
-            },
-            .int => switch (option_ptr.value) {
-                .flag, .list, .map => {
-                    log.err("Expected -D{s} to be an integer, but received a {s}.\n", .{
-                        name, @tagName(option_ptr.value),
-                    });
-                    self.markInvalidUserInput();
-                    return null;
-                },
-                .scalar => |s| {
-                    const n = std.fmt.parseInt(T, s, 10) catch |err| switch (err) {
-                        error.Overflow => {
-                            log.err("-D{s} value {s} cannot fit into type {s}.\n", .{ name, s, @typeName(T) });
-                            self.markInvalidUserInput();
-                            return null;
-                        },
-                        else => {
-                            log.err("Expected -D{s} to be an integer of type {s}.\n", .{ name, @typeName(T) });
-                            self.markInvalidUserInput();
-                            return null;
-                        },
-                    };
-                    return n;
-                },
-            },
-            .float => switch (option_ptr.value) {
-                .flag, .map, .list => {
-                    log.err("Expected -D{s} to be a float, but received a {s}.\n", .{
-                        name, @tagName(option_ptr.value),
-                    });
-                    self.markInvalidUserInput();
-                    return null;
-                },
-                .scalar => |s| {
-                    const n = std.fmt.parseFloat(T, s) catch {
-                        log.err("Expected -D{s} to be a float of type {s}.\n", .{ name, @typeName(T) });
-                        self.markInvalidUserInput();
-                        return null;
-                    };
-                    return n;
-                },
-            },
-            .@"enum" => switch (option_ptr.value) {
-                .flag, .map, .list => {
-                    log.err("Expected -D{s} to be an enum, but received a {s}.\n", .{
-                        name, @tagName(option_ptr.value),
-                    });
-                    self.markInvalidUserInput();
-                    return null;
-                },
-                .scalar => |s| {
-                    if (std.meta.stringToEnum(T, s)) |enum_lit| {
-                        return enum_lit;
-                    } else {
-                        log.err("Expected -D{s} to be of type {s}.\n", .{ name, @typeName(T) });
-                        self.markInvalidUserInput();
-                        return null;
-                    }
-                },
-            },
-            .string => switch (option_ptr.value) {
-                .flag, .list, .map => {
-                    log.err("Expected -D{s} to be a string, but received a {s}.\n", .{
-                        name, @tagName(option_ptr.value),
-                    });
-                    self.markInvalidUserInput();
-                    return null;
-                },
-                .scalar => |s| return s,
-            },
-            .list => switch (option_ptr.value) {
-                .flag, .map => {
-                    log.err("Expected -D{s} to be a list, but received a {s}.\n", .{
-                        name, @tagName(option_ptr.value),
-                    });
-                    self.markInvalidUserInput();
-                    return null;
-                },
-                .scalar => |s| {
-                    return self.allocator.dupe([]const u8, &[_][]const u8{s}) catch unreachable;
-                },
-                .list => |lst| return lst.items,
-            },
-        }
-    }
-
-    pub fn step(self: *Builder, name: []const u8, description: []const u8) *Step {
-        const step_info = self.allocator.create(TopLevelStep) catch unreachable;
-        step_info.* = TopLevelStep{
-            .step = Step.initNoOp(.top_level, name, self.allocator),
-            .description = self.dupe(description),
-        };
-        self.top_level_steps.append(step_info) catch unreachable;
-        return &step_info.step;
-    }
-
-    pub const StandardOptimizeOptionOptions = struct {
-        preferred_optimize_mode: ?std.builtin.Mode = null,
-    };
-
-    pub fn standardOptimizeOption(self: *Builder, options: StandardOptimizeOptionOptions) std.builtin.Mode {
-        if (options.preferred_optimize_mode) |mode| {
-            if (self.option(bool, "release", "optimize for end users") orelse false) {
-                return mode;
-            } else {
-                return .Debug;
-            }
-        } else {
-            return self.option(
-                std.builtin.Mode,
-                "optimize",
-                "prioritize performance, safety, or binary size (-O flag)",
-            ) orelse .Debug;
-        }
-    }
-
-    pub const StandardTargetOptionsArgs = struct {
-        whitelist: ?[]const CrossTarget = null,
-
-        default_target: CrossTarget = CrossTarget{},
-    };
-
-    /// Exposes standard `zig build` options for choosing a target.
-    pub fn standardTargetOptions(self: *Builder, args: StandardTargetOptionsArgs) CrossTarget {
-        const maybe_triple = self.option(
-            []const u8,
-            "target",
-            "The CPU architecture, OS, and ABI to build for",
-        );
-        const mcpu = self.option([]const u8, "cpu", "Target CPU features to add or subtract");
-
-        if (maybe_triple == null and mcpu == null) {
-            return args.default_target;
-        }
-
-        const triple = maybe_triple orelse "native";
-
-        var diags: CrossTarget.ParseOptions.Diagnostics = .{};
-        const selected_target = CrossTarget.parse(.{
-            .arch_os_abi = triple,
-            .cpu_features = mcpu,
-            .diagnostics = &diags,
-        }) catch |err| switch (err) {
-            error.UnknownCpuModel => {
-                log.err("Unknown CPU: '{s}'\nAvailable CPUs for architecture '{s}':", .{
-                    diags.cpu_name.?,
-                    @tagName(diags.arch.?),
-                });
-                for (diags.arch.?.allCpuModels()) |cpu| {
-                    log.err(" {s}", .{cpu.name});
-                }
-                self.markInvalidUserInput();
-                return args.default_target;
-            },
-            error.UnknownCpuFeature => {
-                log.err(
-                    \\Unknown CPU feature: '{s}'
-                    \\Available CPU features for architecture '{s}':
-                    \\
-                , .{
-                    diags.unknown_feature_name.?,
-                    @tagName(diags.arch.?),
-                });
-                for (diags.arch.?.allFeaturesList()) |feature| {
-                    log.err(" {s}: {s}", .{ feature.name, feature.description });
-                }
-                self.markInvalidUserInput();
-                return args.default_target;
-            },
-            error.UnknownOperatingSystem => {
-                log.err(
-                    \\Unknown OS: '{s}'
-                    \\Available operating systems:
-                    \\
-                , .{diags.os_name.?});
-                inline for (std.meta.fields(std.Target.Os.Tag)) |field| {
-                    log.err(" {s}", .{field.name});
-                }
-                self.markInvalidUserInput();
-                return args.default_target;
-            },
-            else => |e| {
-                log.err("Unable to parse target '{s}': {s}\n", .{ triple, @errorName(e) });
-                self.markInvalidUserInput();
-                return args.default_target;
-            },
-        };
-
-        const selected_canonicalized_triple = selected_target.zigTriple(self.allocator) catch unreachable;
-
-        if (args.whitelist) |list| whitelist_check: {
-            // Make sure it's a match of one of the list.
-            var mismatch_triple = true;
-            var mismatch_cpu_features = true;
-            var whitelist_item = CrossTarget{};
-            for (list) |t| {
-                mismatch_cpu_features = true;
-                mismatch_triple = true;
-
-                const t_triple = t.zigTriple(self.allocator) catch unreachable;
-                if (mem.eql(u8, t_triple, selected_canonicalized_triple)) {
-                    mismatch_triple = false;
-                    whitelist_item = t;
-                    if (t.getCpuFeatures().isSuperSetOf(selected_target.getCpuFeatures())) {
-                        mismatch_cpu_features = false;
-                        break :whitelist_check;
-                    } else {
-                        break;
-                    }
-                }
-            }
-            if (mismatch_triple) {
-                log.err("Chosen target '{s}' does not match one of the supported targets:", .{
-                    selected_canonicalized_triple,
-                });
-                for (list) |t| {
-                    const t_triple = t.zigTriple(self.allocator) catch unreachable;
-                    log.err(" {s}", .{t_triple});
-                }
-            } else {
-                assert(mismatch_cpu_features);
-                const whitelist_cpu = whitelist_item.getCpu();
-                const selected_cpu = selected_target.getCpu();
-                log.err("Chosen CPU model '{s}' does not match one of the supported targets:", .{
-                    selected_cpu.model.name,
-                });
-                log.err("  Supported feature Set: ", .{});
-                const all_features = whitelist_cpu.arch.allFeaturesList();
-                var populated_cpu_features = whitelist_cpu.model.features;
-                populated_cpu_features.populateDependencies(all_features);
-                for (all_features) |feature, i_usize| {
-                    const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize);
-                    const in_cpu_set = populated_cpu_features.isEnabled(i);
-                    if (in_cpu_set) {
-                        log.err("{s} ", .{feature.name});
-                    }
-                }
-                log.err("  Remove: ", .{});
-                for (all_features) |feature, i_usize| {
-                    const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize);
-                    const in_cpu_set = populated_cpu_features.isEnabled(i);
-                    const in_actual_set = selected_cpu.features.isEnabled(i);
-                    if (in_actual_set and !in_cpu_set) {
-                        log.err("{s} ", .{feature.name});
-                    }
-                }
-            }
-            self.markInvalidUserInput();
-            return args.default_target;
-        }
-
-        return selected_target;
-    }
-
-    pub fn addUserInputOption(self: *Builder, name_raw: []const u8, value_raw: []const u8) !bool {
-        const name = self.dupe(name_raw);
-        const value = self.dupe(value_raw);
-        const gop = try self.user_input_options.getOrPut(name);
-        if (!gop.found_existing) {
-            gop.value_ptr.* = UserInputOption{
-                .name = name,
-                .value = .{ .scalar = value },
-                .used = false,
-            };
-            return false;
-        }
-
-        // option already exists
-        switch (gop.value_ptr.value) {
-            .scalar => |s| {
-                // turn it into a list
-                var list = ArrayList([]const u8).init(self.allocator);
-                list.append(s) catch unreachable;
-                list.append(value) catch unreachable;
-                self.user_input_options.put(name, .{
-                    .name = name,
-                    .value = .{ .list = list },
-                    .used = false,
-                }) catch unreachable;
-            },
-            .list => |*list| {
-                // append to the list
-                list.append(value) catch unreachable;
-                self.user_input_options.put(name, .{
-                    .name = name,
-                    .value = .{ .list = list.* },
-                    .used = false,
-                }) catch unreachable;
-            },
-            .flag => {
-                log.warn("Option '-D{s}={s}' conflicts with flag '-D{s}'.", .{ name, value, name });
-                return true;
-            },
-            .map => |*map| {
-                _ = map;
-                log.warn("TODO maps as command line arguments is not implemented yet.", .{});
-                return true;
-            },
-        }
-        return false;
-    }
-
-    pub fn addUserInputFlag(self: *Builder, name_raw: []const u8) !bool {
-        const name = self.dupe(name_raw);
-        const gop = try self.user_input_options.getOrPut(name);
-        if (!gop.found_existing) {
-            gop.value_ptr.* = .{
-                .name = name,
-                .value = .{ .flag = {} },
-                .used = false,
-            };
-            return false;
-        }
-
-        // option already exists
-        switch (gop.value_ptr.value) {
-            .scalar => |s| {
-                log.err("Flag '-D{s}' conflicts with option '-D{s}={s}'.", .{ name, name, s });
-                return true;
-            },
-            .list, .map => {
-                log.err("Flag '-D{s}' conflicts with multiple options of the same name.", .{name});
-                return true;
-            },
-            .flag => {},
-        }
-        return false;
-    }
-
-    fn typeToEnum(comptime T: type) TypeId {
-        return switch (@typeInfo(T)) {
-            .Int => .int,
-            .Float => .float,
-            .Bool => .bool,
-            .Enum => .@"enum",
-            else => switch (T) {
-                []const u8 => .string,
-                []const []const u8 => .list,
-                else => @compileError("Unsupported type: " ++ @typeName(T)),
-            },
-        };
-    }
-
-    fn markInvalidUserInput(self: *Builder) void {
-        self.invalid_user_input = true;
-    }
-
-    pub fn validateUserInputDidItFail(self: *Builder) bool {
-        // make sure all args are used
-        var it = self.user_input_options.iterator();
-        while (it.next()) |entry| {
-            if (!entry.value_ptr.used) {
-                log.err("Invalid option: -D{s}", .{entry.key_ptr.*});
-                self.markInvalidUserInput();
-            }
-        }
-
-        return self.invalid_user_input;
-    }
-
-    pub fn spawnChild(self: *Builder, argv: []const []const u8) !void {
-        return self.spawnChildEnvMap(null, self.env_map, argv);
-    }
-
-    fn printCmd(cwd: ?[]const u8, argv: []const []const u8) void {
-        if (cwd) |yes_cwd| std.debug.print("cd {s} && ", .{yes_cwd});
-        for (argv) |arg| {
-            std.debug.print("{s} ", .{arg});
-        }
-        std.debug.print("\n", .{});
-    }
-
-    pub fn spawnChildEnvMap(self: *Builder, cwd: ?[]const u8, env_map: *const EnvMap, argv: []const []const u8) !void {
-        if (self.verbose) {
-            printCmd(cwd, argv);
-        }
-
-        if (!std.process.can_spawn)
-            return error.ExecNotSupported;
-
-        var child = std.ChildProcess.init(argv, self.allocator);
-        child.cwd = cwd;
-        child.env_map = env_map;
-
-        const term = child.spawnAndWait() catch |err| {
-            log.err("Unable to spawn {s}: {s}", .{ argv[0], @errorName(err) });
-            return err;
-        };
-
-        switch (term) {
-            .Exited => |code| {
-                if (code != 0) {
-                    log.err("The following command exited with error code {}:", .{code});
-                    printCmd(cwd, argv);
-                    return error.UncleanExit;
-                }
-            },
-            else => {
-                log.err("The following command terminated unexpectedly:", .{});
-                printCmd(cwd, argv);
-
-                return error.UncleanExit;
-            },
-        }
-    }
-
-    pub fn makePath(self: *Builder, path: []const u8) !void {
-        fs.cwd().makePath(self.pathFromRoot(path)) catch |err| {
-            log.err("Unable to create path {s}: {s}", .{ path, @errorName(err) });
-            return err;
-        };
-    }
-
-    pub fn installArtifact(self: *Builder, artifact: *LibExeObjStep) void {
-        self.getInstallStep().dependOn(&self.addInstallArtifact(artifact).step);
-    }
-
-    pub fn addInstallArtifact(self: *Builder, artifact: *LibExeObjStep) *InstallArtifactStep {
-        return InstallArtifactStep.create(self, artifact);
-    }
-
-    ///`dest_rel_path` is relative to prefix path
-    pub fn installFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void {
-        self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .prefix, dest_rel_path).step);
-    }
-
-    pub fn installDirectory(self: *Builder, options: InstallDirectoryOptions) void {
-        self.getInstallStep().dependOn(&self.addInstallDirectory(options).step);
-    }
-
-    ///`dest_rel_path` is relative to bin path
-    pub fn installBinFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void {
-        self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .bin, dest_rel_path).step);
-    }
-
-    ///`dest_rel_path` is relative to lib path
-    pub fn installLibFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void {
-        self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .lib, dest_rel_path).step);
-    }
-
-    /// Output format (BIN vs Intel HEX) determined by filename
-    pub fn installRaw(self: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep {
-        const raw = self.addInstallRaw(artifact, dest_filename, options);
-        self.getInstallStep().dependOn(&raw.step);
-        return raw;
-    }
-
-    ///`dest_rel_path` is relative to install prefix path
-    pub fn addInstallFile(self: *Builder, source: FileSource, dest_rel_path: []const u8) *InstallFileStep {
-        return self.addInstallFileWithDir(source.dupe(self), .prefix, dest_rel_path);
-    }
-
-    ///`dest_rel_path` is relative to bin path
-    pub fn addInstallBinFile(self: *Builder, source: FileSource, dest_rel_path: []const u8) *InstallFileStep {
-        return self.addInstallFileWithDir(source.dupe(self), .bin, dest_rel_path);
-    }
-
-    ///`dest_rel_path` is relative to lib path
-    pub fn addInstallLibFile(self: *Builder, source: FileSource, dest_rel_path: []const u8) *InstallFileStep {
-        return self.addInstallFileWithDir(source.dupe(self), .lib, dest_rel_path);
-    }
-
-    pub fn addInstallHeaderFile(b: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep {
-        return b.addInstallFileWithDir(.{ .path = src_path }, .header, dest_rel_path);
-    }
-
-    pub fn addInstallRaw(self: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep {
-        return InstallRawStep.create(self, artifact, dest_filename, options);
-    }
-
-    pub fn addInstallFileWithDir(
-        self: *Builder,
-        source: FileSource,
-        install_dir: InstallDir,
-        dest_rel_path: []const u8,
-    ) *InstallFileStep {
-        if (dest_rel_path.len == 0) {
-            panic("dest_rel_path must be non-empty", .{});
-        }
-        const install_step = self.allocator.create(InstallFileStep) catch unreachable;
-        install_step.* = InstallFileStep.init(self, source.dupe(self), install_dir, dest_rel_path);
-        return install_step;
-    }
-
-    pub fn addInstallDirectory(self: *Builder, options: InstallDirectoryOptions) *InstallDirStep {
-        const install_step = self.allocator.create(InstallDirStep) catch unreachable;
-        install_step.* = InstallDirStep.init(self, options);
-        return install_step;
-    }
-
-    pub fn pushInstalledFile(self: *Builder, dir: InstallDir, dest_rel_path: []const u8) void {
-        const file = InstalledFile{
-            .dir = dir,
-            .path = dest_rel_path,
-        };
-        self.installed_files.append(file.dupe(self)) catch unreachable;
-    }
-
-    pub fn updateFile(self: *Builder, source_path: []const u8, dest_path: []const u8) !void {
-        if (self.verbose) {
-            log.info("cp {s} {s} ", .{ source_path, dest_path });
-        }
-        const cwd = fs.cwd();
-        const prev_status = try fs.Dir.updateFile(cwd, source_path, cwd, dest_path, .{});
-        if (self.verbose) switch (prev_status) {
-            .stale => log.info("# installed", .{}),
-            .fresh => log.info("# up-to-date", .{}),
-        };
-    }
-
-    pub fn truncateFile(self: *Builder, dest_path: []const u8) !void {
-        if (self.verbose) {
-            log.info("truncate {s}", .{dest_path});
-        }
-        const cwd = fs.cwd();
-        var src_file = cwd.createFile(dest_path, .{}) catch |err| switch (err) {
-            error.FileNotFound => blk: {
-                if (fs.path.dirname(dest_path)) |dirname| {
-                    try cwd.makePath(dirname);
-                }
-                break :blk try cwd.createFile(dest_path, .{});
-            },
-            else => |e| return e,
-        };
-        src_file.close();
-    }
-
-    pub fn pathFromRoot(self: *Builder, rel_path: []const u8) []u8 {
-        return fs.path.resolve(self.allocator, &[_][]const u8{ self.build_root, rel_path }) catch unreachable;
-    }
-
-    /// Shorthand for `std.fs.path.join(builder.allocator, paths) catch unreachable`
-    pub fn pathJoin(self: *Builder, paths: []const []const u8) []u8 {
-        return fs.path.join(self.allocator, paths) catch unreachable;
-    }
-
-    pub fn fmt(self: *Builder, comptime format: []const u8, args: anytype) []u8 {
-        return fmt_lib.allocPrint(self.allocator, format, args) catch unreachable;
-    }
-
-    pub fn findProgram(self: *Builder, names: []const []const u8, paths: []const []const u8) ![]const u8 {
-        // TODO report error for ambiguous situations
-        const exe_extension = @as(CrossTarget, .{}).exeFileExt();
-        for (self.search_prefixes.items) |search_prefix| {
-            for (names) |name| {
-                if (fs.path.isAbsolute(name)) {
-                    return name;
-                }
-                const full_path = self.pathJoin(&.{
-                    search_prefix,
-                    "bin",
-                    self.fmt("{s}{s}", .{ name, exe_extension }),
-                });
-                return fs.realpathAlloc(self.allocator, full_path) catch continue;
-            }
-        }
-        if (self.env_map.get("PATH")) |PATH| {
-            for (names) |name| {
-                if (fs.path.isAbsolute(name)) {
-                    return name;
-                }
-                var it = mem.tokenize(u8, PATH, &[_]u8{fs.path.delimiter});
-                while (it.next()) |path| {
-                    const full_path = self.pathJoin(&.{
-                        path,
-                        self.fmt("{s}{s}", .{ name, exe_extension }),
-                    });
-                    return fs.realpathAlloc(self.allocator, full_path) catch continue;
-                }
-            }
-        }
-        for (names) |name| {
-            if (fs.path.isAbsolute(name)) {
-                return name;
-            }
-            for (paths) |path| {
-                const full_path = self.pathJoin(&.{
-                    path,
-                    self.fmt("{s}{s}", .{ name, exe_extension }),
-                });
-                return fs.realpathAlloc(self.allocator, full_path) catch continue;
-            }
-        }
-        return error.FileNotFound;
-    }
-
-    pub fn execAllowFail(
-        self: *Builder,
-        argv: []const []const u8,
-        out_code: *u8,
-        stderr_behavior: std.ChildProcess.StdIo,
-    ) ExecError![]u8 {
-        assert(argv.len != 0);
-
-        if (!std.process.can_spawn)
-            return error.ExecNotSupported;
-
-        const max_output_size = 400 * 1024;
-        var child = std.ChildProcess.init(argv, self.allocator);
-        child.stdin_behavior = .Ignore;
-        child.stdout_behavior = .Pipe;
-        child.stderr_behavior = stderr_behavior;
-        child.env_map = self.env_map;
-
-        try child.spawn();
-
-        const stdout = child.stdout.?.reader().readAllAlloc(self.allocator, max_output_size) catch {
-            return error.ReadFailure;
-        };
-        errdefer self.allocator.free(stdout);
-
-        const term = try child.wait();
-        switch (term) {
-            .Exited => |code| {
-                if (code != 0) {
-                    out_code.* = @truncate(u8, code);
-                    return error.ExitCodeFailure;
-                }
-                return stdout;
-            },
-            .Signal, .Stopped, .Unknown => |code| {
-                out_code.* = @truncate(u8, code);
-                return error.ProcessTerminated;
-            },
-        }
-    }
-
-    pub fn execFromStep(self: *Builder, argv: []const []const u8, src_step: ?*Step) ![]u8 {
-        assert(argv.len != 0);
-
-        if (self.verbose) {
-            printCmd(null, argv);
-        }
-
-        if (!std.process.can_spawn) {
-            if (src_step) |s| log.err("{s}...", .{s.name});
-            log.err("Unable to spawn the following command: cannot spawn child process", .{});
-            printCmd(null, argv);
-            std.os.abort();
-        }
-
-        var code: u8 = undefined;
-        return self.execAllowFail(argv, &code, .Inherit) catch |err| switch (err) {
-            error.ExecNotSupported => {
-                if (src_step) |s| log.err("{s}...", .{s.name});
-                log.err("Unable to spawn the following command: cannot spawn child process", .{});
-                printCmd(null, argv);
-                std.os.abort();
-            },
-            error.FileNotFound => {
-                if (src_step) |s| log.err("{s}...", .{s.name});
-                log.err("Unable to spawn the following command: file not found", .{});
-                printCmd(null, argv);
-                std.os.exit(@truncate(u8, code));
-            },
-            error.ExitCodeFailure => {
-                if (src_step) |s| log.err("{s}...", .{s.name});
-                if (self.prominent_compile_errors) {
-                    log.err("The step exited with error code {d}", .{code});
-                } else {
-                    log.err("The following command exited with error code {d}:", .{code});
-                    printCmd(null, argv);
-                }
-
-                std.os.exit(@truncate(u8, code));
-            },
-            error.ProcessTerminated => {
-                if (src_step) |s| log.err("{s}...", .{s.name});
-                log.err("The following command terminated unexpectedly:", .{});
-                printCmd(null, argv);
-                std.os.exit(@truncate(u8, code));
-            },
-            else => |e| return e,
-        };
-    }
-
-    pub fn exec(self: *Builder, argv: []const []const u8) ![]u8 {
-        return self.execFromStep(argv, null);
-    }
-
-    pub fn addSearchPrefix(self: *Builder, search_prefix: []const u8) void {
-        self.search_prefixes.append(self.dupePath(search_prefix)) catch unreachable;
-    }
-
-    pub fn getInstallPath(self: *Builder, dir: InstallDir, dest_rel_path: []const u8) []const u8 {
-        assert(!fs.path.isAbsolute(dest_rel_path)); // Install paths must be relative to the prefix
-        const base_dir = switch (dir) {
-            .prefix => self.install_path,
-            .bin => self.exe_dir,
-            .lib => self.lib_dir,
-            .header => self.h_dir,
-            .custom => |path| self.pathJoin(&.{ self.install_path, path }),
-        };
-        return fs.path.resolve(
-            self.allocator,
-            &[_][]const u8{ base_dir, dest_rel_path },
-        ) catch unreachable;
-    }
-
-    pub const Dependency = struct {
-        builder: *Builder,
-
-        pub fn artifact(d: *Dependency, name: []const u8) *LibExeObjStep {
-            var found: ?*LibExeObjStep = null;
-            for (d.builder.install_tls.step.dependencies.items) |dep_step| {
-                const inst = dep_step.cast(InstallArtifactStep) orelse continue;
-                if (mem.eql(u8, inst.artifact.name, name)) {
-                    if (found != null) panic("artifact name '{s}' is ambiguous", .{name});
-                    found = inst.artifact;
-                }
-            }
-            return found orelse {
-                for (d.builder.install_tls.step.dependencies.items) |dep_step| {
-                    const inst = dep_step.cast(InstallArtifactStep) orelse continue;
-                    log.info("available artifact: '{s}'", .{inst.artifact.name});
-                }
-                panic("unable to find artifact '{s}'", .{name});
-            };
-        }
-    };
-
-    pub fn dependency(b: *Builder, name: []const u8, args: anytype) *Dependency {
-        const build_runner = @import("root");
-        const deps = build_runner.dependencies;
-
-        inline for (@typeInfo(deps.imports).Struct.decls) |decl| {
-            if (mem.startsWith(u8, decl.name, b.dep_prefix) and
-                mem.endsWith(u8, decl.name, name) and
-                decl.name.len == b.dep_prefix.len + name.len)
-            {
-                const build_zig = @field(deps.imports, decl.name);
-                const build_root = @field(deps.build_root, decl.name);
-                return dependencyInner(b, name, build_root, build_zig, args);
-            }
-        }
-
-        const full_path = b.pathFromRoot("build.zig.ini");
-        std.debug.print("no dependency named '{s}' in '{s}'\n", .{ name, full_path });
-        std.process.exit(1);
-    }
-
-    fn dependencyInner(
-        b: *Builder,
-        name: []const u8,
-        build_root: []const u8,
-        comptime build_zig: type,
-        args: anytype,
-    ) *Dependency {
-        const sub_builder = b.createChild(name, build_root, args) catch unreachable;
-        sub_builder.runBuild(build_zig) catch unreachable;
-
-        if (sub_builder.validateUserInputDidItFail()) {
-            std.debug.dumpCurrentStackTrace(@returnAddress());
-        }
-
-        const dep = b.allocator.create(Dependency) catch unreachable;
-        dep.* = .{ .builder = sub_builder };
-        return dep;
-    }
-
-    pub fn runBuild(b: *Builder, build_zig: anytype) anyerror!void {
-        switch (@typeInfo(@typeInfo(@TypeOf(build_zig.build)).Fn.return_type.?)) {
-            .Void => build_zig.build(b),
-            .ErrorUnion => try build_zig.build(b),
-            else => @compileError("expected return type of build to be 'void' or '!void'"),
-        }
-    }
-};
-
-test "builder.findProgram compiles" {
-    if (builtin.os.tag == .wasi) return error.SkipZigTest;
-
-    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
-    defer arena.deinit();
-
-    const builder = try Builder.create(
-        arena.allocator(),
-        "zig",
-        "zig-cache",
-        "zig-cache",
-        "zig-cache",
-    );
-    defer builder.destroy();
-    _ = builder.findProgram(&[_][]const u8{}, &[_][]const u8{}) catch null;
-}
-
-pub const Pkg = struct {
-    name: []const u8,
-    source: FileSource,
-    dependencies: ?[]const Pkg = null,
-};
-
-/// A file that is generated by a build step.
-/// This struct is an interface that is meant to be used with `@fieldParentPtr` to implement the actual path logic.
-pub const GeneratedFile = struct {
-    /// The step that generates the file
-    step: *Step,
-
-    /// The path to the generated file. Must be either absolute or relative to the build root.
-    /// This value must be set in the `fn make()` of the `step` and must not be `null` afterwards.
-    path: ?[]const u8 = null,
-
-    pub fn getPath(self: GeneratedFile) []const u8 {
-        return self.path orelse std.debug.panic(
-            "getPath() was called on a GeneratedFile that wasn't build yet. Is there a missing Step dependency on step '{s}'?",
-            .{self.step.name},
-        );
-    }
-};
-
-/// A file source is a reference to an existing or future file.
-///
-pub const FileSource = union(enum) {
-    /// A plain file path, relative to build root or absolute.
-    path: []const u8,
-
-    /// A file that is generated by an interface. Those files usually are
-    /// not available until built by a build step.
-    generated: *const GeneratedFile,
-
-    /// Returns a new file source that will have a relative path to the build root guaranteed.
-    /// This should be preferred over setting `.path` directly as it documents that the files are in the project directory.
-    pub fn relative(path: []const u8) FileSource {
-        std.debug.assert(!std.fs.path.isAbsolute(path));
-        return FileSource{ .path = path };
-    }
-
-    /// Returns a string that can be shown to represent the file source.
-    /// Either returns the path or `"generated"`.
-    pub fn getDisplayName(self: FileSource) []const u8 {
-        return switch (self) {
-            .path => self.path,
-            .generated => "generated",
-        };
-    }
-
-    /// Adds dependencies this file source implies to the given step.
-    pub fn addStepDependencies(self: FileSource, step: *Step) void {
-        switch (self) {
-            .path => {},
-            .generated => |gen| step.dependOn(gen.step),
-        }
-    }
-
-    /// Should only be called during make(), returns a path relative to the build root or absolute.
-    pub fn getPath(self: FileSource, builder: *Builder) []const u8 {
-        const path = switch (self) {
-            .path => |p| builder.pathFromRoot(p),
-            .generated => |gen| gen.getPath(),
-        };
-        return path;
-    }
-
-    /// Duplicates the file source for a given builder.
-    pub fn dupe(self: FileSource, b: *Builder) FileSource {
-        return switch (self) {
-            .path => |p| .{ .path = b.dupePath(p) },
-            .generated => |gen| .{ .generated = gen },
-        };
-    }
-};
-
-/// Allocates a new string for assigning a value to a named macro.
-/// If the value is omitted, it is set to 1.
-/// `name` and `value` need not live longer than the function call.
-pub fn constructCMacro(allocator: Allocator, name: []const u8, value: ?[]const u8) []const u8 {
-    var macro = allocator.alloc(
-        u8,
-        name.len + if (value) |value_slice| value_slice.len + 1 else 0,
-    ) catch |err| if (err == error.OutOfMemory) @panic("Out of memory") else unreachable;
-    mem.copy(u8, macro, name);
-    if (value) |value_slice| {
-        macro[name.len] = '=';
-        mem.copy(u8, macro[name.len + 1 ..], value_slice);
-    }
-    return macro;
-}
-
-/// deprecated: use `InstallDirStep.Options`
-pub const InstallDirectoryOptions = InstallDirStep.Options;
-
-pub const Step = struct {
-    id: Id,
-    name: []const u8,
-    makeFn: MakeFn,
-    dependencies: ArrayList(*Step),
-    loop_flag: bool,
-    done_flag: bool,
-
-    const MakeFn = *const fn (self: *Step) anyerror!void;
-
-    pub const Id = enum {
-        top_level,
-        lib_exe_obj,
-        install_artifact,
-        install_file,
-        install_dir,
-        log,
-        remove_dir,
-        fmt,
-        translate_c,
-        write_file,
-        run,
-        emulatable_run,
-        check_file,
-        check_object,
-        config_header,
-        install_raw,
-        options,
-        custom,
-
-        pub fn Type(comptime id: Id) type {
-            return switch (id) {
-                .top_level => Builder.TopLevelStep,
-                .lib_exe_obj => LibExeObjStep,
-                .install_artifact => InstallArtifactStep,
-                .install_file => InstallFileStep,
-                .install_dir => InstallDirStep,
-                .log => LogStep,
-                .remove_dir => RemoveDirStep,
-                .fmt => FmtStep,
-                .translate_c => TranslateCStep,
-                .write_file => WriteFileStep,
-                .run => RunStep,
-                .emulatable_run => EmulatableRunStep,
-                .check_file => CheckFileStep,
-                .check_object => CheckObjectStep,
-                .config_header => ConfigHeaderStep,
-                .install_raw => InstallRawStep,
-                .options => OptionsStep,
-                .custom => @compileError("no type available for custom step"),
-            };
-        }
-    };
-
-    pub fn init(id: Id, name: []const u8, allocator: Allocator, makeFn: MakeFn) Step {
-        return Step{
-            .id = id,
-            .name = allocator.dupe(u8, name) catch unreachable,
-            .makeFn = makeFn,
-            .dependencies = ArrayList(*Step).init(allocator),
-            .loop_flag = false,
-            .done_flag = false,
-        };
-    }
-    pub fn initNoOp(id: Id, name: []const u8, allocator: Allocator) Step {
-        return init(id, name, allocator, makeNoOp);
-    }
-
-    pub fn make(self: *Step) !void {
-        if (self.done_flag) return;
-
-        try self.makeFn(self);
-        self.done_flag = true;
-    }
-
-    pub fn dependOn(self: *Step, other: *Step) void {
-        self.dependencies.append(other) catch unreachable;
-    }
-
-    fn makeNoOp(self: *Step) anyerror!void {
-        _ = self;
-    }
-
-    pub fn cast(step: *Step, comptime T: type) ?*T {
-        if (step.id == T.base_id) {
-            return @fieldParentPtr(T, "step", step);
-        }
-        return null;
-    }
-};
-
-pub const VcpkgRoot = union(VcpkgRootStatus) {
-    unattempted: void,
-    not_found: void,
-    found: []const u8,
-};
-
-pub const VcpkgRootStatus = enum {
-    unattempted,
-    not_found,
-    found,
-};
-
-pub const InstallDir = union(enum) {
-    prefix: void,
-    lib: void,
-    bin: void,
-    header: void,
-    /// A path relative to the prefix
-    custom: []const u8,
-
-    /// Duplicates the install directory including the path if set to custom.
-    pub fn dupe(self: InstallDir, builder: *Builder) InstallDir {
-        if (self == .custom) {
-            // Written with this temporary to avoid RLS problems
-            const duped_path = builder.dupe(self.custom);
-            return .{ .custom = duped_path };
-        } else {
-            return self;
-        }
-    }
-};
-
-pub const InstalledFile = struct {
-    dir: InstallDir,
-    path: []const u8,
-
-    /// Duplicates the installed file path and directory.
-    pub fn dupe(self: InstalledFile, builder: *Builder) InstalledFile {
-        return .{
-            .dir = self.dir.dupe(builder),
-            .path = builder.dupe(self.path),
-        };
-    }
-};
-
-pub fn serializeCpu(allocator: Allocator, cpu: std.Target.Cpu) ![]const u8 {
-    // TODO this logic can disappear if cpu model + features becomes part of the target triple
-    const all_features = cpu.arch.allFeaturesList();
-    var populated_cpu_features = cpu.model.features;
-    populated_cpu_features.populateDependencies(all_features);
-
-    if (populated_cpu_features.eql(cpu.features)) {
-        // The CPU name alone is sufficient.
-        return cpu.model.name;
-    } else {
-        var mcpu_buffer = ArrayList(u8).init(allocator);
-        try mcpu_buffer.appendSlice(cpu.model.name);
-
-        for (all_features) |feature, i_usize| {
-            const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize);
-            const in_cpu_set = populated_cpu_features.isEnabled(i);
-            const in_actual_set = cpu.features.isEnabled(i);
-            if (in_cpu_set and !in_actual_set) {
-                try mcpu_buffer.writer().print("-{s}", .{feature.name});
-            } else if (!in_cpu_set and in_actual_set) {
-                try mcpu_buffer.writer().print("+{s}", .{feature.name});
-            }
-        }
-
-        return try mcpu_buffer.toOwnedSlice();
-    }
-}
-
-test "dupePkg()" {
-    if (builtin.os.tag == .wasi) return error.SkipZigTest;
-
-    var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
-    defer arena.deinit();
-    var builder = try Builder.create(
-        arena.allocator(),
-        "test",
-        "test",
-        "test",
-        "test",
-    );
-    defer builder.destroy();
-
-    var pkg_dep = Pkg{
-        .name = "pkg_dep",
-        .source = .{ .path = "/not/a/pkg_dep.zig" },
-    };
-    var pkg_top = Pkg{
-        .name = "pkg_top",
-        .source = .{ .path = "/not/a/pkg_top.zig" },
-        .dependencies = &[_]Pkg{pkg_dep},
-    };
-    const dupe = builder.dupePkg(pkg_top);
-
-    const original_deps = pkg_top.dependencies.?;
-    const dupe_deps = dupe.dependencies.?;
-
-    // probably the same top level package details
-    try std.testing.expectEqualStrings(pkg_top.name, dupe.name);
-
-    // probably the same dependencies
-    try std.testing.expectEqual(original_deps.len, dupe_deps.len);
-    try std.testing.expectEqual(original_deps[0].name, pkg_dep.name);
-
-    // could segfault otherwise if pointers in duplicated package's fields are
-    // the same as those in stack allocated package's fields
-    try std.testing.expect(dupe_deps.ptr != original_deps.ptr);
-    try std.testing.expect(dupe.name.ptr != pkg_top.name.ptr);
-    try std.testing.expect(dupe.source.path.ptr != pkg_top.source.path.ptr);
-    try std.testing.expect(dupe_deps[0].name.ptr != pkg_dep.name.ptr);
-    try std.testing.expect(dupe_deps[0].source.path.ptr != pkg_dep.source.path.ptr);
-}
-
-test {
-    _ = CheckFileStep;
-    _ = CheckObjectStep;
-    _ = EmulatableRunStep;
-    _ = FmtStep;
-    _ = InstallArtifactStep;
-    _ = InstallDirStep;
-    _ = InstallFileStep;
-    _ = InstallRawStep;
-    _ = LibExeObjStep;
-    _ = LogStep;
-    _ = OptionsStep;
-    _ = RemoveDirStep;
-    _ = RunStep;
-    _ = TranslateCStep;
-    _ = WriteFileStep;
-}
lib/std/std.zig
@@ -9,6 +9,7 @@ pub const AutoArrayHashMapUnmanaged = array_hash_map.AutoArrayHashMapUnmanaged;
 pub const AutoHashMap = hash_map.AutoHashMap;
 pub const AutoHashMapUnmanaged = hash_map.AutoHashMapUnmanaged;
 pub const BoundedArray = @import("bounded_array.zig").BoundedArray;
+pub const Build = @import("Build.zig");
 pub const BufMap = @import("buf_map.zig").BufMap;
 pub const BufSet = @import("buf_set.zig").BufSet;
 pub const ChildProcess = @import("child_process.zig").ChildProcess;
@@ -49,7 +50,6 @@ pub const array_hash_map = @import("array_hash_map.zig");
 pub const atomic = @import("atomic.zig");
 pub const base64 = @import("base64.zig");
 pub const bit_set = @import("bit_set.zig");
-pub const build = @import("build.zig");
 pub const builtin = @import("builtin.zig");
 pub const c = @import("c.zig");
 pub const coff = @import("coff.zig");
@@ -96,6 +96,12 @@ pub const wasm = @import("wasm.zig");
 pub const zig = @import("zig.zig");
 pub const start = @import("start.zig");
 
+///// Deprecated. Use `std.Build` instead.
+//pub const build = struct {
+//    /// Deprecated. Use `std.Build` instead.
+//    pub const Builder = Build;
+//};
+
 const root = @import("root");
 const options_override = if (@hasDecl(root, "std_options")) root.std_options else struct {};
 
lib/build_runner.zig
@@ -3,7 +3,6 @@ const std = @import("std");
 const builtin = @import("builtin");
 const io = std.io;
 const fmt = std.fmt;
-const Builder = std.build.Builder;
 const mem = std.mem;
 const process = std.process;
 const ArrayList = std.ArrayList;
@@ -42,7 +41,7 @@ pub fn main() !void {
         return error.InvalidArgs;
     };
 
-    const builder = try Builder.create(
+    const builder = try std.Build.create(
         allocator,
         zig_exe,
         build_root,
@@ -58,7 +57,7 @@ pub fn main() !void {
     const stdout_stream = io.getStdOut().writer();
 
     var install_prefix: ?[]const u8 = null;
-    var dir_list = Builder.DirList{};
+    var dir_list = std.Build.DirList{};
 
     // before arg parsing, check for the NO_COLOR environment variable
     // if it exists, default the color setting to .off
@@ -230,7 +229,7 @@ pub fn main() !void {
     };
 }
 
-fn usage(builder: *Builder, already_ran_build: bool, out_stream: anytype) !void {
+fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !void {
     // run the build script to collect the options
     if (!already_ran_build) {
         builder.resolveInstallPrefix(null, .{});
@@ -330,7 +329,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: anytype) !void
     );
 }
 
-fn usageAndErr(builder: *Builder, already_ran_build: bool, out_stream: anytype) void {
+fn usageAndErr(builder: *std.Build, already_ran_build: bool, out_stream: anytype) void {
     usage(builder, already_ran_build, out_stream) catch {};
     process.exit(1);
 }
test/link/bss/build.zig
@@ -1,6 +1,6 @@
-const Builder = @import("std").build.Builder;
+const std = @import("std");
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
     const test_step = b.step("test", "Test");
 
test/link/common_symbols/build.zig
@@ -1,6 +1,6 @@
-const Builder = @import("std").build.Builder;
+const std = @import("std");
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
 
     const lib_a = b.addStaticLibrary(.{
test/link/common_symbols_alignment/build.zig
@@ -1,6 +1,6 @@
-const Builder = @import("std").build.Builder;
+const std = @import("std");
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
     const target = b.standardTargetOptions(.{});
 
test/link/interdependent_static_c_libs/build.zig
@@ -1,6 +1,6 @@
-const Builder = @import("std").build.Builder;
+const std = @import("std");
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
     const target = b.standardTargetOptions(.{});
 
test/link/macho/bugs/13056/build.zig
@@ -1,7 +1,6 @@
 const std = @import("std");
-const Builder = std.build.Builder;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
 
     const target: std.zig.CrossTarget = .{ .os_tag = .macos };
test/link/macho/bugs/13457/build.zig
@@ -1,8 +1,7 @@
 const std = @import("std");
-const Builder = std.build.Builder;
-const LibExeObjectStep = std.build.LibExeObjStep;
+const LibExeObjectStep = std.Build.LibExeObjStep;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
     const target: std.zig.CrossTarget = .{ .os_tag = .macos };
 
test/link/macho/dead_strip/build.zig
@@ -1,8 +1,7 @@
 const std = @import("std");
-const Builder = std.build.Builder;
-const LibExeObjectStep = std.build.LibExeObjStep;
+const LibExeObjectStep = std.Build.LibExeObjStep;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
     const target: std.zig.CrossTarget = .{ .os_tag = .macos };
 
@@ -37,7 +36,7 @@ pub fn build(b: *Builder) void {
     }
 }
 
-fn createScenario(b: *Builder, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep {
+fn createScenario(b: *std.Build, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep {
     const exe = b.addExecutable(.{
         .name = "test",
         .optimize = optimize,
test/link/macho/dead_strip_dylibs/build.zig
@@ -1,8 +1,7 @@
 const std = @import("std");
-const Builder = std.build.Builder;
-const LibExeObjectStep = std.build.LibExeObjStep;
+const LibExeObjectStep = std.Build.LibExeObjStep;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
 
     const test_step = b.step("test", "Test the program");
@@ -36,7 +35,7 @@ pub fn build(b: *Builder) void {
     }
 }
 
-fn createScenario(b: *Builder, optimize: std.builtin.OptimizeMode) *LibExeObjectStep {
+fn createScenario(b: *std.Build, optimize: std.builtin.OptimizeMode) *LibExeObjectStep {
     const exe = b.addExecutable(.{
         .name = "test",
         .optimize = optimize,
test/link/macho/dylib/build.zig
@@ -1,7 +1,6 @@
 const std = @import("std");
-const Builder = std.build.Builder;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
     const target: std.zig.CrossTarget = .{ .os_tag = .macos };
 
test/link/macho/empty/build.zig
@@ -1,7 +1,6 @@
 const std = @import("std");
-const Builder = std.build.Builder;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
     const target: std.zig.CrossTarget = .{ .os_tag = .macos };
 
@@ -17,7 +16,7 @@ pub fn build(b: *Builder) void {
     exe.addCSourceFile("empty.c", &[0][]const u8{});
     exe.linkLibC();
 
-    const run_cmd = std.build.EmulatableRunStep.create(b, "run", exe);
+    const run_cmd = std.Build.EmulatableRunStep.create(b, "run", exe);
     run_cmd.expectStdOutEqual("Hello!\n");
     test_step.dependOn(&run_cmd.step);
 }
test/link/macho/entry/build.zig
@@ -1,7 +1,6 @@
 const std = @import("std");
-const Builder = std.build.Builder;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
 
     const test_step = b.step("test", "Test");
test/link/macho/headerpad/build.zig
@@ -1,9 +1,8 @@
 const std = @import("std");
 const builtin = @import("builtin");
-const Builder = std.build.Builder;
-const LibExeObjectStep = std.build.LibExeObjStep;
+const LibExeObjectStep = std.Build.LibExeObjStep;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
 
     const test_step = b.step("test", "Test");
@@ -94,7 +93,7 @@ pub fn build(b: *Builder) void {
     }
 }
 
-fn simpleExe(b: *Builder, optimize: std.builtin.OptimizeMode) *LibExeObjectStep {
+fn simpleExe(b: *std.Build, optimize: std.builtin.OptimizeMode) *LibExeObjectStep {
     const exe = b.addExecutable(.{
         .name = "main",
         .optimize = optimize,
test/link/macho/linksection/build.zig
@@ -1,6 +1,6 @@
 const std = @import("std");
 
-pub fn build(b: *std.build.Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
     const target = std.zig.CrossTarget{ .os_tag = .macos };
 
test/link/macho/needed_framework/build.zig
@@ -1,8 +1,7 @@
 const std = @import("std");
-const Builder = std.build.Builder;
-const LibExeObjectStep = std.build.LibExeObjStep;
+const LibExeObjectStep = std.Build.LibExeObjStep;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
 
     const test_step = b.step("test", "Test the program");
test/link/macho/needed_library/build.zig
@@ -1,8 +1,7 @@
 const std = @import("std");
-const Builder = std.build.Builder;
-const LibExeObjectStep = std.build.LibExeObjStep;
+const LibExeObjectStep = std.Build.LibExeObjStep;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
     const target: std.zig.CrossTarget = .{ .os_tag = .macos };
 
test/link/macho/objc/build.zig
@@ -1,7 +1,6 @@
 const std = @import("std");
-const Builder = std.build.Builder;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
 
     const test_step = b.step("test", "Test the program");
@@ -18,6 +17,6 @@ pub fn build(b: *Builder) void {
     // populate paths to the sysroot here.
     exe.linkFramework("Foundation");
 
-    const run_cmd = std.build.EmulatableRunStep.create(b, "run", exe);
+    const run_cmd = std.Build.EmulatableRunStep.create(b, "run", exe);
     test_step.dependOn(&run_cmd.step);
 }
test/link/macho/objcpp/build.zig
@@ -1,7 +1,6 @@
 const std = @import("std");
-const Builder = std.build.Builder;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
 
     const test_step = b.step("test", "Test the program");
test/link/macho/pagezero/build.zig
@@ -1,7 +1,6 @@
 const std = @import("std");
-const Builder = std.build.Builder;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
     const target: std.zig.CrossTarget = .{ .os_tag = .macos };
 
test/link/macho/search_strategy/build.zig
@@ -1,8 +1,7 @@
 const std = @import("std");
-const Builder = std.build.Builder;
-const LibExeObjectStep = std.build.LibExeObjStep;
+const LibExeObjectStep = std.Build.LibExeObjStep;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
     const target: std.zig.CrossTarget = .{ .os_tag = .macos };
 
@@ -29,14 +28,14 @@ pub fn build(b: *Builder) void {
         const exe = createScenario(b, optimize, target);
         exe.search_strategy = .paths_first;
 
-        const run = std.build.EmulatableRunStep.create(b, "run", exe);
+        const run = std.Build.EmulatableRunStep.create(b, "run", exe);
         run.cwd = b.pathFromRoot(".");
         run.expectStdOutEqual("Hello world");
         test_step.dependOn(&run.step);
     }
 }
 
-fn createScenario(b: *Builder, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep {
+fn createScenario(b: *std.Build, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep {
     const static = b.addStaticLibrary(.{
         .name = "a",
         .optimize = optimize,
@@ -44,7 +43,7 @@ fn createScenario(b: *Builder, optimize: std.builtin.OptimizeMode, target: std.z
     });
     static.addCSourceFile("a.c", &.{});
     static.linkLibC();
-    static.override_dest_dir = std.build.InstallDir{
+    static.override_dest_dir = std.Build.InstallDir{
         .custom = "static",
     };
     static.install();
@@ -57,7 +56,7 @@ fn createScenario(b: *Builder, optimize: std.builtin.OptimizeMode, target: std.z
     });
     dylib.addCSourceFile("a.c", &.{});
     dylib.linkLibC();
-    dylib.override_dest_dir = std.build.InstallDir{
+    dylib.override_dest_dir = std.Build.InstallDir{
         .custom = "dynamic",
     };
     dylib.install();
test/link/macho/stack_size/build.zig
@@ -1,7 +1,6 @@
 const std = @import("std");
-const Builder = std.build.Builder;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
     const target: std.zig.CrossTarget = .{ .os_tag = .macos };
 
test/link/macho/strict_validation/build.zig
@@ -1,9 +1,8 @@
 const std = @import("std");
 const builtin = @import("builtin");
-const Builder = std.build.Builder;
-const LibExeObjectStep = std.build.LibExeObjStep;
+const LibExeObjectStep = std.Build.LibExeObjStep;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
     const target: std.zig.CrossTarget = .{ .os_tag = .macos };
 
test/link/macho/tls/build.zig
@@ -1,7 +1,6 @@
 const std = @import("std");
-const Builder = std.build.Builder;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
     const target: std.zig.CrossTarget = .{ .os_tag = .macos };
 
test/link/macho/unwind_info/build.zig
@@ -1,9 +1,8 @@
 const std = @import("std");
 const builtin = @import("builtin");
-const Builder = std.build.Builder;
-const LibExeObjectStep = std.build.LibExeObjStep;
+const LibExeObjectStep = std.Build.LibExeObjStep;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
     const target: std.zig.CrossTarget = .{ .os_tag = .macos };
 
@@ -14,8 +13,8 @@ pub fn build(b: *Builder) void {
 }
 
 fn testUnwindInfo(
-    b: *Builder,
-    test_step: *std.build.Step,
+    b: *std.Build,
+    test_step: *std.Build.Step,
     optimize: std.builtin.OptimizeMode,
     target: std.zig.CrossTarget,
     dead_strip: bool,
@@ -52,7 +51,7 @@ fn testUnwindInfo(
     test_step.dependOn(&run_cmd.step);
 }
 
-fn createScenario(b: *Builder, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep {
+fn createScenario(b: *std.Build, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep {
     const exe = b.addExecutable(.{
         .name = "test",
         .optimize = optimize,
test/link/macho/uuid/build.zig
@@ -1,8 +1,7 @@
 const std = @import("std");
-const Builder = std.build.Builder;
-const LibExeObjectStep = std.build.LibExeObjStep;
+const LibExeObjectStep = std.Build.LibExeObjStep;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const test_step = b.step("test", "Test");
     test_step.dependOn(b.getInstallStep());
 
@@ -27,8 +26,8 @@ pub fn build(b: *Builder) void {
 }
 
 fn testUuid(
-    b: *Builder,
-    test_step: *std.build.Step,
+    b: *std.Build,
+    test_step: *std.Build.Step,
     optimize: std.builtin.OptimizeMode,
     target: std.zig.CrossTarget,
     comptime exp: []const u8,
@@ -52,7 +51,7 @@ fn testUuid(
     }
 }
 
-fn simpleDylib(b: *Builder, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep {
+fn simpleDylib(b: *std.Build, optimize: std.builtin.OptimizeMode, target: std.zig.CrossTarget) *LibExeObjectStep {
     const dylib = b.addSharedLibrary(.{
         .name = "test",
         .version = .{ .major = 1, .minor = 0 },
test/link/macho/weak_framework/build.zig
@@ -1,8 +1,7 @@
 const std = @import("std");
-const Builder = std.build.Builder;
-const LibExeObjectStep = std.build.LibExeObjStep;
+const LibExeObjectStep = std.Build.LibExeObjStep;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
 
     const test_step = b.step("test", "Test the program");
test/link/macho/weak_library/build.zig
@@ -1,8 +1,7 @@
 const std = @import("std");
-const Builder = std.build.Builder;
-const LibExeObjectStep = std.build.LibExeObjStep;
+const LibExeObjectStep = std.Build.LibExeObjStep;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
     const target: std.zig.CrossTarget = .{ .os_tag = .macos };
 
test/link/static_lib_as_system_lib/build.zig
@@ -1,7 +1,6 @@
 const std = @import("std");
-const Builder = std.build.Builder;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
     const target = b.standardTargetOptions(.{});
 
test/link/wasm/archive/build.zig
@@ -1,7 +1,6 @@
 const std = @import("std");
-const Builder = std.build.Builder;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const test_step = b.step("test", "Test");
     test_step.dependOn(b.getInstallStep());
 
test/link/wasm/basic-features/build.zig
@@ -1,6 +1,6 @@
 const std = @import("std");
 
-pub fn build(b: *std.build.Builder) void {
+pub fn build(b: *std.Build) void {
     // Library with explicitly set cpu features
     const lib = b.addSharedLibrary(.{
         .name = "lib",
test/link/wasm/bss/build.zig
@@ -1,7 +1,6 @@
 const std = @import("std");
-const Builder = std.build.Builder;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const test_step = b.step("test", "Test");
     test_step.dependOn(b.getInstallStep());
 
test/link/wasm/export/build.zig
@@ -1,6 +1,6 @@
 const std = @import("std");
 
-pub fn build(b: *std.build.Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
 
     const no_export = b.addSharedLibrary(.{
test/link/wasm/export-data/build.zig
@@ -1,7 +1,6 @@
 const std = @import("std");
-const Builder = std.build.Builder;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const test_step = b.step("test", "Test");
     test_step.dependOn(b.getInstallStep());
 
test/link/wasm/extern/build.zig
@@ -1,6 +1,6 @@
 const std = @import("std");
 
-pub fn build(b: *std.build.Builder) void {
+pub fn build(b: *std.Build) void {
     const exe = b.addExecutable(.{
         .name = "extern",
         .root_source_file = .{ .path = "main.zig" },
test/link/wasm/extern-mangle/build.zig
@@ -1,7 +1,6 @@
 const std = @import("std");
-const Builder = std.build.Builder;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const test_step = b.step("test", "Test");
     test_step.dependOn(b.getInstallStep());
 
test/link/wasm/function-table/build.zig
@@ -1,7 +1,6 @@
 const std = @import("std");
-const Builder = std.build.Builder;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
 
     const test_step = b.step("test", "Test");
test/link/wasm/infer-features/build.zig
@@ -1,6 +1,6 @@
 const std = @import("std");
 
-pub fn build(b: *std.build.Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
 
     // Wasm Object file which we will use to infer the features from
test/link/wasm/producers/build.zig
@@ -1,8 +1,7 @@
 const std = @import("std");
 const builtin = @import("builtin");
-const Builder = std.build.Builder;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const test_step = b.step("test", "Test");
     test_step.dependOn(b.getInstallStep());
 
test/link/wasm/segments/build.zig
@@ -1,7 +1,6 @@
 const std = @import("std");
-const Builder = std.build.Builder;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const test_step = b.step("test", "Test");
     test_step.dependOn(b.getInstallStep());
 
test/link/wasm/stack_pointer/build.zig
@@ -1,7 +1,6 @@
 const std = @import("std");
-const Builder = std.build.Builder;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const test_step = b.step("test", "Test");
     test_step.dependOn(b.getInstallStep());
 
test/link/wasm/type/build.zig
@@ -1,7 +1,6 @@
 const std = @import("std");
-const Builder = std.build.Builder;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const test_step = b.step("test", "Test");
     test_step.dependOn(b.getInstallStep());
 
test/src/compare_output.zig
@@ -1,7 +1,6 @@
 // This is the implementation of the test harness.
 // For the actual test cases, see test/compare_output.zig.
 const std = @import("std");
-const build = std.build;
 const ArrayList = std.ArrayList;
 const fmt = std.fmt;
 const mem = std.mem;
@@ -9,8 +8,8 @@ const fs = std.fs;
 const OptimizeMode = std.builtin.OptimizeMode;
 
 pub const CompareOutputContext = struct {
-    b: *build.Builder,
-    step: *build.Step,
+    b: *std.Build,
+    step: *std.Build.Step,
     test_index: usize,
     test_filter: ?[]const u8,
     optimize_modes: []const OptimizeMode,
test/src/run_translated_c.zig
@@ -1,15 +1,14 @@
 // This is the implementation of the test harness for running translated
 // C code. For the actual test cases, see test/run_translated_c.zig.
 const std = @import("std");
-const build = std.build;
 const ArrayList = std.ArrayList;
 const fmt = std.fmt;
 const mem = std.mem;
 const fs = std.fs;
 
 pub const RunTranslatedCContext = struct {
-    b: *build.Builder,
-    step: *build.Step,
+    b: *std.Build,
+    step: *std.Build.Step,
     test_index: usize,
     test_filter: ?[]const u8,
     target: std.zig.CrossTarget,
test/src/translate_c.zig
@@ -1,7 +1,6 @@
 // This is the implementation of the test harness.
 // For the actual test cases, see test/translate_c.zig.
 const std = @import("std");
-const build = std.build;
 const ArrayList = std.ArrayList;
 const fmt = std.fmt;
 const mem = std.mem;
@@ -9,8 +8,8 @@ const fs = std.fs;
 const CrossTarget = std.zig.CrossTarget;
 
 pub const TranslateCContext = struct {
-    b: *build.Builder,
-    step: *build.Step,
+    b: *std.Build,
+    step: *std.Build.Step,
     test_index: usize,
     test_filter: ?[]const u8,
 
test/standalone/brace_expansion/build.zig
@@ -1,6 +1,6 @@
-const Builder = @import("std").build.Builder;
+const std = @import("std");
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const main = b.addTest(.{
         .root_source_file = .{ .path = "main.zig" },
         .optimize = b.standardOptimizeOption(.{}),
test/standalone/c_compiler/build.zig
@@ -1,9 +1,8 @@
 const std = @import("std");
 const builtin = @import("builtin");
-const Builder = std.build.Builder;
 const CrossTarget = std.zig.CrossTarget;
 
-// TODO integrate this with the std.build executor API
+// TODO integrate this with the std.Build executor API
 fn isRunnableTarget(t: CrossTarget) bool {
     if (t.isNative()) return true;
 
@@ -11,7 +10,7 @@ fn isRunnableTarget(t: CrossTarget) bool {
         t.getCpuArch() == builtin.cpu.arch);
 }
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
     const target = b.standardTargetOptions(.{});
 
test/standalone/emit_asm_and_bin/build.zig
@@ -1,6 +1,6 @@
-const Builder = @import("std").build.Builder;
+const std = @import("std");
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const main = b.addTest(.{
         .root_source_file = .{ .path = "main.zig" },
         .optimize = b.standardOptimizeOption(.{}),
test/standalone/empty_env/build.zig
@@ -1,6 +1,6 @@
-const Builder = @import("std").build.Builder;
+const std = @import("std");
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const main = b.addExecutable(.{
         .name = "main",
         .root_source_file = .{ .path = "main.zig" },
test/standalone/global_linkage/build.zig
@@ -1,6 +1,6 @@
-const Builder = @import("std").build.Builder;
+const std = @import("std");
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
 
     const obj1 = b.addStaticLibrary(.{
test/standalone/install_raw_hex/build.zig
@@ -1,8 +1,8 @@
 const builtin = @import("builtin");
 const std = @import("std");
-const CheckFileStep = std.build.CheckFileStep;
+const CheckFileStep = std.Build.CheckFileStep;
 
-pub fn build(b: *std.build.Builder) void {
+pub fn build(b: *std.Build) void {
     const target = .{
         .cpu_arch = .thumb,
         .cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m4 },
test/standalone/issue_11595/build.zig
@@ -1,9 +1,8 @@
 const std = @import("std");
 const builtin = @import("builtin");
-const Builder = std.build.Builder;
 const CrossTarget = std.zig.CrossTarget;
 
-// TODO integrate this with the std.build executor API
+// TODO integrate this with the std.Build executor API
 fn isRunnableTarget(t: CrossTarget) bool {
     if (t.isNative()) return true;
 
@@ -11,7 +10,7 @@ fn isRunnableTarget(t: CrossTarget) bool {
         t.getCpuArch() == builtin.cpu.arch);
 }
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
     const target = b.standardTargetOptions(.{});
 
test/standalone/issue_12588/build.zig
@@ -1,7 +1,6 @@
 const std = @import("std");
-const Builder = std.build.Builder;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
     const target = b.standardTargetOptions(.{});
 
test/standalone/issue_12706/build.zig
@@ -1,9 +1,8 @@
 const std = @import("std");
 const builtin = @import("builtin");
-const Builder = std.build.Builder;
 const CrossTarget = std.zig.CrossTarget;
 
-// TODO integrate this with the std.build executor API
+// TODO integrate this with the std.Build executor API
 fn isRunnableTarget(t: CrossTarget) bool {
     if (t.isNative()) return true;
 
@@ -11,7 +10,7 @@ fn isRunnableTarget(t: CrossTarget) bool {
         t.getCpuArch() == builtin.cpu.arch);
 }
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
     const target = b.standardTargetOptions(.{});
 
test/standalone/issue_13030/build.zig
@@ -1,9 +1,8 @@
 const std = @import("std");
 const builtin = @import("builtin");
-const Builder = std.build.Builder;
 const CrossTarget = std.zig.CrossTarget;
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
     const target = b.standardTargetOptions(.{});
 
test/standalone/issue_339/build.zig
@@ -1,6 +1,6 @@
-const Builder = @import("std").build.Builder;
+const std = @import("std");
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const obj = b.addObject(.{
         .name = "test",
         .root_source_file = .{ .path = "test.zig" },
test/standalone/issue_5825/build.zig
@@ -1,6 +1,6 @@
-const Builder = @import("std").build.Builder;
+const std = @import("std");
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const target = .{
         .cpu_arch = .x86_64,
         .os_tag = .windows,
test/standalone/issue_7030/build.zig
@@ -1,6 +1,6 @@
-const Builder = @import("std").build.Builder;
+const std = @import("std");
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const exe = b.addExecutable(.{
         .name = "issue_7030",
         .root_source_file = .{ .path = "main.zig" },
test/standalone/issue_794/build.zig
@@ -1,6 +1,6 @@
-const Builder = @import("std").build.Builder;
+const std = @import("std");
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const test_artifact = b.addTest(.{
         .root_source_file = .{ .path = "main.zig" },
     });
test/standalone/issue_8550/build.zig
@@ -1,6 +1,6 @@
 const std = @import("std");
 
-pub fn build(b: *std.build.Builder) !void {
+pub fn build(b: *std.Build) !void {
     const target = std.zig.CrossTarget{
         .os_tag = .freestanding,
         .cpu_arch = .arm,
test/standalone/issue_9812/build.zig
@@ -1,6 +1,6 @@
 const std = @import("std");
 
-pub fn build(b: *std.build.Builder) !void {
+pub fn build(b: *std.Build) !void {
     const optimize = b.standardOptimizeOption(.{});
     const zip_add = b.addTest(.{
         .root_source_file = .{ .path = "main.zig" },
test/standalone/load_dynamic_library/build.zig
@@ -1,6 +1,6 @@
-const Builder = @import("std").build.Builder;
+const std = @import("std");
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const target = b.standardTargetOptions(.{});
     const optimize = b.standardOptimizeOption(.{});
 
test/standalone/main_pkg_path/build.zig
@@ -1,6 +1,6 @@
-const Builder = @import("std").build.Builder;
+const std = @import("std");
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const test_exe = b.addTest(.{
         .root_source_file = .{ .path = "a/test.zig" },
     });
test/standalone/mix_c_files/build.zig
@@ -1,9 +1,8 @@
 const std = @import("std");
 const builtin = @import("builtin");
-const Builder = std.build.Builder;
 const CrossTarget = std.zig.CrossTarget;
 
-// TODO integrate this with the std.build executor API
+// TODO integrate this with the std.Build executor API
 fn isRunnableTarget(t: CrossTarget) bool {
     if (t.isNative()) return true;
 
@@ -11,7 +10,7 @@ fn isRunnableTarget(t: CrossTarget) bool {
         t.getCpuArch() == builtin.cpu.arch);
 }
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
     const target = b.standardTargetOptions(.{});
 
test/standalone/mix_o_files/build.zig
@@ -1,6 +1,6 @@
-const Builder = @import("std").build.Builder;
+const std = @import("std");
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
 
     const obj = b.addObject(.{
test/standalone/options/build.zig
@@ -1,6 +1,6 @@
 const std = @import("std");
 
-pub fn build(b: *std.build.Builder) void {
+pub fn build(b: *std.Build) void {
     const target = b.standardTargetOptions(.{});
     const optimize = b.standardOptimizeOption(.{});
 
test/standalone/pie/build.zig
@@ -1,6 +1,6 @@
-const Builder = @import("std").build.Builder;
+const std = @import("std");
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const main = b.addTest(.{
         .root_source_file = .{ .path = "main.zig" },
         .optimize = b.standardOptimizeOption(.{}),
test/standalone/pkg_import/build.zig
@@ -1,6 +1,6 @@
-const Builder = @import("std").build.Builder;
+const std = @import("std");
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
 
     const exe = b.addExecutable(.{
test/standalone/shared_library/build.zig
@@ -1,6 +1,6 @@
-const Builder = @import("std").build.Builder;
+const std = @import("std");
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
     const target = b.standardTargetOptions(.{});
     const lib = b.addSharedLibrary(.{
test/standalone/static_c_lib/build.zig
@@ -1,6 +1,6 @@
-const Builder = @import("std").build.Builder;
+const std = @import("std");
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
 
     const foo = b.addStaticLibrary(.{
test/standalone/test_runner_path/build.zig
@@ -1,6 +1,6 @@
-const Builder = @import("std").build.Builder;
+const std = @import("std");
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const test_exe = b.addTest(.{
         .root_source_file = .{ .path = "test.zig" },
         .kind = .test_exe,
test/standalone/use_alias/build.zig
@@ -1,6 +1,6 @@
-const Builder = @import("std").build.Builder;
+const std = @import("std");
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const main = b.addTest(.{
         .root_source_file = .{ .path = "main.zig" },
         .optimize = b.standardOptimizeOption(.{}),
test/standalone/windows_spawn/build.zig
@@ -1,6 +1,6 @@
-const Builder = @import("std").build.Builder;
+const std = @import("std");
 
-pub fn build(b: *Builder) void {
+pub fn build(b: *std.Build) void {
     const optimize = b.standardOptimizeOption(.{});
 
     const hello = b.addExecutable(.{
test/tests.zig
@@ -1,7 +1,6 @@
 const std = @import("std");
 const builtin = @import("builtin");
 const debug = std.debug;
-const build = std.build;
 const CrossTarget = std.zig.CrossTarget;
 const io = std.io;
 const fs = std.fs;
@@ -9,9 +8,10 @@ const mem = std.mem;
 const fmt = std.fmt;
 const ArrayList = std.ArrayList;
 const OptimizeMode = std.builtin.OptimizeMode;
-const LibExeObjStep = build.LibExeObjStep;
+const LibExeObjStep = std.Build.LibExeObjStep;
 const Allocator = mem.Allocator;
-const ExecError = build.Builder.ExecError;
+const ExecError = std.Build.ExecError;
+const Step = std.Build.Step;
 
 // Cases
 const compare_output = @import("compare_output.zig");
@@ -462,7 +462,7 @@ const test_targets = blk: {
 
 const max_stdout_size = 1 * 1024 * 1024; // 1 MB
 
-pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode) *build.Step {
+pub fn addCompareOutputTests(b: *std.Build, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode) *Step {
     const cases = b.allocator.create(CompareOutputContext) catch unreachable;
     cases.* = CompareOutputContext{
         .b = b,
@@ -477,7 +477,7 @@ pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8, optimi
     return cases.step;
 }
 
-pub fn addStackTraceTests(b: *build.Builder, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode) *build.Step {
+pub fn addStackTraceTests(b: *std.Build, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode) *Step {
     const cases = b.allocator.create(StackTracesContext) catch unreachable;
     cases.* = StackTracesContext{
         .b = b,
@@ -493,7 +493,7 @@ pub fn addStackTraceTests(b: *build.Builder, test_filter: ?[]const u8, optimize_
 }
 
 pub fn addStandaloneTests(
-    b: *build.Builder,
+    b: *std.Build,
     test_filter: ?[]const u8,
     optimize_modes: []const OptimizeMode,
     skip_non_native: bool,
@@ -506,7 +506,7 @@ pub fn addStandaloneTests(
     enable_wasmtime: bool,
     enable_wine: bool,
     enable_symlinks_windows: bool,
-) *build.Step {
+) *Step {
     const cases = b.allocator.create(StandaloneContext) catch unreachable;
     cases.* = StandaloneContext{
         .b = b,
@@ -532,13 +532,13 @@ pub fn addStandaloneTests(
 }
 
 pub fn addLinkTests(
-    b: *build.Builder,
+    b: *std.Build,
     test_filter: ?[]const u8,
     optimize_modes: []const OptimizeMode,
     enable_macos_sdk: bool,
     omit_stage2: bool,
     enable_symlinks_windows: bool,
-) *build.Step {
+) *Step {
     const cases = b.allocator.create(StandaloneContext) catch unreachable;
     cases.* = StandaloneContext{
         .b = b,
@@ -556,7 +556,7 @@ pub fn addLinkTests(
     return cases.step;
 }
 
-pub fn addCliTests(b: *build.Builder, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode) *build.Step {
+pub fn addCliTests(b: *std.Build, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode) *Step {
     _ = test_filter;
     _ = optimize_modes;
     const step = b.step("test-cli", "Test the command line interface");
@@ -577,7 +577,7 @@ pub fn addCliTests(b: *build.Builder, test_filter: ?[]const u8, optimize_modes:
     return step;
 }
 
-pub fn addAssembleAndLinkTests(b: *build.Builder, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode) *build.Step {
+pub fn addAssembleAndLinkTests(b: *std.Build, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode) *Step {
     const cases = b.allocator.create(CompareOutputContext) catch unreachable;
     cases.* = CompareOutputContext{
         .b = b,
@@ -592,7 +592,7 @@ pub fn addAssembleAndLinkTests(b: *build.Builder, test_filter: ?[]const u8, opti
     return cases.step;
 }
 
-pub fn addTranslateCTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {
+pub fn addTranslateCTests(b: *std.Build, test_filter: ?[]const u8) *Step {
     const cases = b.allocator.create(TranslateCContext) catch unreachable;
     cases.* = TranslateCContext{
         .b = b,
@@ -607,10 +607,10 @@ pub fn addTranslateCTests(b: *build.Builder, test_filter: ?[]const u8) *build.St
 }
 
 pub fn addRunTranslatedCTests(
-    b: *build.Builder,
+    b: *std.Build,
     test_filter: ?[]const u8,
     target: std.zig.CrossTarget,
-) *build.Step {
+) *Step {
     const cases = b.allocator.create(RunTranslatedCContext) catch unreachable;
     cases.* = .{
         .b = b,
@@ -625,7 +625,7 @@ pub fn addRunTranslatedCTests(
     return cases.step;
 }
 
-pub fn addGenHTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {
+pub fn addGenHTests(b: *std.Build, test_filter: ?[]const u8) *Step {
     const cases = b.allocator.create(GenHContext) catch unreachable;
     cases.* = GenHContext{
         .b = b,
@@ -640,7 +640,7 @@ pub fn addGenHTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {
 }
 
 pub fn addPkgTests(
-    b: *build.Builder,
+    b: *std.Build,
     test_filter: ?[]const u8,
     root_src: []const u8,
     name: []const u8,
@@ -651,7 +651,7 @@ pub fn addPkgTests(
     skip_libc: bool,
     skip_stage1: bool,
     skip_stage2: bool,
-) *build.Step {
+) *Step {
     const step = b.step(b.fmt("test-{s}", .{name}), desc);
 
     for (test_targets) |test_target| {
@@ -742,8 +742,8 @@ pub fn addPkgTests(
 }
 
 pub const StackTracesContext = struct {
-    b: *build.Builder,
-    step: *build.Step,
+    b: *std.Build,
+    step: *Step,
     test_index: usize,
     test_filter: ?[]const u8,
     optimize_modes: []const OptimizeMode,
@@ -840,7 +840,7 @@ pub const StackTracesContext = struct {
     const RunAndCompareStep = struct {
         pub const base_id = .custom;
 
-        step: build.Step,
+        step: Step,
         context: *StackTracesContext,
         exe: *LibExeObjStep,
         name: []const u8,
@@ -858,7 +858,7 @@ pub const StackTracesContext = struct {
             const allocator = context.b.allocator;
             const ptr = allocator.create(RunAndCompareStep) catch unreachable;
             ptr.* = RunAndCompareStep{
-                .step = build.Step.init(.custom, "StackTraceCompareOutputStep", allocator, make),
+                .step = Step.init(.custom, "StackTraceCompareOutputStep", allocator, make),
                 .context = context,
                 .exe = exe,
                 .name = name,
@@ -871,7 +871,7 @@ pub const StackTracesContext = struct {
             return ptr;
         }
 
-        fn make(step: *build.Step) !void {
+        fn make(step: *Step) !void {
             const self = @fieldParentPtr(RunAndCompareStep, "step", step);
             const b = self.context.b;
 
@@ -1014,8 +1014,8 @@ pub const StackTracesContext = struct {
 };
 
 pub const StandaloneContext = struct {
-    b: *build.Builder,
-    step: *build.Step,
+    b: *std.Build,
+    step: *Step,
     test_index: usize,
     test_filter: ?[]const u8,
     optimize_modes: []const OptimizeMode,
@@ -1150,8 +1150,8 @@ pub const StandaloneContext = struct {
 };
 
 pub const GenHContext = struct {
-    b: *build.Builder,
-    step: *build.Step,
+    b: *std.Build,
+    step: *Step,
     test_index: usize,
     test_filter: ?[]const u8,
 
@@ -1178,7 +1178,7 @@ pub const GenHContext = struct {
     };
 
     const GenHCmpOutputStep = struct {
-        step: build.Step,
+        step: Step,
         context: *GenHContext,
         obj: *LibExeObjStep,
         name: []const u8,
@@ -1194,7 +1194,7 @@ pub const GenHContext = struct {
             const allocator = context.b.allocator;
             const ptr = allocator.create(GenHCmpOutputStep) catch unreachable;
             ptr.* = GenHCmpOutputStep{
-                .step = build.Step.init(.Custom, "ParseCCmpOutput", allocator, make),
+                .step = Step.init(.Custom, "ParseCCmpOutput", allocator, make),
                 .context = context,
                 .obj = obj,
                 .name = name,
@@ -1206,7 +1206,7 @@ pub const GenHContext = struct {
             return ptr;
         }
 
-        fn make(step: *build.Step) !void {
+        fn make(step: *Step) !void {
             const self = @fieldParentPtr(GenHCmpOutputStep, "step", step);
             const b = self.context.b;
 
@@ -1348,7 +1348,7 @@ const c_abi_targets = [_]CrossTarget{
     },
 };
 
-pub fn addCAbiTests(b: *build.Builder, skip_non_native: bool, skip_release: bool) *build.Step {
+pub fn addCAbiTests(b: *std.Build, skip_non_native: bool, skip_release: bool) *Step {
     const step = b.step("test-c-abi", "Run the C ABI tests");
 
     const optimize_modes: [2]OptimizeMode = .{ .Debug, .ReleaseFast };
build.zig
@@ -1,19 +1,18 @@
 const std = @import("std");
 const builtin = std.builtin;
-const Builder = std.build.Builder;
 const tests = @import("test/tests.zig");
 const BufMap = std.BufMap;
 const mem = std.mem;
 const ArrayList = std.ArrayList;
 const io = std.io;
 const fs = std.fs;
-const InstallDirectoryOptions = std.build.InstallDirectoryOptions;
+const InstallDirectoryOptions = std.Build.InstallDirectoryOptions;
 const assert = std.debug.assert;
 
 const zig_version = std.builtin.Version{ .major = 0, .minor = 11, .patch = 0 };
 const stack_size = 32 * 1024 * 1024;
 
-pub fn build(b: *Builder) !void {
+pub fn build(b: *std.Build) !void {
     const release = b.option(bool, "release", "Build in release mode") orelse false;
     const only_c = b.option(bool, "only-c", "Translate the Zig compiler to C code, with only the C backend enabled") orelse false;
     const target = t: {
@@ -477,7 +476,7 @@ pub fn build(b: *Builder) !void {
     try addWasiUpdateStep(b, version);
 }
 
-fn addWasiUpdateStep(b: *Builder, version: [:0]const u8) !void {
+fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {
     const semver = try std.SemanticVersion.parse(version);
 
     var target: std.zig.CrossTarget = .{
@@ -514,10 +513,10 @@ fn addWasiUpdateStep(b: *Builder, version: [:0]const u8) !void {
 }
 
 fn addCompilerStep(
-    b: *Builder,
+    b: *std.Build,
     optimize: std.builtin.OptimizeMode,
     target: std.zig.CrossTarget,
-) *std.build.LibExeObjStep {
+) *std.Build.LibExeObjStep {
     const exe = b.addExecutable(.{
         .name = "zig",
         .root_source_file = .{ .path = "src/main.zig" },
@@ -543,9 +542,9 @@ const exe_cflags = [_][]const u8{
 };
 
 fn addCmakeCfgOptionsToExe(
-    b: *Builder,
+    b: *std.Build,
     cfg: CMakeConfig,
-    exe: *std.build.LibExeObjStep,
+    exe: *std.Build.LibExeObjStep,
     use_zig_libcxx: bool,
 ) !void {
     if (exe.target.isDarwin()) {
@@ -624,7 +623,7 @@ fn addCmakeCfgOptionsToExe(
     }
 }
 
-fn addStaticLlvmOptionsToExe(exe: *std.build.LibExeObjStep) !void {
+fn addStaticLlvmOptionsToExe(exe: *std.Build.LibExeObjStep) !void {
     // Adds the Zig C++ sources which both stage1 and stage2 need.
     //
     // We need this because otherwise zig_clang_cc1_main.cpp ends up pulling
@@ -661,9 +660,9 @@ fn addStaticLlvmOptionsToExe(exe: *std.build.LibExeObjStep) !void {
 }
 
 fn addCxxKnownPath(
-    b: *Builder,
+    b: *std.Build,
     ctx: CMakeConfig,
-    exe: *std.build.LibExeObjStep,
+    exe: *std.Build.LibExeObjStep,
     objname: []const u8,
     errtxt: ?[]const u8,
     need_cpp_includes: bool,
@@ -696,7 +695,7 @@ fn addCxxKnownPath(
     }
 }
 
-fn addCMakeLibraryList(exe: *std.build.LibExeObjStep, list: []const u8) void {
+fn addCMakeLibraryList(exe: *std.Build.LibExeObjStep, list: []const u8) void {
     var it = mem.tokenize(u8, list, ";");
     while (it.next()) |lib| {
         if (mem.startsWith(u8, lib, "-l")) {
@@ -710,7 +709,7 @@ fn addCMakeLibraryList(exe: *std.build.LibExeObjStep, list: []const u8) void {
 }
 
 const CMakeConfig = struct {
-    llvm_linkage: std.build.LibExeObjStep.Linkage,
+    llvm_linkage: std.Build.LibExeObjStep.Linkage,
     cmake_binary_dir: []const u8,
     cmake_prefix_path: []const u8,
     cmake_static_library_prefix: []const u8,
@@ -727,7 +726,7 @@ const CMakeConfig = struct {
 
 const max_config_h_bytes = 1 * 1024 * 1024;
 
-fn findConfigH(b: *Builder, config_h_path_option: ?[]const u8) ?[]const u8 {
+fn findConfigH(b: *std.Build, config_h_path_option: ?[]const u8) ?[]const u8 {
     if (config_h_path_option) |path| {
         var config_h_or_err = fs.cwd().openFile(path, .{});
         if (config_h_or_err) |*file| {
@@ -773,7 +772,7 @@ fn findConfigH(b: *Builder, config_h_path_option: ?[]const u8) ?[]const u8 {
     } else unreachable; // TODO should not need `else unreachable`.
 }
 
-fn parseConfigH(b: *Builder, config_h_text: []const u8) ?CMakeConfig {
+fn parseConfigH(b: *std.Build, config_h_text: []const u8) ?CMakeConfig {
     var ctx: CMakeConfig = .{
         .llvm_linkage = undefined,
         .cmake_binary_dir = undefined,
@@ -862,7 +861,7 @@ fn parseConfigH(b: *Builder, config_h_text: []const u8) ?CMakeConfig {
     return ctx;
 }
 
-fn toNativePathSep(b: *Builder, s: []const u8) []u8 {
+fn toNativePathSep(b: *std.Build, s: []const u8) []u8 {
     const duplicated = b.allocator.dupe(u8, s) catch unreachable;
     for (duplicated) |*byte| switch (byte.*) {
         '/' => byte.* = fs.path.sep,