From 0f3471eb6643140c67587c205aea6582f415dd06 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 29 Apr 2026 15:36:33 -0700 Subject: [PATCH] maker: finish porting over run step --- BRANCH_TODO | 1 + lib/compiler/Maker/Graph.zig | 9 +- lib/compiler/Maker/Step/Compile.zig | 6 +- lib/compiler/Maker/Step/Run.zig | 199 ++++++++++++++++------------ lib/compiler/aro/aro/Driver.zig | 7 +- lib/compiler/configurer.zig | 1 + lib/std/Build/Configuration.zig | 37 +++++- lib/std/Target.zig | 4 +- lib/std/Target/Query.zig | 2 +- lib/std/zig.zig | 2 +- lib/std/zig/system.zig | 33 +++-- src/main.zig | 6 +- 12 files changed, 194 insertions(+), 113 deletions(-) diff --git a/BRANCH_TODO b/BRANCH_TODO index 7b28f34c27eaf74e21e7457de00cb0ac9b4606af..66c225ddadd80f507483992de56e2f60da790ac7 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -16,6 +16,7 @@ * restore the generated_compiler_rt_dyn_lib hack? * run args * https://codeberg.org/ziglang/zig/pulls/30762 +* get the target from the parent process instead ## Followup Issues * reduce the size of Maker.Step.Extended (make Run smaller) probably by using an arena per make diff --git a/lib/compiler/Maker/Graph.zig b/lib/compiler/Maker/Graph.zig index cb963003491d0a29969402029cd2c868e93d2f4c..3a3136d8783c12e12424cceff48085aa6784f026 100644 --- a/lib/compiler/Maker/Graph.zig +++ b/lib/compiler/Maker/Graph.zig @@ -6,6 +6,7 @@ const Io = std.Io; const Allocator = std.mem.Allocator; const Configuration = std.Build.Configuration; const Path = std.Build.Cache.Path; +const Directory = std.Build.Cache.Directory; io: Io, /// Process lifetime. @@ -13,10 +14,10 @@ arena: Allocator, cache: std.Build.Cache, zig_exe: []const u8, environ_map: std.process.Environ.Map, -global_cache_root: std.Build.Cache.Directory, -local_cache_root: std.Build.Cache.Directory, -zig_lib_directory: std.Build.Cache.Directory, -build_root_directory: std.Build.Cache.Directory, +global_cache_root: Directory, +local_cache_root: Directory, +zig_lib_directory: Directory, +build_root_directory: Directory, pkg_root: Path, debug_compiler_runtime_libs: ?std.builtin.OptimizeMode = null, diff --git a/lib/compiler/Maker/Step/Compile.zig b/lib/compiler/Maker/Step/Compile.zig index d4d370bb80421b6d277ed1b120a059eac118f616..5beb76ae5078ee6ec336421c4c35feef09fe815d 100644 --- a/lib/compiler/Maker/Step/Compile.zig +++ b/lib/compiler/Maker/Step/Compile.zig @@ -22,6 +22,8 @@ zig_process: ?*Step.ZigProcess = null, zig_args: std.ArrayList([]const u8) = .empty, /// Populated by InstallArtifact. installed_path: ?Path = null, +/// Populated by `make`, used by `Run`. +is_linking_libc: bool = false, pub fn make( compile: *Compile, @@ -144,7 +146,7 @@ const ModuleListContext = struct { }; fn lowerZigArgs( - compile: *const Compile, + compile: *Compile, compile_index: Configuration.Step.Index, maker: *const Maker, zig_args: *std.ArrayList([]const u8), @@ -564,6 +566,8 @@ fn lowerZigArgs( try zig_args.ensureUnusedCapacity(gpa, 2); if (is_linking_libcpp) zig_args.appendAssumeCapacity("-lc++"); if (is_linking_libc) zig_args.appendAssumeCapacity("-lc"); + + compile.is_linking_libc = is_linking_libc; } if (conf_comp.win32_manifest.value) |manifest_file| { diff --git a/lib/compiler/Maker/Step/Run.zig b/lib/compiler/Maker/Step/Run.zig index 81b46e031cf132e8c6bf5f1971624686eeede7d6..53d9c8cdb427508ba0fe89b4410c854df7666b38 100644 --- a/lib/compiler/Maker/Step/Run.zig +++ b/lib/compiler/Maker/Step/Run.zig @@ -1717,7 +1717,7 @@ fn runCommand( has_side_effects: bool, output_dir_path: []const u8, fuzz_context: ?FuzzContext, -) !void { +) Step.ExtendedMakeError!void { const graph = maker.graph; const arena = graph.arena; // TODO don't leak into process arena const gpa = maker.gpa; @@ -1757,8 +1757,6 @@ fn runCommand( } try graph.handleVerbose(cwd, environ_map, argv); - if (true) @panic("TODO"); - const opt_generic_result = spawnChildAndCollect( run_index, run, @@ -1777,22 +1775,33 @@ fn runCommand( // relying on it being a Compile step. This will make this logic // work even for the edge case that the binary was produced by a // third party. - const exe = switch (run.argv.items[0]) { - .artifact => |exe| exe.artifact, - else => break :interpret, - }; - switch (exe.kind) { + const arg0 = conf_run.args.slice[0].get(conf); + const producer_index = arg0.producer.value orelse break :interpret; + const producer_step = producer_index.ptr(conf); + const producer = producer_step.extended.get(conf.extra).compile; + switch (producer.flags3.kind) { .exe, .@"test" => {}, else => break :interpret, } + const root_module = producer.root_module.get(conf); + const root_module_target = root_module.resolved_target.get(conf).?.result.get(conf); + const other_target_query = root_module_target.unwrap(conf); + const root_target = std.zig.system.resolveTargetQuery(io, other_target_query) catch unreachable; + const link_libc = maker.stepByIndex(producer_index).extended.compile.is_linking_libc; - const root_target = exe.rootModuleTarget(); - const need_cross_libc = exe.is_linking_libc and - (root_target.isGnuLibC() or (root_target.isMuslLibC() and exe.linkage == .dynamic)); - const other_target = exe.root_module.resolved_target.?.result; - switch (std.zig.system.getExternalExecutor(io, &graph.host.result, &other_target, .{ + // TODO get this from the parent process instead + const host: std.Target = std.zig.system.resolveTargetQuery(io, .{}) catch |he| switch (he) { + error.Canceled => |e| return e, + else => builtin.target, + }; + + const need_cross_libc = link_libc and root_target.os.tag == .linux and + producer.flags2.linkage == .dynamic; + switch (std.zig.system.getExternalExecutor(io, &root_target, .{ + .host_cpu_arch = host.cpu.arch, + .host_os_tag = host.os.tag, .qemu_fixes_dl = need_cross_libc and graph.libc_runtimes_dir != null, - .link_libc = exe.is_linking_libc, + .link_libc = link_libc, })) { .native, .rosetta => { if (allow_skip) return error.MakeSkipped; @@ -1800,8 +1809,9 @@ fn runCommand( }, .wine => |bin_name| { if (graph.enable_wine) { - try interp_argv.append(bin_name); - try interp_argv.appendSlice(argv); + try interp_argv.ensureUnusedCapacity(arena, 1 + argv.len); + interp_argv.appendAssumeCapacity(bin_name); + interp_argv.appendSliceAssumeCapacity(argv); // Wine's excessive stderr logging is only situationally helpful. Disable it by default, but // allow the user to override it (e.g. with `WINEDEBUG=err+all`) if desired. @@ -1809,17 +1819,18 @@ fn runCommand( try environ_map.put("WINEDEBUG", "-all"); } } else { - return failForeign(conf_run, maker, run_index, "-fwine", argv[0], exe); + return failForeign(&conf_run, maker, run_index, "-fwine", argv[0], &root_target, &host); } }, .qemu => |bin_name| { if (graph.enable_qemu) { - try interp_argv.append(bin_name); + try interp_argv.ensureUnusedCapacity(arena, 3 + argv.len); + interp_argv.appendAssumeCapacity(bin_name); if (need_cross_libc) { if (graph.libc_runtimes_dir) |dir| { - try interp_argv.append("-L"); - try interp_argv.append(try Dir.path.join(arena, &.{ + interp_argv.appendAssumeCapacity("-L"); + interp_argv.appendAssumeCapacity(try Dir.path.join(arena, &.{ dir, try if (root_target.isGnuLibC()) std.zig.target.glibcRuntimeTriple( arena, @@ -1832,37 +1843,38 @@ fn runCommand( root_target.abi, ) else unreachable, })); - } else return failForeign(conf_run, maker, run_index, "--libc-runtimes", argv[0], exe); + } else return failForeign(&conf_run, maker, run_index, "--libc-runtimes", argv[0], &root_target, &host); } - try interp_argv.appendSlice(argv); - } else return failForeign(conf_run, maker, run_index, "-fqemu", argv[0], exe); + interp_argv.appendSliceAssumeCapacity(argv); + } else return failForeign(&conf_run, maker, run_index, "-fqemu", argv[0], &root_target, &host); }, .darling => |bin_name| { if (graph.enable_darling) { - try interp_argv.append(bin_name); - try interp_argv.appendSlice(argv); + try interp_argv.ensureUnusedCapacity(arena, 1 + argv.len); + interp_argv.appendAssumeCapacity(bin_name); + interp_argv.appendSliceAssumeCapacity(argv); } else { - return failForeign(conf_run, maker, run_index, "-fdarling", argv[0], exe); + return failForeign(&conf_run, maker, run_index, "-fdarling", argv[0], &root_target, &host); } }, .wasmtime => |bin_name| { if (graph.enable_wasmtime) { - try interp_argv.append(bin_name); - try interp_argv.append("--dir=."); + try interp_argv.ensureUnusedCapacity(arena, 3 + argv.len); + interp_argv.appendAssumeCapacity(bin_name); + interp_argv.appendAssumeCapacity("--dir=."); // Wasmtime doeesn't inherit environment variables from the parent process // by default. '-S inherit-env' was added in Wasmtime version 20. - try interp_argv.append("-Sinherit-env"); - try interp_argv.append(argv[0]); - try interp_argv.appendSlice(argv[1..]); + interp_argv.appendAssumeCapacity("-Sinherit-env"); + interp_argv.appendSliceAssumeCapacity(argv); } else { - return failForeign(conf_run, maker, run_index, "-fwasmtime", argv[0], exe); + return failForeign(&conf_run, maker, run_index, "-fwasmtime", argv[0], &root_target, &host); } }, .bad_dl => |foreign_dl| { if (allow_skip) return error.MakeSkipped; - const host_dl = graph.host.result.dynamic_linker.get() orelse "(none)"; + const host_dl = host.dynamic_linker.get() orelse "(none)"; return step.fail(maker, \\the host system is unable to execute binaries from the target @@ -1874,7 +1886,7 @@ fn runCommand( .bad_os_or_cpu => { if (allow_skip) return error.MakeSkipped; - const host_name = try graph.host.result.zigTriple(arena); + const host_name = try host.zigTriple(arena); const foreign_name = try root_target.zigTriple(arena); return step.fail(maker, "the host system ({s}) is unable to execute binaries from the target ({s})", .{ @@ -1885,15 +1897,24 @@ fn runCommand( if (root_target.os.tag == .windows) { // On Windows we don't have rpaths so we have to add .dll search paths to PATH - addPathForDynLibs(exe); + addPathForDynLibs(producer_index); } gpa.free(step.result_failed_command.?); step.result_failed_command = null; - try graph.handleVerbose(cwd, run.environ_map, interp_argv.items); + try graph.handleVerbose(cwd, environ_map, interp_argv.items); - break :term spawnChildAndCollect(run_index, run, maker, progress_node, interp_argv.items, &environ_map, has_side_effects, fuzz_context) catch |e| { - if (!run.failing_to_execute_foreign_is_an_error) return error.MakeSkipped; + break :term spawnChildAndCollect( + run_index, + run, + maker, + progress_node, + interp_argv.items, + environ_map, + has_side_effects, + fuzz_context, + ) catch |e| { + if (!conf_run.flags.failing_to_execute_foreign_is_an_error) return error.MakeSkipped; if (e == error.MakeFailed) return error.MakeFailed; // error already reported return step.fail(maker, "unable to spawn interpreter {s}: {t}", .{ interp_argv.items[0], e }); }; @@ -1919,47 +1940,51 @@ fn runCommand( const Stream = struct { captured: ?Configuration.Step.Run.CapturedStream, bytes: ?[]const u8, + trim_whitespace: Configuration.Step.Run.TrimWhitespace, }; - for ([_]Stream{ + for (&[_]Stream{ .{ .captured = conf_run.captured_stdout.value, .bytes = generic_result.stdout, + .trim_whitespace = conf_run.flags.stdout_trim_whitespace, }, .{ .captured = conf_run.captured_stderr.value, .bytes = generic_result.stderr, + .trim_whitespace = conf_run.flags.stderr_trim_whitespace, }, - }) |stream| { + }) |*stream| { if (stream.captured) |captured| { - const output_components = .{ output_dir_path, captured.output.basename }; - const output_path = try cache_root.join(arena, &output_components); - captured.output.generated_file.path = output_path; - - const sub_path = try Dir.path.join(arena, &output_components); - const sub_path_dirname = Dir.path.dirname(sub_path).?; - cache_root.handle.createDirPath(io, sub_path_dirname) catch |err| { - return step.fail(maker, "unable to make path '{f}{s}': {t}", .{ - cache_root, sub_path_dirname, err, - }); + const output_path: Path = .{ + .root_dir = cache_root, + .sub_path = try Dir.path.join(arena, &.{ + output_dir_path, captured.basename.slice(conf), + }), }; - const data = switch (captured.trim_whitespace) { + maker.generatedPath(captured.generated_file).* = output_path; + + const sub_path_parent = output_path.dirname().?; + sub_path_parent.root_dir.handle.createDirPath(io, sub_path_parent.sub_path) catch |err| + return step.fail(maker, "unable to make path {f}: {t}", .{ sub_path_parent, err }); + + const data = switch (stream.trim_whitespace) { .none => stream.bytes.?, .all => mem.trim(u8, stream.bytes.?, &std.ascii.whitespace), .leading => mem.trimStart(u8, stream.bytes.?, &std.ascii.whitespace), .trailing => mem.trimEnd(u8, stream.bytes.?, &std.ascii.whitespace), }; - cache_root.handle.writeFile(io, .{ .sub_path = sub_path, .data = data }) catch |err| { - return step.fail(maker, "unable to write file '{f}{s}': {t}", .{ - cache_root, sub_path, err, - }); - }; + output_path.root_dir.handle.writeFile(io, .{ + .sub_path = output_path.sub_path, + .data = data, + }) catch |err| return step.fail(maker, "unable to write file {f}: {t}", .{ output_path, err }); } } switch (conf_run.flags.stdio) { .zig_test => unreachable, - .check => |checks| for (checks.items) |check| switch (check) { - .expect_stderr_exact => |expected_bytes| { + .check => { + if (conf_run.expect_stderr_exact.value) |bytes| { + const expected_bytes = bytes.slice(conf); if (!mem.eql(u8, expected_bytes, generic_result.stderr.?)) { return step.fail(maker, \\========= expected this stderr: ========= @@ -1971,8 +1996,23 @@ fn runCommand( generic_result.stderr.?, }); } - }, - .expect_stderr_match => |match| { + } + if (conf_run.expect_stdout_exact.value) |bytes| { + const expected_bytes = bytes.slice(conf); + if (!mem.eql(u8, expected_bytes, generic_result.stdout.?)) { + return step.fail(maker, + \\========= expected this stdout: ========= + \\{s} + \\========= but found: ==================== + \\{s} + , .{ + expected_bytes, + generic_result.stdout.?, + }); + } + } + for (conf_run.expect_stderr_match.slice) |bytes| { + const match = bytes.slice(conf); if (mem.find(u8, generic_result.stderr.?, match) == null) { return step.fail(maker, \\========= expected to find in stderr: ========= @@ -1984,21 +2024,9 @@ fn runCommand( generic_result.stderr.?, }); } - }, - .expect_stdout_exact => |expected_bytes| { - if (!mem.eql(u8, expected_bytes, generic_result.stdout.?)) { - return step.fail(maker, - \\========= expected this stdout: ========= - \\{s} - \\========= but found: ==================== - \\{s} - , .{ - expected_bytes, - generic_result.stdout.?, - }); - } - }, - .expect_stdout_match => |match| { + } + for (conf_run.expect_stdout_match.slice) |bytes| { + const match = bytes.slice(conf); if (mem.find(u8, generic_result.stdout.?, match) == null) { return step.fail(maker, \\========= expected to find in stdout: ========= @@ -2010,15 +2038,21 @@ fn runCommand( generic_result.stdout.?, }); } - }, - .expect_term => |expected_term| { + } + if (conf_run.expect_term_value.value) |expected_term_value| { + const expected_term: process.Child.Term = switch (conf_run.flags2.expect_term_status) { + .exited => .{ .exited = @intCast(expected_term_value) }, + .signal => .{ .signal = @enumFromInt(expected_term_value) }, + .stopped => .{ .stopped = @enumFromInt(expected_term_value) }, + .unknown => .{ .unknown = expected_term_value }, + }; if (!termMatches(expected_term, generic_result.term)) { return step.fail(maker, "process {f} (expected {f})", .{ fmtTerm(generic_result.term), fmtTerm(expected_term), }); } - }, + } }, else => { // On failure, report captured stderr like normal standard error output. @@ -2032,7 +2066,7 @@ fn runCommand( } } - try step.handleChildProcessTerm(generic_result.term); + try step.handleChildProcessTerm(maker, generic_result.term); }, } } @@ -2256,7 +2290,8 @@ fn failForeign( step_index: Configuration.Step.Index, suggested_flag: []const u8, argv0: []const u8, - exe: *Step.Compile, + artifact_target: *const std.Target, + host_target: *const std.Target, ) Step.ExtendedMakeError { const step = maker.stepByIndex(step_index); switch (conf_run.flags.stdio) { @@ -2265,8 +2300,8 @@ fn failForeign( const graph = maker.graph; const process_arena = graph.arena; // TODO don't leak into process arena - const host_name = try graph.host.result.zigTriple(process_arena); - const foreign_name = try exe.rootModuleTarget().zigTriple(process_arena); + const host_name = try host_target.zigTriple(process_arena); + const foreign_name = try artifact_target.zigTriple(process_arena); return step.fail(maker, \\unable to spawn foreign binary '{s}' ({s}) on host system ({s}) diff --git a/lib/compiler/aro/aro/Driver.zig b/lib/compiler/aro/aro/Driver.zig index f1bf6b8d4e62e56a924ef4954eddc784296e5239..269be075fb3b225e6bf1cd923b2e022e13d1f8b3 100644 --- a/lib/compiler/aro/aro/Driver.zig +++ b/lib/compiler/aro/aro/Driver.zig @@ -1041,9 +1041,10 @@ fn parseTarget(d: *Driver, arch_os_abi: []const u8, opt_cpu_features: ?[]const u } else if (mem.eql(u8, cpu_name, "baseline")) { query.cpu_model = .baseline; } else { - query.cpu_model = .{ .explicit = arch.parseCpuModel(cpu_name) catch |er| switch (er) { - error.UnknownCpuModel => return d.fatal("unknown CPU model: '{s}'", .{cpu_name}), - } }; + query.cpu_model = .{ + .explicit = arch.parseCpuModel(cpu_name) orelse + return d.fatal("unknown CPU model: '{s}'", .{cpu_name}), + }; } if (opt_sub_arch) |sub_arch| { diff --git a/lib/compiler/configurer.zig b/lib/compiler/configurer.zig index 7815198bcaceadaea247f7ea5889c8a832511aaf..e99f6384eff5e0fb08a6769a99e51f32a4ca8b4b 100644 --- a/lib/compiler/configurer.zig +++ b/lib/compiler/configurer.zig @@ -83,6 +83,7 @@ pub fn main(init: process.Init.Minimal) !void { .environ_map = try init.environ.createMap(arena), .global_cache_root = global_cache_directory, .zig_lib_directory = zig_lib_directory, + // TODO get this from parent process instead .host = .{ .query = .{}, .result = try std.zig.system.resolveTargetQuery(io, .{}), diff --git a/lib/std/Build/Configuration.zig b/lib/std/Build/Configuration.zig index 4c81bdb9eeff53d1528a0097ab161e3ce90ad3e2..eb1736db1d26d6505d04846abffc2b4b18f5c2c0 100644 --- a/lib/std/Build/Configuration.zig +++ b/lib/std/Build/Configuration.zig @@ -1797,7 +1797,7 @@ pub const TargetQuery = struct { } pub fn get(this: @This(), c: *const Configuration) ?TargetQuery { - return (unwrap(this) orelse return null).get(c); + return (this.unwrap() orelse return null).get(c); } }; @@ -1831,6 +1831,15 @@ pub const TargetQuery = struct { .windows => .windows, }; } + + pub fn unwrap(this: @This(), c: *const Configuration) ?std.Target.Query.OsVersion { + return switch (this) { + .none => .none, + .semver => |sv| .{ .semver = std.SemanticVersion.parse(sv.slice(c)) catch unreachable }, + .windows => |wv| .{ .windows = wv }, + .default => null, + }; + } }; pub const Abi = enum(u5) { none, @@ -2052,6 +2061,32 @@ pub const TargetQuery = struct { android_api_level: bool, dynamic_linker: bool, }; + + pub fn unwrap(tq: *const TargetQuery, c: *const Configuration) std.Target.Query { + const cpu_arch = tq.flags.cpu_arch.unwrap(); + return .{ + .cpu_arch = cpu_arch, + .cpu_model = switch (tq.flags.cpu_model) { + .native => .native, + .baseline => .baseline, + .determined_by_arch_os => .determined_by_arch_os, + .explicit => .{ .explicit = cpu_arch.?.parseCpuModel(tq.cpu_name.value.?.slice(c)).? }, + }, + .cpu_features_add = tq.cpu_features_add.value orelse .empty, + .cpu_features_sub = tq.cpu_features_sub.value orelse .empty, + .os_tag = tq.flags.os_tag.unwrap(), + .os_version_min = tq.os_version_min.u.unwrap(c), + .os_version_max = tq.os_version_max.u.unwrap(c), + .glibc_version = if (tq.glibc_version.value) |s| + std.SemanticVersion.parse(s.slice(c)) catch unreachable + else + null, + .android_api_level = tq.android_api_level.value, + .abi = tq.flags.abi.unwrap(), + .dynamic_linker = .init(if (tq.dynamic_linker.value) |s| s.slice(c) else null), + .ofmt = tq.flags.object_format.unwrap(), + }; + } }; pub const Storage = enum { diff --git a/lib/std/Target.zig b/lib/std/Target.zig index aaed0a2855a27d352b1cef23b739ee5f156b9282..49ad49b0b13fae90d34d196d28f39e83523e80cd 100644 --- a/lib/std/Target.zig +++ b/lib/std/Target.zig @@ -1668,13 +1668,13 @@ pub const Cpu = struct { }; } - pub fn parseCpuModel(arch: Arch, cpu_name: []const u8) !*const Cpu.Model { + pub fn parseCpuModel(arch: Arch, cpu_name: []const u8) ?*const Cpu.Model { for (arch.allCpuModels()) |cpu| { if (std.mem.eql(u8, cpu_name, cpu.name)) { return cpu; } } - return error.UnknownCpuModel; + return null; } pub fn endian(arch: Arch) std.builtin.Endian { diff --git a/lib/std/Target/Query.zig b/lib/std/Target/Query.zig index 2f6b9fb718b8452065d972395342f453261d09ee..c1a533020b2de773e1c04544ff61a46eb865d583 100644 --- a/lib/std/Target/Query.zig +++ b/lib/std/Target/Query.zig @@ -282,7 +282,7 @@ pub fn parse(args: ParseOptions) !Query { } else if (mem.eql(u8, cpu_name, "baseline")) { result.cpu_model = .baseline; } else { - result.cpu_model = .{ .explicit = try arch.parseCpuModel(cpu_name) }; + result.cpu_model = .{ .explicit = arch.parseCpuModel(cpu_name) orelse return error.UnknownCpuModel }; } while (index < cpu_features.len) { diff --git a/lib/std/zig.zig b/lib/std/zig.zig index 3abf43b3258452a24cdebb12f92e0d5085e338dc..700978a94d51c0e4071c24156c9869d347e6fac4 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -680,7 +680,7 @@ pub fn putAstErrorsIntoBundle( pub fn resolveTargetQueryOrFatal(io: Io, target_query: std.Target.Query) std.Target { return std.zig.system.resolveTargetQuery(io, target_query) catch |err| - std.process.fatal("unable to resolve target: {s}", .{@errorName(err)}); + std.process.fatal("unable to resolve target: {t}", .{err}); } pub fn parseTargetQueryOrReportFatalError( diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index ff4692db91f77e80257b81d85d986d5de69099c8..9d47215a99562ded1fdb437242d9c5729d921e81 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -28,6 +28,8 @@ pub const Executor = union(enum) { }; pub const GetExternalExecutorOptions = struct { + host_cpu_arch: std.Target.Cpu.Arch, + host_os_tag: std.Target.Os.Tag, allow_darling: bool = true, allow_qemu: bool = true, allow_rosetta: bool = true, @@ -39,24 +41,21 @@ pub const GetExternalExecutorOptions = struct { /// Return whether or not the given host is capable of running executables of /// the other target. -pub fn getExternalExecutor( - io: Io, - host: *const std.Target, - candidate: *const std.Target, - options: GetExternalExecutorOptions, -) Executor { - const os_match = host.os.tag == candidate.os.tag; +pub fn getExternalExecutor(io: Io, candidate: *const std.Target, options: GetExternalExecutorOptions) Executor { + const host_os_tag = options.host_os_tag; + const host_cpu_arch = options.host_cpu_arch; + const os_match = host_os_tag == candidate.os.tag; const cpu_ok = cpu_ok: { - if (host.cpu.arch == candidate.cpu.arch) + if (host_cpu_arch == candidate.cpu.arch) break :cpu_ok true; - if (host.cpu.arch == .x86_64 and candidate.cpu.arch == .x86) + if (host_cpu_arch == .x86_64 and candidate.cpu.arch == .x86) break :cpu_ok true; - if (host.cpu.arch == .aarch64 and candidate.cpu.arch == .arm) + if (host_cpu_arch == .aarch64 and candidate.cpu.arch == .arm) break :cpu_ok true; - if (host.cpu.arch == .aarch64_be and candidate.cpu.arch == .armeb) + if (host_cpu_arch == .aarch64_be and candidate.cpu.arch == .armeb) break :cpu_ok true; // TODO additionally detect incompatible CPU features. @@ -83,7 +82,7 @@ pub fn getExternalExecutor( // If the OS match and OS is macOS and CPU is arm64, we can use Rosetta 2 // to emulate the foreign architecture. if (options.allow_rosetta and os_match and - (host.os.tag == .maccatalyst or host.os.tag == .macos) and host.cpu.arch == .aarch64) + (host_os_tag == .maccatalyst or host_os_tag == .macos) and host_cpu_arch == .aarch64) { switch (candidate.cpu.arch) { .x86_64 => return .rosetta, @@ -173,13 +172,13 @@ pub fn getExternalExecutor( .windows => { if (options.allow_wine) { const wine_supported = switch (candidate.cpu.arch) { - .thumb => switch (host.cpu.arch) { + .thumb => switch (host_cpu_arch) { .arm, .thumb, .aarch64 => true, else => false, }, - .aarch64 => host.cpu.arch == .aarch64, - .x86 => host.cpu.arch.isX86(), - .x86_64 => host.cpu.arch == .x86_64, + .aarch64 => host_cpu_arch == .aarch64, + .x86 => host_cpu_arch.isX86(), + .x86_64 => host_cpu_arch == .x86_64, else => false, }; return if (wine_supported) .{ .wine = "wine" } else bad_result; @@ -191,7 +190,7 @@ pub fn getExternalExecutor( // This check can be loosened once darling adds a QEMU-based emulation // layer for non-host architectures: // https://github.com/darlinghq/darling/issues/863 - if (candidate.cpu.arch != host.cpu.arch) { + if (candidate.cpu.arch != host_cpu_arch) { return bad_result; } return .{ .darling = "darling" }; diff --git a/src/main.zig b/src/main.zig index f774eb522fecf9c9dd093be05d3a4d80dbb4d5c2..6a4768c3db1bc3e835aabe99e2fa50ccbf65052b 100644 --- a/src/main.zig +++ b/src/main.zig @@ -6825,7 +6825,11 @@ fn warnAboutForeignBinaries( const host_query: std.Target.Query = .{}; const host_target = std.zig.resolveTargetQueryOrFatal(io, host_query); - switch (std.zig.system.getExternalExecutor(io, &host_target, target, .{ .link_libc = link_libc })) { + switch (std.zig.system.getExternalExecutor(io, target, .{ + .host_cpu_arch = host_target.cpu.arch, + .host_os_tag = host_target.os.tag, + .link_libc = link_libc, + })) { .native => return, .rosetta => { const host_name = try host_target.zigTriple(arena); -- 2.54.0