diff --git a/build.zig b/build.zig index 1d44c249c..3cb5eccf5 100644 --- a/build.zig +++ b/build.zig @@ -45,7 +45,7 @@ pub fn build(b: *std.Build) !void { }); const docgen_cmd = b.addRunArtifact(docgen_exe); - docgen_cmd.addArgs(&.{ "--zig", b.zig_exe }); + docgen_cmd.addArgs(&.{ "--zig", b.graph.zig_exe }); if (b.zig_lib_dir) |p| { docgen_cmd.addArg("--zig-lib-dir"); docgen_cmd.addDirectoryArg(p); @@ -410,14 +410,14 @@ pub fn build(b: *std.Build) !void { test_cases_options.addOption(bool, "only_c", only_c); test_cases_options.addOption(bool, "only_core_functionality", true); test_cases_options.addOption(bool, "only_reduce", false); - test_cases_options.addOption(bool, "enable_qemu", b.enable_qemu); - test_cases_options.addOption(bool, "enable_wine", b.enable_wine); - test_cases_options.addOption(bool, "enable_wasmtime", b.enable_wasmtime); - test_cases_options.addOption(bool, "enable_rosetta", b.enable_rosetta); - test_cases_options.addOption(bool, "enable_darling", b.enable_darling); + test_cases_options.addOption(bool, "enable_qemu", b.graph.enable_qemu); + test_cases_options.addOption(bool, "enable_wine", b.graph.enable_wine); + test_cases_options.addOption(bool, "enable_wasmtime", b.graph.enable_wasmtime); + test_cases_options.addOption(bool, "enable_rosetta", b.graph.enable_rosetta); + test_cases_options.addOption(bool, "enable_darling", b.graph.enable_darling); test_cases_options.addOption(u32, "mem_leak_frames", mem_leak_frames * 2); test_cases_options.addOption(bool, "value_tracing", value_tracing); - test_cases_options.addOption(?[]const u8, "glibc_runtimes_dir", b.glibc_runtimes_dir); + test_cases_options.addOption(?[]const u8, "glibc_runtimes_dir", b.graph.glibc_runtimes_dir); test_cases_options.addOption([:0]const u8, "version", version); test_cases_options.addOption(std.SemanticVersion, "semver", semver); test_cases_options.addOption(?[]const u8, "test_filter", test_filter); @@ -884,7 +884,7 @@ fn findConfigH(b: *std.Build, config_h_path_option: ?[]const u8) ?[]const u8 { } } - var check_dir = fs.path.dirname(b.zig_exe).?; + var check_dir = fs.path.dirname(b.graph.zig_exe).?; while (true) { var dir = fs.cwd().openDir(check_dir, .{}) catch unreachable; defer dir.close(); diff --git a/deps/aro/build/GenerateDef.zig b/deps/aro/build/GenerateDef.zig index 5c0f8d4b1..c6e861529 100644 --- a/deps/aro/build/GenerateDef.zig +++ b/deps/aro/build/GenerateDef.zig @@ -53,7 +53,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { const self = @fieldParentPtr(GenerateDef, "step", step); const arena = b.allocator; - var man = b.cache.obtain(); + var man = b.graph.cache.obtain(); defer man.deinit(); // Random bytes to make GenerateDef unique. Refresh this with new diff --git a/lib/build_runner.zig b/lib/build_runner.zig index 4e478e798..156c26e7e 100644 --- a/lib/build_runner.zig +++ b/lib/build_runner.zig @@ -46,11 +46,6 @@ pub fn main() !void { return error.InvalidArgs; }; - const host: std.Build.ResolvedTarget = .{ - .query = .{}, - .result = try std.zig.system.resolveTargetQuery(.{}), - }; - const build_root_directory: std.Build.Cache.Directory = .{ .path = build_root, .handle = try std.fs.cwd().openDir(build_root, .{}), @@ -66,28 +61,28 @@ pub fn main() !void { .handle = try std.fs.cwd().makeOpenPath(global_cache_root, .{}), }; - var cache: std.Build.Cache = .{ - .gpa = arena, - .manifest_dir = try local_cache_directory.handle.makeOpenPath("h", .{}), + var graph: std.Build.Graph = .{ + .arena = arena, + .cache = .{ + .gpa = arena, + .manifest_dir = try local_cache_directory.handle.makeOpenPath("h", .{}), + }, + .zig_exe = zig_exe, + .env_map = try process.getEnvMap(arena), + .global_cache_root = global_cache_directory, }; - cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() }); - cache.addPrefix(build_root_directory); - cache.addPrefix(local_cache_directory); - cache.addPrefix(global_cache_directory); - cache.hash.addBytes(builtin.zig_version_string); - var system_library_options: std.StringArrayHashMapUnmanaged(std.Build.SystemLibraryMode) = .{}; + graph.cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() }); + graph.cache.addPrefix(build_root_directory); + graph.cache.addPrefix(local_cache_directory); + graph.cache.addPrefix(global_cache_directory); + graph.cache.hash.addBytes(builtin.zig_version_string); const builder = try std.Build.create( - arena, - zig_exe, + &graph, build_root_directory, local_cache_directory, - global_cache_directory, - host, - &cache, dependencies.root_deps, - &system_library_options, ); var targets = ArrayList([]const u8).init(arena); @@ -132,10 +127,16 @@ pub fn main() !void { steps_menu = true; } else if (mem.eql(u8, arg, "--system-lib")) { const name = nextArgOrFatal(args, &arg_idx); - builder.system_library_options.put(arena, name, .user_enabled) catch @panic("OOM"); + graph.system_library_options.put(arena, name, .user_enabled) catch @panic("OOM"); } else if (mem.eql(u8, arg, "--no-system-lib")) { const name = nextArgOrFatal(args, &arg_idx); - builder.system_library_options.put(arena, name, .user_disabled) catch @panic("OOM"); + graph.system_library_options.put(arena, name, .user_disabled) catch @panic("OOM"); + } else if (mem.eql(u8, arg, "--host-target")) { + graph.host_query_options.arch_os_abi = nextArgOrFatal(args, &arg_idx); + } else if (mem.eql(u8, arg, "--host-cpu")) { + graph.host_query_options.cpu_features = nextArgOrFatal(args, &arg_idx); + } else if (mem.eql(u8, arg, "--host-dynamic-linker")) { + graph.host_query_options.dynamic_linker = nextArgOrFatal(args, &arg_idx); } else if (mem.eql(u8, arg, "--prefix-lib-dir")) { dir_list.lib_dir = nextArgOrFatal(args, &arg_idx); } else if (mem.eql(u8, arg, "--prefix-exe-dir")) { @@ -193,7 +194,7 @@ pub fn main() !void { } else if (mem.eql(u8, arg, "--debug-compile-errors")) { builder.debug_compile_errors = true; } else if (mem.eql(u8, arg, "--glibc-runtimes")) { - builder.glibc_runtimes_dir = nextArgOrFatal(args, &arg_idx); + graph.glibc_runtimes_dir = nextArgOrFatal(args, &arg_idx); } else if (mem.eql(u8, arg, "--verbose-link")) { builder.verbose_link = true; } else if (mem.eql(u8, arg, "--verbose-air")) { @@ -213,25 +214,25 @@ pub fn main() !void { } else if (mem.eql(u8, arg, "--prominent-compile-errors")) { prominent_compile_errors = true; } else if (mem.eql(u8, arg, "-fwine")) { - builder.enable_wine = true; + graph.enable_wine = true; } else if (mem.eql(u8, arg, "-fno-wine")) { - builder.enable_wine = false; + graph.enable_wine = false; } else if (mem.eql(u8, arg, "-fqemu")) { - builder.enable_qemu = true; + graph.enable_qemu = true; } else if (mem.eql(u8, arg, "-fno-qemu")) { - builder.enable_qemu = false; + graph.enable_qemu = false; } else if (mem.eql(u8, arg, "-fwasmtime")) { - builder.enable_wasmtime = true; + graph.enable_wasmtime = true; } else if (mem.eql(u8, arg, "-fno-wasmtime")) { - builder.enable_wasmtime = false; + graph.enable_wasmtime = false; } else if (mem.eql(u8, arg, "-frosetta")) { - builder.enable_rosetta = true; + graph.enable_rosetta = true; } else if (mem.eql(u8, arg, "-fno-rosetta")) { - builder.enable_rosetta = false; + graph.enable_rosetta = false; } else if (mem.eql(u8, arg, "-fdarling")) { - builder.enable_darling = true; + graph.enable_darling = true; } else if (mem.eql(u8, arg, "-fno-darling")) { - builder.enable_darling = false; + graph.enable_darling = false; } else if (mem.eql(u8, arg, "-freference-trace")) { builder.reference_trace = 256; } else if (mem.startsWith(u8, arg, "-freference-trace=")) { @@ -266,11 +267,19 @@ pub fn main() !void { } } + const host_query = std.Build.parseTargetQuery(graph.host_query_options) catch |err| switch (err) { + error.ParseFailed => process.exit(1), + }; + builder.host = .{ + .query = .{}, + .result = try std.zig.system.resolveTargetQuery(host_query), + }; + const stderr = std.io.getStdErr(); const ttyconf = get_tty_conf(color, stderr); switch (ttyconf) { - .no_color => try builder.env_map.put("NO_COLOR", "1"), - .escape_codes => try builder.env_map.put("YES_COLOR", "1"), + .no_color => try graph.env_map.put("NO_COLOR", "1"), + .escape_codes => try graph.env_map.put("YES_COLOR", "1"), .windows_api => {}, } @@ -1029,7 +1038,7 @@ fn usage(b: *std.Build, out_stream: anytype) !void { \\ \\Steps: \\ - , .{b.zig_exe}); + , .{b.graph.zig_exe}); try steps(b, out_stream); try out_stream.writeAll( @@ -1104,22 +1113,23 @@ fn usage(b: *std.Build, out_stream: anytype) !void { \\ --system [dir] System Package Mode. Disable fetching; prefer system libs \\ --host-target [triple] Use the provided target as the host \\ --host-cpu [cpu] Use the provided CPU as the host + \\ --host-dynamic-linker [path] Use the provided dynamic linker as the host \\ --system-lib [name] Use the system-provided library \\ --no-system-lib [name] Do not use the system-provided library \\ \\ Available System Library Integrations: Enabled: \\ ); - if (b.system_library_options.entries.len == 0) { + if (b.graph.system_library_options.entries.len == 0) { try out_stream.writeAll(" (none) -\n"); } else { - for (b.system_library_options.keys(), b.system_library_options.values()) |name, v| { + for (b.graph.system_library_options.keys(), b.graph.system_library_options.values()) |k, v| { const status = switch (v) { .declared_enabled => "yes", .declared_disabled => "no", .user_enabled, .user_disabled => unreachable, // already emitted error }; - try out_stream.print(" {s:<43} {s}\n", .{ name, status }); + try out_stream.print(" {s:<43} {s}\n", .{ k, status }); } } @@ -1203,7 +1213,7 @@ fn fatal(comptime f: []const u8, args: anytype) noreturn { fn validateSystemLibraryOptions(b: *std.Build) void { var bad = false; - for (b.system_library_options.keys(), b.system_library_options.values()) |k, v| { + for (b.graph.system_library_options.keys(), b.graph.system_library_options.values()) |k, v| { switch (v) { .user_disabled, .user_enabled => { // The user tried to enable or disable a system library integration, but diff --git a/lib/std/Build.zig b/lib/std/Build.zig index a9176debb..828bed955 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -22,15 +22,14 @@ pub const Cache = @import("Build/Cache.zig"); pub const Step = @import("Build/Step.zig"); pub const Module = @import("Build/Module.zig"); +/// Shared state among all Build instances. +graph: *Graph, install_tls: TopLevelStep, uninstall_tls: TopLevelStep, allocator: Allocator, user_input_options: UserInputOptionsMap, available_options_map: AvailableOptionsMap, available_options_list: ArrayList(AvailableOption), -/// All Build instances share this hash map. -system_library_options: *std.StringArrayHashMapUnmanaged(SystemLibraryMode), -system_package_mode: bool, verbose: bool, verbose_link: bool, verbose_cc: bool, @@ -41,9 +40,7 @@ verbose_cimport: bool, verbose_llvm_cpu_features: bool, reference_trace: ?u32 = null, invalid_user_input: bool, -zig_exe: [:0]const u8, default_step: *Step, -env_map: *EnvMap, top_level_steps: std.StringArrayHashMapUnmanaged(*TopLevelStep), install_prefix: []const u8, dest_dir: ?[]const u8, @@ -52,14 +49,12 @@ exe_dir: []const u8, h_dir: []const u8, install_path: []const u8, sysroot: ?[]const u8 = null, -search_prefixes: ArrayList([]const u8), +search_prefixes: std.ArrayListUnmanaged([]const u8), libc_file: ?[]const u8 = null, installed_files: ArrayList(InstalledFile), /// Path to the directory containing build.zig. build_root: Cache.Directory, cache_root: Cache.Directory, -global_cache_root: Cache.Directory, -cache: *Cache, zig_lib_dir: ?LazyPath, pkg_config_pkg_list: ?(PkgConfigError![]const PkgConfigPkg) = null, args: ?[][]const u8 = null, @@ -71,22 +66,6 @@ debug_pkg_config: bool = false, /// Set to 0 to disable stack collection. debug_stack_frames_count: u8 = 8, -/// 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: ResolvedTarget, @@ -101,9 +80,38 @@ initialized_deps: *InitializedDepMap, /// A mapping from dependency names to package hashes. available_deps: AvailableDeps, +/// Shared state among all Build instances. +/// Settings that are here rather than in Build are not configurable per-package. +pub const Graph = struct { + arena: Allocator, + system_library_options: std.StringArrayHashMapUnmanaged(SystemLibraryMode) = .{}, + system_package_mode: bool = false, + cache: Cache, + zig_exe: [:0]const u8, + env_map: EnvMap, + global_cache_root: Cache.Directory, + host_query_options: std.Target.Query.ParseOptions = .{}, + + /// 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, +}; + const AvailableDeps = []const struct { []const u8, []const u8 }; -pub const SystemLibraryMode = enum { +const SystemLibraryMode = enum { /// User asked for the library to be disabled. /// The build runner has not confirmed whether the setting is recognized yet. user_disabled, @@ -226,29 +234,20 @@ pub const DirList = struct { }; pub fn create( - allocator: Allocator, - zig_exe: [:0]const u8, + graph: *Graph, build_root: Cache.Directory, cache_root: Cache.Directory, - global_cache_root: Cache.Directory, - host: ResolvedTarget, - cache: *Cache, available_deps: AvailableDeps, - system_library_options: *std.StringArrayHashMapUnmanaged(SystemLibraryMode), ) !*Build { - const env_map = try allocator.create(EnvMap); - env_map.* = try process.getEnvMap(allocator); + const arena = graph.arena; + const initialized_deps = try arena.create(InitializedDepMap); + initialized_deps.* = InitializedDepMap.initContext(arena, .{ .allocator = arena }); - const initialized_deps = try allocator.create(InitializedDepMap); - initialized_deps.* = InitializedDepMap.initContext(allocator, .{ .allocator = allocator }); - - const self = try allocator.create(Build); + const self = try arena.create(Build); self.* = .{ - .zig_exe = zig_exe, + .graph = graph, .build_root = build_root, .cache_root = cache_root, - .global_cache_root = global_cache_root, - .cache = cache, .verbose = false, .verbose_link = false, .verbose_cc = false, @@ -258,20 +257,19 @@ pub fn create( .verbose_cimport = false, .verbose_llvm_cpu_features = 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), + .allocator = arena, + .user_input_options = UserInputOptionsMap.init(arena), + .available_options_map = AvailableOptionsMap.init(arena), + .available_options_list = ArrayList(AvailableOption).init(arena), .top_level_steps = .{}, .default_step = undefined, - .env_map = env_map, - .search_prefixes = ArrayList([]const u8).init(allocator), + .search_prefixes = .{}, .install_prefix = undefined, .lib_dir = undefined, .exe_dir = undefined, .h_dir = undefined, - .dest_dir = env_map.get("DESTDIR"), - .installed_files = ArrayList(InstalledFile).init(allocator), + .dest_dir = graph.env_map.get("DESTDIR"), + .installed_files = ArrayList(InstalledFile).init(arena), .install_tls = .{ .step = Step.init(.{ .id = .top_level, @@ -292,16 +290,14 @@ pub fn create( .zig_lib_dir = null, .install_path = undefined, .args = null, - .host = host, - .modules = std.StringArrayHashMap(*Module).init(allocator), - .named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(allocator), + .host = undefined, + .modules = std.StringArrayHashMap(*Module).init(arena), + .named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(arena), .initialized_deps = initialized_deps, .available_deps = available_deps, - .system_library_options = system_library_options, - .system_package_mode = false, }; - try self.top_level_steps.put(allocator, self.install_tls.step.name, &self.install_tls); - try self.top_level_steps.put(allocator, self.uninstall_tls.step.name, &self.uninstall_tls); + try self.top_level_steps.put(arena, self.install_tls.step.name, &self.install_tls); + try self.top_level_steps.put(arena, self.uninstall_tls.step.name, &self.uninstall_tls); self.default_step = &self.install_tls.step; return self; } @@ -328,6 +324,7 @@ fn createChildOnly( const allocator = parent.allocator; const child = try allocator.create(Build); child.* = .{ + .graph = parent.graph, .allocator = allocator, .install_tls = .{ .step = Step.init(.{ @@ -359,9 +356,7 @@ fn createChildOnly( .verbose_llvm_cpu_features = parent.verbose_llvm_cpu_features, .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 = .{}, .install_prefix = undefined, .dest_dir = parent.dest_dir, @@ -375,26 +370,16 @@ fn createChildOnly( .installed_files = ArrayList(InstalledFile).init(allocator), .build_root = build_root, .cache_root = parent.cache_root, - .global_cache_root = parent.global_cache_root, - .cache = parent.cache, .zig_lib_dir = parent.zig_lib_dir, .debug_log_scopes = parent.debug_log_scopes, .debug_compile_errors = parent.debug_compile_errors, .debug_pkg_config = parent.debug_pkg_config, - .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 }), .modules = std.StringArrayHashMap(*Module).init(allocator), .named_writefiles = std.StringArrayHashMap(*Step.WriteFile).init(allocator), .initialized_deps = parent.initialized_deps, .available_deps = pkg_deps, - .system_library_options = parent.system_library_options, - .system_package_mode = parent.system_package_mode, }; try child.top_level_steps.put(allocator, child.install_tls.step.name, &child.install_tls); try child.top_level_steps.put(allocator, child.uninstall_tls.step.name, &child.uninstall_tls); @@ -572,7 +557,7 @@ fn hashUserInputOptionsMap(allocator: Allocator, user_input_options: UserInputOp fn determineAndApplyInstallPrefix(b: *Build) !void { // Create an installation directory local to this package. This will be used when // dependant packages require a standard prefix, such as include directories for C headers. - var hash = b.cache.hash; + var hash = b.graph.cache.hash; // Random bytes to make unique. Refresh this with new random bytes when // implementation is modified in a non-backwards-compatible way. hash.add(@as(u32, 0xd8cb0055)); @@ -587,12 +572,6 @@ fn determineAndApplyInstallPrefix(b: *Build) !void { b.resolveInstallPrefix(install_prefix, .{}); } -pub fn destroy(b: *Build) void { - b.env_map.deinit(); - b.top_level_steps.deinit(b.allocator); - b.allocator.destroy(b); -} - /// 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| { @@ -1273,6 +1252,54 @@ pub fn standardTargetOptions(b: *Build, args: StandardTargetOptionsArgs) Resolve return b.resolveTargetQuery(query); } +pub fn parseTargetQuery(options: std.Target.Query.ParseOptions) error{ParseFailed}!std.Target.Query { + var diags: Target.Query.ParseOptions.Diagnostics = .{}; + var opts_copy = options; + opts_copy.diagnostics = &diags; + return std.Target.Query.parse(options) catch |err| switch (err) { + error.UnknownCpuModel => { + std.debug.print("unknown CPU: '{s}'\navailable CPUs for architecture '{s}':\n", .{ + diags.cpu_name.?, @tagName(diags.arch.?), + }); + for (diags.arch.?.allCpuModels()) |cpu| { + std.debug.print(" {s}\n", .{cpu.name}); + } + return error.ParseFailed; + }, + error.UnknownCpuFeature => { + std.debug.print( + \\unknown CPU feature: '{s}' + \\available CPU features for architecture '{s}': + \\ + , .{ + diags.unknown_feature_name.?, + @tagName(diags.arch.?), + }); + for (diags.arch.?.allFeaturesList()) |feature| { + std.debug.print(" {s}: {s}\n", .{ feature.name, feature.description }); + } + return error.ParseFailed; + }, + error.UnknownOperatingSystem => { + std.debug.print( + \\unknown OS: '{s}' + \\available operating systems: + \\ + , .{diags.os_name.?}); + inline for (std.meta.fields(Target.Os.Tag)) |field| { + std.debug.print(" {s}\n", .{field.name}); + } + return error.ParseFailed; + }, + else => |e| { + std.debug.print("unable to parse target '{s}': {s}\n", .{ + options.arch_os_abi, @errorName(e), + }); + return error.ParseFailed; + }, + }; +} + /// Exposes standard `zig build` options for choosing a target. pub fn standardTargetOptionsQueryOnly(b: *Build, args: StandardTargetOptionsArgs) Target.Query { const maybe_triple = b.option( @@ -1280,60 +1307,28 @@ pub fn standardTargetOptionsQueryOnly(b: *Build, args: StandardTargetOptionsArgs "target", "The CPU architecture, OS, and ABI to build for", ); - const mcpu = b.option([]const u8, "cpu", "Target CPU features to add or subtract"); + const mcpu = b.option( + []const u8, + "cpu", + "Target CPU features to add or subtract", + ); + const dynamic_linker = b.option( + []const u8, + "dynamic-linker", + "Path to interpreter on the target system", + ); - if (maybe_triple == null and mcpu == null) { + if (maybe_triple == null and mcpu == null and dynamic_linker == null) return args.default_target; - } const triple = maybe_triple orelse "native"; - var diags: Target.Query.ParseOptions.Diagnostics = .{}; - const selected_target = Target.Query.parse(.{ + const selected_target = parseTargetQuery(.{ .arch_os_abi = triple, .cpu_features = mcpu, - .diagnostics = &diags, + .dynamic_linker = dynamic_linker, }) 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}); - } - b.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 }); - } - b.markInvalidUserInput(); - return args.default_target; - }, - error.UnknownOperatingSystem => { - log.err( - \\Unknown OS: '{s}' - \\Available operating systems: - \\ - , .{diags.os_name.?}); - inline for (std.meta.fields(Target.Os.Tag)) |field| { - log.err(" {s}", .{field.name}); - } - b.markInvalidUserInput(); - return args.default_target; - }, - else => |e| { - log.err("Unable to parse target '{s}': {s}\n", .{ triple, @errorName(e) }); + error.ParseFailed => { b.markInvalidUserInput(); return args.default_target; }, @@ -1622,7 +1617,7 @@ pub fn findProgram(self: *Build, names: []const []const u8, paths: []const []con return fs.realpathAlloc(self.allocator, full_path) catch continue; } } - if (self.env_map.get("PATH")) |PATH| { + if (self.graph.env_map.get("PATH")) |PATH| { for (names) |name| { if (fs.path.isAbsolute(name)) { return name; @@ -1668,7 +1663,7 @@ pub fn runAllowFail( child.stdin_behavior = .Ignore; child.stdout_behavior = .Pipe; child.stderr_behavior = stderr_behavior; - child.env_map = self.env_map; + child.env_map = &self.graph.env_map; try child.spawn(); @@ -1714,8 +1709,8 @@ pub fn run(b: *Build, argv: []const []const u8) []u8 { }; } -pub fn addSearchPrefix(self: *Build, search_prefix: []const u8) void { - self.search_prefixes.append(self.dupePath(search_prefix)) catch @panic("OOM"); +pub fn addSearchPrefix(b: *Build, search_prefix: []const u8) void { + b.search_prefixes.append(b.allocator, b.dupePath(search_prefix)) catch @panic("OOM"); } pub fn getInstallPath(self: *Build, dir: InstallDir, dest_rel_path: []const u8) []const u8 { @@ -2310,9 +2305,7 @@ pub const ResolvedTarget = struct { /// Converts a target query into a fully resolved target that can be passed to /// various parts of the API. pub fn resolveTargetQuery(b: *Build, query: Target.Query) ResolvedTarget { - // This context will likely be required in the future when the target is - // resolved via a WASI API or via the build protocol. - _ = b; + if (query.isNative()) return b.host; return .{ .query = query, @@ -2326,7 +2319,7 @@ pub fn wantSharedLibSymLinks(target: Target) bool { } pub fn systemLibraryOption(b: *Build, name: []const u8) bool { - const gop = b.system_library_options.getOrPut(b.allocator, name) catch @panic("OOM"); + const gop = b.graph.system_library_options.getOrPut(b.allocator, name) catch @panic("OOM"); if (gop.found_existing) switch (gop.value_ptr.*) { .user_disabled => { gop.value_ptr.* = .declared_disabled; @@ -2340,7 +2333,7 @@ pub fn systemLibraryOption(b: *Build, name: []const u8) bool { .declared_enabled => return true, } else { gop.key_ptr.* = b.dupe(name); - if (b.system_package_mode) { + if (b.graph.system_package_mode) { gop.value_ptr.* = .declared_enabled; return true; } else { diff --git a/lib/std/Build/Step.zig b/lib/std/Build/Step.zig index fade29db1..f67cba6c3 100644 --- a/lib/std/Build/Step.zig +++ b/lib/std/Build/Step.zig @@ -314,7 +314,7 @@ pub fn evalZigProcess( try handleVerbose(s.owner, null, argv); var child = std.ChildProcess.init(argv, arena); - child.env_map = b.env_map; + child.env_map = &b.graph.env_map; child.stdin_behavior = .Pipe; child.stdout_behavior = .Pipe; child.stderr_behavior = .Pipe; diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig index 68e68b28a..0c438069f 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -923,7 +923,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { var zig_args = ArrayList([]const u8).init(arena); defer zig_args.deinit(); - try zig_args.append(b.zig_exe); + try zig_args.append(b.graph.zig_exe); const cmd = switch (self.kind) { .lib => "build-lib", @@ -933,6 +933,16 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { }; try zig_args.append(cmd); + if (!mem.eql(u8, b.graph.host_query_options.arch_os_abi, "native")) { + try zig_args.appendSlice(&.{ "--host-target", b.graph.host_query_options.arch_os_abi }); + } + if (b.graph.host_query_options.cpu_features) |cpu| { + try zig_args.appendSlice(&.{ "--host-cpu", cpu }); + } + if (b.graph.host_query_options.dynamic_linker) |dl| { + try zig_args.appendSlice(&.{ "--host-dynamic-linker", dl }); + } + if (b.reference_trace) |some| { try zig_args.append(try std.fmt.allocPrint(arena, "-freference-trace={d}", .{some})); } @@ -1393,7 +1403,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { try zig_args.append(b.cache_root.path orelse "."); try zig_args.append("--global-cache-dir"); - try zig_args.append(b.global_cache_root.path orelse "."); + try zig_args.append(b.graph.global_cache_root.path orelse "."); try zig_args.append("--name"); try zig_args.append(self.name); diff --git a/lib/std/Build/Step/ConfigHeader.zig b/lib/std/Build/Step/ConfigHeader.zig index 55c7cf387..9c2f5d082 100644 --- a/lib/std/Build/Step/ConfigHeader.zig +++ b/lib/std/Build/Step/ConfigHeader.zig @@ -171,7 +171,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { const gpa = b.allocator; const arena = b.allocator; - var man = b.cache.obtain(); + var man = b.graph.cache.obtain(); defer man.deinit(); // Random bytes to make ConfigHeader unique. Refresh this with new diff --git a/lib/std/Build/Step/Fmt.zig b/lib/std/Build/Step/Fmt.zig index 8e8cc51c0..b9828e34d 100644 --- a/lib/std/Build/Step/Fmt.zig +++ b/lib/std/Build/Step/Fmt.zig @@ -52,7 +52,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { var argv: std.ArrayListUnmanaged([]const u8) = .{}; try argv.ensureUnusedCapacity(arena, 2 + 1 + self.paths.len + 2 * self.exclude_paths.len); - argv.appendAssumeCapacity(b.zig_exe); + argv.appendAssumeCapacity(b.graph.zig_exe); argv.appendAssumeCapacity("fmt"); if (self.check) { diff --git a/lib/std/Build/Step/ObjCopy.zig b/lib/std/Build/Step/ObjCopy.zig index 6691107bf..e10c5ce9a 100644 --- a/lib/std/Build/Step/ObjCopy.zig +++ b/lib/std/Build/Step/ObjCopy.zig @@ -94,7 +94,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { const b = step.owner; const self = @fieldParentPtr(ObjCopy, "step", step); - var man = b.cache.obtain(); + var man = b.graph.cache.obtain(); defer man.deinit(); // Random bytes to make ObjCopy unique. Refresh this with new random @@ -133,7 +133,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { }; var argv = std.ArrayList([]const u8).init(b.allocator); - try argv.appendSlice(&.{ b.zig_exe, "objcopy" }); + try argv.appendSlice(&.{ b.graph.zig_exe, "objcopy" }); if (self.only_section) |only_section| { try argv.appendSlice(&.{ "-j", only_section }); diff --git a/lib/std/Build/Step/Options.zig b/lib/std/Build/Step/Options.zig index beaaf4e3a..8dfe73570 100644 --- a/lib/std/Build/Step/Options.zig +++ b/lib/std/Build/Step/Options.zig @@ -222,7 +222,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { const basename = "options.zig"; // Hash contents to file name. - var hash = b.cache.hash; + var hash = b.graph.cache.hash; // Random bytes to make unique. Refresh this with new random bytes when // implementation is modified in a non-backwards-compatible way. hash.add(@as(u32, 0xad95e922)); @@ -301,27 +301,28 @@ test Options { var arena = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena.deinit(); - const host: std.Build.ResolvedTarget = .{ - .query = .{}, - .result = try std.zig.system.resolveTargetQuery(.{}), - }; - - var cache: std.Build.Cache = .{ - .gpa = arena.allocator(), - .manifest_dir = std.fs.cwd(), + var graph: std.Build.Graph = .{ + .arena = arena.allocator(), + .cache = .{ + .gpa = arena.allocator(), + .manifest_dir = std.fs.cwd(), + }, + .zig_exe = "test", + .env_map = std.process.EnvMap.init(arena.allocator()), + .global_cache_root = .{ .path = "test", .handle = std.fs.cwd() }, }; var builder = try std.Build.create( - arena.allocator(), - "test", + &graph, .{ .path = "test", .handle = std.fs.cwd() }, .{ .path = "test", .handle = std.fs.cwd() }, - .{ .path = "test", .handle = std.fs.cwd() }, - host, - &cache, &.{}, ); - defer builder.destroy(); + + builder.host = .{ + .query = .{}, + .result = try std.zig.system.resolveTargetQuery(.{}), + }; const options = builder.addOptions(); diff --git a/lib/std/Build/Step/Run.zig b/lib/std/Build/Step/Run.zig index de8f9816a..2d49c4840 100644 --- a/lib/std/Build/Step/Run.zig +++ b/lib/std/Build/Step/Run.zig @@ -463,7 +463,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { var argv_list = ArrayList([]const u8).init(arena); var output_placeholders = ArrayList(IndexedOutput).init(arena); - var man = b.cache.obtain(); + var man = b.graph.cache.obtain(); defer man.deinit(); for (self.argv.items) |arg| { @@ -747,7 +747,7 @@ fn runCommand( exe.is_linking_libc; const other_target = exe.root_module.resolved_target.?.result; switch (std.zig.system.getExternalExecutor(b.host.result, &other_target, .{ - .qemu_fixes_dl = need_cross_glibc and b.glibc_runtimes_dir != null, + .qemu_fixes_dl = need_cross_glibc and b.graph.glibc_runtimes_dir != null, .link_libc = exe.is_linking_libc, })) { .native, .rosetta => { @@ -755,7 +755,7 @@ fn runCommand( break :interpret; }, .wine => |bin_name| { - if (b.enable_wine) { + if (b.graph.enable_wine) { try interp_argv.append(bin_name); try interp_argv.appendSlice(argv); } else { @@ -763,9 +763,9 @@ fn runCommand( } }, .qemu => |bin_name| { - if (b.enable_qemu) { + if (b.graph.enable_qemu) { const glibc_dir_arg = if (need_cross_glibc) - b.glibc_runtimes_dir orelse + b.graph.glibc_runtimes_dir orelse return failForeign(self, "--glibc-runtimes", argv[0], exe) else null; @@ -798,7 +798,7 @@ fn runCommand( } }, .darling => |bin_name| { - if (b.enable_darling) { + if (b.graph.enable_darling) { try interp_argv.append(bin_name); try interp_argv.appendSlice(argv); } else { @@ -806,7 +806,7 @@ fn runCommand( } }, .wasmtime => |bin_name| { - if (b.enable_wasmtime) { + if (b.graph.enable_wasmtime) { try interp_argv.append(bin_name); try interp_argv.append("--dir=."); try interp_argv.append(argv[0]); @@ -1036,7 +1036,7 @@ fn spawnChildAndCollect( child.cwd = b.build_root.path; child.cwd_dir = b.build_root.handle; } - child.env_map = self.env_map orelse b.env_map; + child.env_map = self.env_map orelse &b.graph.env_map; child.request_resource_usage_statistics = true; child.stdin_behavior = switch (self.stdio) { diff --git a/lib/std/Build/Step/TranslateC.zig b/lib/std/Build/Step/TranslateC.zig index c55c5889e..223b00499 100644 --- a/lib/std/Build/Step/TranslateC.zig +++ b/lib/std/Build/Step/TranslateC.zig @@ -121,7 +121,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { const self = @fieldParentPtr(TranslateC, "step", step); var argv_list = std.ArrayList([]const u8).init(b.allocator); - try argv_list.append(b.zig_exe); + try argv_list.append(b.graph.zig_exe); try argv_list.append("translate-c"); if (self.link_libc) { try argv_list.append("-lc"); diff --git a/lib/std/Build/Step/WriteFile.zig b/lib/std/Build/Step/WriteFile.zig index 7fcf06249..aab40a8a5 100644 --- a/lib/std/Build/Step/WriteFile.zig +++ b/lib/std/Build/Step/WriteFile.zig @@ -190,7 +190,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { // If, for example, a hard-coded path was used as the location to put WriteFile // files, then two WriteFiles executing in parallel might clobber each other. - var man = b.cache.obtain(); + var man = b.graph.cache.obtain(); defer man.deinit(); // Random bytes to make WriteFile unique. Refresh this with diff --git a/test/src/Cases.zig b/test/src/Cases.zig index 041d53762..614cf690a 100644 --- a/test/src/Cases.zig +++ b/test/src/Cases.zig @@ -562,7 +562,7 @@ pub fn lowerToBuildSteps( run.setName(incr_case.base_path); run.addArgs(&.{ case_base_path_with_dir, - b.zig_exe, + b.graph.zig_exe, }); run.expectStdOutEqual(""); parent_step.dependOn(&run.step); @@ -653,7 +653,7 @@ pub fn lowerToBuildSteps( break :no_exec; } const run_c = b.addSystemCommand(&.{ - b.zig_exe, + b.graph.zig_exe, "run", "-cflags", "-Ilib", diff --git a/test/tests.zig b/test/tests.zig index 9dcc77b14..a749719c8 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -796,7 +796,7 @@ pub fn addCliTests(b: *std.Build) *Step { { // Test `zig init`. const tmp_path = b.makeTempPath(); - const init_exe = b.addSystemCommand(&.{ b.zig_exe, "init" }); + const init_exe = b.addSystemCommand(&.{ b.graph.zig_exe, "init" }); init_exe.setCwd(.{ .cwd_relative = tmp_path }); init_exe.setName("zig init"); init_exe.expectStdOutEqual(""); @@ -810,20 +810,20 @@ pub fn addCliTests(b: *std.Build) *Step { const bad_out_arg = "-femit-bin=does" ++ s ++ "not" ++ s ++ "exist" ++ s ++ "foo.exe"; const ok_src_arg = "src" ++ s ++ "main.zig"; const expected = "error: unable to open output directory 'does" ++ s ++ "not" ++ s ++ "exist': FileNotFound\n"; - const run_bad = b.addSystemCommand(&.{ b.zig_exe, "build-exe", ok_src_arg, bad_out_arg }); + const run_bad = b.addSystemCommand(&.{ b.graph.zig_exe, "build-exe", ok_src_arg, bad_out_arg }); run_bad.setName("zig build-exe error message for bad -femit-bin arg"); run_bad.expectExitCode(1); run_bad.expectStdErrEqual(expected); run_bad.expectStdOutEqual(""); run_bad.step.dependOn(&init_exe.step); - const run_test = b.addSystemCommand(&.{ b.zig_exe, "build", "test" }); + const run_test = b.addSystemCommand(&.{ b.graph.zig_exe, "build", "test" }); run_test.setCwd(.{ .cwd_relative = tmp_path }); run_test.setName("zig build test"); run_test.expectStdOutEqual(""); run_test.step.dependOn(&init_exe.step); - const run_run = b.addSystemCommand(&.{ b.zig_exe, "build", "run" }); + const run_run = b.addSystemCommand(&.{ b.graph.zig_exe, "build", "run" }); run_run.setCwd(.{ .cwd_relative = tmp_path }); run_run.setName("zig build run"); run_run.expectStdOutEqual("Run `zig build test` to run the tests.\n"); @@ -857,7 +857,7 @@ pub fn addCliTests(b: *std.Build) *Step { // This is intended to be the exact CLI usage used by godbolt.org. const run = b.addSystemCommand(&.{ - b.zig_exe, "build-obj", + b.graph.zig_exe, "build-obj", "--cache-dir", tmp_path, "--name", "example", "-fno-emit-bin", "-fno-emit-h", @@ -900,7 +900,7 @@ pub fn addCliTests(b: *std.Build) *Step { subdir.writeFile("fmt3.zig", unformatted_code) catch @panic("unhandled"); // Test zig fmt affecting only the appropriate files. - const run1 = b.addSystemCommand(&.{ b.zig_exe, "fmt", "fmt1.zig" }); + const run1 = b.addSystemCommand(&.{ b.graph.zig_exe, "fmt", "fmt1.zig" }); run1.setName("run zig fmt one file"); run1.setCwd(.{ .cwd_relative = tmp_path }); run1.has_side_effects = true; @@ -908,7 +908,7 @@ pub fn addCliTests(b: *std.Build) *Step { run1.expectStdOutEqual("fmt1.zig\n"); // Test excluding files and directories from a run - const run2 = b.addSystemCommand(&.{ b.zig_exe, "fmt", "--exclude", "fmt2.zig", "--exclude", "subdir", "." }); + const run2 = b.addSystemCommand(&.{ b.graph.zig_exe, "fmt", "--exclude", "fmt2.zig", "--exclude", "subdir", "." }); run2.setName("run zig fmt on directory with exclusions"); run2.setCwd(.{ .cwd_relative = tmp_path }); run2.has_side_effects = true; @@ -916,7 +916,7 @@ pub fn addCliTests(b: *std.Build) *Step { run2.step.dependOn(&run1.step); // Test excluding non-existent file - const run3 = b.addSystemCommand(&.{ b.zig_exe, "fmt", "--exclude", "fmt2.zig", "--exclude", "nonexistent.zig", "." }); + const run3 = b.addSystemCommand(&.{ b.graph.zig_exe, "fmt", "--exclude", "fmt2.zig", "--exclude", "nonexistent.zig", "." }); run3.setName("run zig fmt on directory with non-existent exclusion"); run3.setCwd(.{ .cwd_relative = tmp_path }); run3.has_side_effects = true; @@ -924,7 +924,7 @@ pub fn addCliTests(b: *std.Build) *Step { run3.step.dependOn(&run2.step); // running it on the dir, only the new file should be changed - const run4 = b.addSystemCommand(&.{ b.zig_exe, "fmt", "." }); + const run4 = b.addSystemCommand(&.{ b.graph.zig_exe, "fmt", "." }); run4.setName("run zig fmt the directory"); run4.setCwd(.{ .cwd_relative = tmp_path }); run4.has_side_effects = true; @@ -932,7 +932,7 @@ pub fn addCliTests(b: *std.Build) *Step { run4.step.dependOn(&run3.step); // both files have been formatted, nothing should change now - const run5 = b.addSystemCommand(&.{ b.zig_exe, "fmt", "." }); + const run5 = b.addSystemCommand(&.{ b.graph.zig_exe, "fmt", "." }); run5.setName("run zig fmt with nothing to do"); run5.setCwd(.{ .cwd_relative = tmp_path }); run5.has_side_effects = true; @@ -946,7 +946,7 @@ pub fn addCliTests(b: *std.Build) *Step { write6.step.dependOn(&run5.step); // Test `zig fmt` handling UTF-16 decoding. - const run6 = b.addSystemCommand(&.{ b.zig_exe, "fmt", "." }); + const run6 = b.addSystemCommand(&.{ b.graph.zig_exe, "fmt", "." }); run6.setName("run zig fmt convert UTF-16 to UTF-8"); run6.setCwd(.{ .cwd_relative = tmp_path }); run6.has_side_effects = true;