diff --git a/lib/compiler/Maker.zig b/lib/compiler/Maker.zig index 61b99159cecbfc9603b04e716d97ba448a431248..12df472dea24af6477265bbd9e922542db8a8757 100644 --- a/lib/compiler/Maker.zig +++ b/lib/compiler/Maker.zig @@ -3631,7 +3631,7 @@ pub fn resolveLazyPath( const c = &maker.scanned_config.configuration; return switch (lazy_path) { .source_path => |sp| try packagePath(maker, arena, sp.owner, sp.sub_path.slice(c)), - .relative => |relative| relativePath(maker, arena, relative), + .relative => |relative| try relativePath(maker, arena, relative, stepByIndex(maker, asking_step_index)), .generated => |gen| { const base = generatedPath(maker, gen.index); var file_path = base; @@ -3768,7 +3768,12 @@ pub fn packagePath( }; } -pub fn relativePath(maker: *const Maker, arena: Allocator, relative: Configuration.LazyPath.Relative) Allocator.Error!Path { +pub fn relativePath( + maker: *const Maker, + arena: Allocator, + relative: Configuration.LazyPath.Relative, + asking_step: *Step, +) error{ OutOfMemory, MakeFailed }!Path { const graph = maker.graph; const c = &maker.scanned_config.configuration; const sub_path = relative.sub_path.slice(c); @@ -3789,12 +3794,12 @@ pub fn relativePath(maker: *const Maker, arena: Allocator, relative: Configurati .root_dir = graph.build_root_directory, .sub_path = sub_path, }, - .zig_exe => .{ - .root_dir = .cwd(), - .sub_path = if (sub_path.len == 0) - graph.zig_exe - else - try Io.Dir.path.join(arena, &.{ graph.zig_exe, sub_path }), + .zig_exe => { + assert(sub_path.len == 0); + return .{ + .root_dir = .cwd(), + .sub_path = graph.zig_exe, + }; }, .zig_lib => .{ .root_dir = graph.zig_lib_directory, @@ -3804,6 +3809,10 @@ pub fn relativePath(maker: *const Maker, arena: Allocator, relative: Configurati .install_lib => try maker.install_paths.lib.join(arena, sub_path), .install_bin => try maker.install_paths.bin.join(arena, sub_path), .install_include => try maker.install_paths.include.join(arena, sub_path), + .libc_runtimes => if (maker.graph.libc_runtimes_dir) |libc_runtimes_dir| .{ + .root_dir = .cwd(), + .sub_path = try Dir.path.join(arena, &.{ libc_runtimes_dir, sub_path }), + } else asking_step.fail(maker, "unknown LazyPath: \"--libc-runtimes\" not specified", .{}), }; } @@ -4391,15 +4400,22 @@ fn confPathDepToCachePath( else => |index| try Dir.path.join(arena, &.{ index.get(c).?.root_path.slice(c), sub_path }), }, }, + .zig_exe => { + assert(sub_path.len == 0); + return .{ + .root_dir = .cwd(), + .sub_path = graph.zig_exe, + }; + }, .zig_lib => .{ .root_dir = graph.zig_lib_directory, .sub_path = sub_path, }, - .zig_exe => @panic("TODO"), .install_prefix => @panic("TODO"), .install_lib => @panic("TODO"), .install_bin => @panic("TODO"), .install_include => @panic("TODO"), + .libc_runtimes => @panic("TODO"), }; } diff --git a/lib/compiler/Maker/Step.zig b/lib/compiler/Maker/Step.zig index ebf2a4672892d24cf96db6947d9a04e07da1e69e..37212902592f2dfd5d2ea0d760b861d1e7fe03e2 100644 --- a/lib/compiler/Maker/Step.zig +++ b/lib/compiler/Maker/Step.zig @@ -857,7 +857,7 @@ pub fn setWatchInputsFromManifestFiles( } /// For steps that have a single input that never changes when re-running `make`. -pub fn singleUnchangingWatchInput(step: *Step, maker: *Maker, arena: Allocator, lazy_path: LazyPath) Allocator.Error!void { +pub fn singleUnchangingWatchInput(step: *Step, maker: *Maker, arena: Allocator, lazy_path: LazyPath) FailError!void { if (!step.inputs.populated()) try step.addWatchInput(maker, arena, lazy_path); } @@ -866,7 +866,7 @@ pub fn clearWatchInputs(step: *Step, maker: *Maker) void { } /// Places a *file* dependency on the path. -pub fn addWatchInput(step: *Step, maker: *Maker, arena: Allocator, lazy_file: LazyPath) Allocator.Error!void { +pub fn addWatchInput(step: *Step, maker: *Maker, arena: Allocator, lazy_file: LazyPath) FailError!void { const conf = &maker.scanned_config.configuration; switch (lazy_file) { .source_path => |source_path| { @@ -875,7 +875,7 @@ pub fn addWatchInput(step: *Step, maker: *Maker, arena: Allocator, lazy_file: La try addWatchInputPath(step, maker, pkg_path); }, .relative => |relative| { - const resolved_path = try maker.relativePath(arena, relative); + const resolved_path = try maker.relativePath(arena, relative, step); try addWatchInputPath(step, maker, resolved_path); }, // Nothing to watch because this dependency edge is modeled instead via `dependants`. @@ -890,7 +890,7 @@ pub fn addWatchInput(step: *Step, maker: *Maker, arena: Allocator, lazy_file: La /// Paths derived from this directory should also be manually added via /// `addDirectoryWatchInputFromPath` if and only if this function returns /// `true`. -pub fn addDirectoryWatchInput(step: *Step, maker: *Maker, lazy_directory: LazyPath) Allocator.Error!bool { +pub fn addDirectoryWatchInput(step: *Step, maker: *Maker, lazy_directory: LazyPath) FailError!bool { const graph = maker.graph; const arena = graph.arena; // TODO don't leak into the process arena switch (lazy_directory) { @@ -901,7 +901,7 @@ pub fn addDirectoryWatchInput(step: *Step, maker: *Maker, lazy_directory: LazyPa try addDirectoryWatchInputFromPath(step, maker, pkg_path); }, .relative => |relative| { - const resolved_path = try maker.relativePath(arena, relative); + const resolved_path = try maker.relativePath(arena, relative, step); try addDirectoryWatchInputFromPath(step, maker, resolved_path); }, // Nothing to watch because this dependency edge is modeled instead via `dependants`. diff --git a/lib/compiler/Maker/Step/Run.zig b/lib/compiler/Maker/Step/Run.zig index 784f84eef95e7aeb912c097a4b0781def6a2ddcf..8ce0a66837e0ed9fb9cf27e39a170bf7845a9204 100644 --- a/lib/compiler/Maker/Step/Run.zig +++ b/lib/compiler/Maker/Step/Run.zig @@ -250,9 +250,18 @@ pub fn make( protocol_args.appendAssumeCapacity(0); }, .path_file => { + const lazy_path = arg.path.value.?.get(conf); + switch (lazy_path) { + else => {}, + .relative => |relative| switch (relative.flags.base) { + else => {}, + .libc_runtimes => if (graph.libc_runtimes_dir == null) continue, + }, + } + const prefix = if (arg.prefix.value) |p| p.slice(conf) else ""; const suffix = if (arg.suffix.value) |p| p.slice(conf) else ""; - const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index); + const file_path = try maker.resolveLazyPath(arena, lazy_path, run_index); try owned_files.resize(gpa, owned_files.bit_length + 1, true); try inherit_files.ensureUnusedCapacity(gpa, 1); @@ -283,9 +292,18 @@ pub fn make( } }, .path_directory => { + const lazy_path = arg.path.value.?.get(conf); + switch (lazy_path) { + else => {}, + .relative => |relative| switch (relative.flags.base) { + else => {}, + .libc_runtimes => if (graph.libc_runtimes_dir == null) continue, + }, + } + const prefix = if (arg.prefix.value) |p| p.slice(conf) else ""; const suffix = if (arg.suffix.value) |p| p.slice(conf) else ""; - const dir_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index); + const dir_path = try maker.resolveLazyPath(arena, lazy_path, run_index); try input_dirs.append(gpa, dir_path); const has_sub_path = dir_path.sub_path.len > 0; @@ -2242,12 +2260,8 @@ fn runCommand( else => builtin.target, }; - const need_cross_libc = config.flags.link_libc and root_target.os.tag == .linux and - switch (producer.flags2.linkage) { - .static => false, - .dynamic => true, - .default => root_target.isGnuLibC(), - }; + const need_cross_libc = root_target.os.tag == .linux and + config.flags.link_libc and config.flags.link_mode == .dynamic; switch (std.zig.system.getExternalExecutor(io, &root_target, .{ .host_cpu_arch = host.cpu.arch, .host_os_tag = host.os.tag, @@ -2316,7 +2330,7 @@ fn runCommand( interp_argv.appendAssumeCapacity(bin_name); interp_argv.appendAssumeCapacity("--dir=."); for (conf_run.preopens.slice) |preopen| { - const path = try maker.resolveLazyPath(arena, preopen.path.get(conf), run_index); + const path = try maker.resolveLazyPathIndex(arena, preopen.path, run_index); path.root_dir.handle.createDirPath(io, path.subPathOrDot()) catch |e| return step.fail(maker, "failed creating directory {f}: {t}", .{ path, e }); interp_argv.appendAssumeCapacity(try arena.print("--dir={f}::{s}", .{ path, preopen.name.slice(conf) })); diff --git a/lib/std/Build.zig b/lib/std/Build.zig index 730c6bcba58f9c216929acd6157f30c497508a6b..36b48d62cf8075024dddc8dc21b339b929d34c5e 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -2693,12 +2693,15 @@ fn validateConfigureDependency(lazy_path: LazyPath) void { .src_path, .cwd_relative, .dependency => {}, // OK .generated => @panic("configure phase cannot depend on files generated during make phase"), .relative => |relative| switch (relative.base) { - .cwd, .build_root, .local_cache, .global_cache, .zig_exe, .zig_lib => {}, // OK + .cwd, .build_root, .local_cache, .global_cache, .zig_lib => {}, // OK + .zig_exe => if (relative.sub_path.len > 0) @panic("file base cannot have a sub path"), .install_prefix, .install_lib, .install_bin, .install_include, => @panic("configure phase cannot depend on files installed during make phase"), + .libc_runtimes, + => @panic("configure phase cannot depend on directory known only during make phase"), }, } } diff --git a/lib/std/Build/Configuration.zig b/lib/std/Build/Configuration.zig index f0c3ff44d92678e6fbdf945e9d12883b75f95049..53bd11500b0d70d4448bd461cfcd924fec6482a2 100644 --- a/lib/std/Build/Configuration.zig +++ b/lib/std/Build/Configuration.zig @@ -1575,6 +1575,7 @@ pub const LazyPath = union(@This().Tag) { install_lib, install_bin, install_include, + libc_runtimes, }; }; }; diff --git a/lib/std/Io.zig b/lib/std/Io.zig index 759855179a6e99e770afc2be497774b9e5b21cd2..1f26d2bf7ea49c898b81d7921e5520a6d6d033e0 100644 --- a/lib/std/Io.zig +++ b/lib/std/Io.zig @@ -218,8 +218,8 @@ pub const VTable = struct { childKill: *const fn (?*anyopaque, *std.process.Child) void, progressParentFile: *const fn (?*anyopaque) std.Progress.ParentFileError!File, - inheritParentDir: *const fn (?*anyopaque, handle: Dir.Handle) (Cancelable || UnexpectedError)!Dir, - inheritParentFile: *const fn (?*anyopaque, handle: File.Handle, flags: File.Flags) (Cancelable || UnexpectedError)!File, + inheritParentDir: *const fn (?*anyopaque, handle: Dir.Handle) InheritParentHandleError!Dir, + inheritParentFile: *const fn (?*anyopaque, handle: File.Handle, flags: File.Flags) InheritParentHandleError!File, now: *const fn (?*anyopaque, Clock) Timestamp, clockResolution: *const fn (?*anyopaque, Clock) Clock.ResolutionError!Duration, @@ -827,6 +827,10 @@ pub const UnexpectedError = error{ Unexpected, }; +pub const InheritParentHandleError = error{ + UnsupportedOperation, +} || Cancelable || UnexpectedError; + pub const Clock = enum { /// A settable system-wide clock that measures real (i.e. wall-clock) /// time. This clock is affected by discontinuous jumps in the system @@ -2802,8 +2806,8 @@ pub const failing: std.Io = .{ .childKill = unreachableChildKill, .progressParentFile = failingProgressParentFile, - .inheritParentDir = unreachableInheritParentDir, - .inheritParentFile = unreachableInheritParentFile, + .inheritParentDir = failingInheritParentDir, + .inheritParentFile = failingInheritParentFile, .random = noRandom, .randomSecure = failingRandomSecure, @@ -3474,17 +3478,17 @@ pub fn failingProgressParentFile(userdata: ?*anyopaque) std.Progress.ParentFileE return error.UnsupportedOperation; } -pub fn unreachableInheritParentDir(userdata: ?*anyopaque, handle: Dir.Handle) (Cancelable || UnexpectedError)!Dir { +pub fn failingInheritParentDir(userdata: ?*anyopaque, handle: Dir.Handle) InheritParentHandleError!Dir { _ = userdata; _ = handle; - unreachable; + return error.UnsupportedOperation; } -pub fn unreachableInheritParentFile(userdata: ?*anyopaque, handle: File.Handle, flags: File.Flags) (Cancelable || UnexpectedError)!File { +pub fn failingInheritParentFile(userdata: ?*anyopaque, handle: File.Handle, flags: File.Flags) InheritParentHandleError!File { _ = userdata; _ = handle; _ = flags; - unreachable; + return error.UnsupportedOperation; } pub fn noRandom(userdata: ?*anyopaque, buffer: []u8) void { diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig index 00f29608098c8942e621ba96d6e81e906b463d0f..30b924f59d835a85aeb2a1420d504a4a7d443b01 100644 --- a/lib/std/Io/Threaded.zig +++ b/lib/std/Io/Threaded.zig @@ -1975,6 +1975,10 @@ const have_copy_file_range = switch (native_os) { .linux, .freebsd => true, else => false, }; +const have_fcntl = switch (native_os) { + .linux, .dragonfly, .freebsd, .netbsd, .openbsd, .illumos, .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => true, + else => false, +}; const have_fcopyfile = is_darwin; const have_fchmodat2 = native_os == .linux and (builtin.os.isAtLeast(.linux, .{ .major = 6, .minor = 6, .patch = 0 }) orelse true) and @@ -17195,7 +17199,7 @@ pub fn posixExecveat( break :err posix.errno(posix.system.execve(p, argv, env_block.slice.ptr)); }; if (comptime native_os == .linux and (!builtin.link_libc or - (builtin.target.abi.isGnu() and builtin.target.os.version_range.linux.glibc.order( + (builtin.target.isGnuLibC() and builtin.target.os.version_range.linux.glibc.order( .{ .major = 2, .minor = 34, .patch = 0 }, ).compare(.gte)))) { diff --git a/test/src/Runner.zig b/test/src/Runner.zig index 8a7b3832a41b014de1d86626fe9b8bdd686ec15e..22f1962f0d6739e0a8b3ca09cef45bd610455cef 100644 --- a/test/src/Runner.zig +++ b/test/src/Runner.zig @@ -22,10 +22,12 @@ const Args = struct { src_dir: ?std.Io.Dir, targets: std.ArrayList(u32), target_bytes: std.ArrayList(u8), + libc_runtimes_dir: ?std.Io.Dir, + enable_darling: bool, enable_qemu: bool, - enable_wine: bool, + enable_rosetta: bool, enable_wasmtime: bool, - enable_darling: bool, + enable_wine: bool, quiet: bool, fn deinit(args: *Args, gpa: std.mem.Allocator) void { @@ -73,7 +75,28 @@ pub fn runServer(runner: *Runner) ProtocolError { .args => { const args_body = try arena.alloc(u8, hdr.bytes_len); runner.server.in.readSliceAll(args_body) catch unreachable; - var state: enum { positional, zig, lib, src, target } = .positional; + const State = enum { + positional, + @"--zig", + @"--lib", + @"--src", + @"--target", + @"--libc-runtimes", + }; + var state: State = .positional; + const state_expected: std.enums.EnumArray(State, enum { + path, + dir, + file, + string, + }) = .init(.{ + .positional = .path, + .@"--zig" = .file, + .@"--lib" = .dir, + .@"--src" = .dir, + .@"--target" = .string, + .@"--libc-runtimes" = .dir, + }); var input_dir: std.zig.Server.Message.InputDir = .cwd; var args_body_offset: usize = 0; while (args_body.len - args_body_offset > 0) { @@ -87,42 +110,56 @@ pub fn runServer(runner: *Runner) ProtocolError { args_body_offset = end + 1; switch (state) { .positional => if (std.mem.eql(u8, string, "--target")) { - state = .target; + state = .@"--target"; continue; } else if (std.mem.cutPrefix(u8, string, "--target=")) |target| { try runner.args.addTarget(runner.gpa, target); + } else if (std.mem.eql(u8, string, "--libc-runtimes")) { + state = .@"--libc-runtimes"; + continue; + } else if (std.mem.eql(u8, string, "-fdarling")) { + runner.args.enable_darling = true; } else if (std.mem.eql(u8, string, "-fqemu")) { runner.args.enable_qemu = true; - } else if (std.mem.eql(u8, string, "-fwine")) { - runner.args.enable_wine = true; + } else if (std.mem.eql(u8, string, "-frosetta")) { + runner.args.enable_rosetta = true; } else if (std.mem.eql(u8, string, "-fwasmtime")) { runner.args.enable_wasmtime = true; - } else if (std.mem.eql(u8, string, "-fdarling")) { - runner.args.enable_darling = true; + } else if (std.mem.eql(u8, string, "-fwine")) { + runner.args.enable_wine = true; } else if (std.mem.eql(u8, string, "--quiet")) { runner.args.quiet = true; }, - .zig => unreachable, - .lib => unreachable, - .src => unreachable, - .target => try runner.args.addTarget(runner.gpa, string), + .@"--target" => try runner.args.addTarget(runner.gpa, string), + else => return runner.fail( + "\"{t}\" expected {t}, got {t}", + .{ state, state_expected.get(state), arg }, + ), } }, .prefix => { const end = std.mem.findScalarPos(u8, args_body, args_body_offset, 0).?; const string = args_body[args_body_offset..end]; args_body_offset = end + 1; + assert(state == .positional); state = if (std.mem.eql(u8, string, "--zig=")) - .zig + .@"--zig" else if (std.mem.eql(u8, string, "--lib=")) - .lib + .@"--lib" else if (std.mem.eql(u8, string, "--src=")) - .src + .@"--src" + else if (std.mem.eql(u8, string, "--libc-runtimes=")) + .@"--libc-runtimes" else - unreachable; + return runner.fail("unsupported arg prefix: {q}", .{string}); continue; }, - .suffix => unreachable, + .suffix => { + const end = std.mem.findScalarPos(u8, args_body, args_body_offset, 0).?; + const string = args_body[args_body_offset..end]; + args_body_offset = end + 1; + return runner.fail("unsupported arg suffix: {q}", .{string}); + }, .input_dir => { input_dir = @fromBackingInt(@backingInt(input_dir) + 1); continue :arg .output_dir; @@ -137,16 +174,19 @@ pub fn runServer(runner: *Runner) ProtocolError { dir_handle.*, ) catch |err| switch (err) { error.Canceled => |e| return e, - error.Unexpected => |e| return runner.fail( + else => |e| return runner.fail( "unable to inherit parent dir: {t}", .{e}, ), }; switch (state) { .positional => { - assert(runner.args.@"test" == null); + if (runner.args.@"test" != null or + runner.args.manifest_file != null) return runner.fail( + "{t} specified multiple times", + .{state}, + ); runner.args.@"test" = .{ .input_dir = input_dir, .dir = dir }; - assert(runner.args.manifest_file == null); const manifest_path = "manifest"; runner.args.manifest_file = dir.openFile( runner.io, @@ -161,16 +201,31 @@ pub fn runServer(runner: *Runner) ProtocolError { }; try runner.discoverInput(input_dir, manifest_path); }, - .zig => unreachable, - .lib => { - assert(runner.args.lib_dir == null); + .@"--lib" => { + if (runner.args.lib_dir != null) return runner.fail( + "\"{t}\" specified multiple times", + .{state}, + ); runner.args.lib_dir = dir; }, - .src => { - assert(runner.args.src_dir == null); + .@"--src" => { + if (runner.args.src_dir != null) return runner.fail( + "\"{t}\" specified multiple times", + .{state}, + ); runner.args.src_dir = dir; }, - .target => unreachable, + .@"--libc-runtimes" => { + if (runner.args.libc_runtimes_dir != null) return runner.fail( + "\"{t}\" specified multiple times", + .{state}, + ); + runner.args.libc_runtimes_dir = dir; + }, + else => return runner.fail( + "\"{t}\" expected {t}, got {t}", + .{ state, state_expected.get(state), arg }, + ), } }, .input_file, .input_file_content, .output_file => { @@ -184,23 +239,31 @@ pub fn runServer(runner: *Runner) ProtocolError { .{ .nonblocking = false }, ) catch |err| switch (err) { error.Canceled => |e| return e, - error.Unexpected => |e| return runner.fail( + else => |e| return runner.fail( "unable to inherit parent file: {t}", .{e}, ), }; switch (state) { .positional => { - assert(runner.args.manifest_file == null); + if (runner.args.@"test" != null or + runner.args.manifest_file != null) return runner.fail( + "{t} specified multiple times", + .{state}, + ); runner.args.manifest_file = file; }, - .zig => { - assert(runner.args.zig_exe == null); + .@"--zig" => { + if (runner.args.zig_exe != null) return runner.fail( + "\"{t}\" specified multiple times", + .{state}, + ); runner.args.zig_exe = file; }, - .lib => unreachable, - .src => unreachable, - .target => unreachable, + else => return runner.fail( + "\"{t}\" expected {t}, got {t}", + .{ state, state_expected.get(state), arg }, + ), } }, } @@ -480,7 +543,6 @@ fn testOne(runner: *Runner, test_index: u32) TestError!void { .target_query = target_query, .manifest_sr = .init(&manifest_fr.interface, runner.gpa, &runner.eb_wip, src_path_string: { var path_buffer: [std.Io.Dir.max_path_bytes]u8 = undefined; - const src_path = src_path: { break :src_path path_buffer[0 .. manifest_file.realPath( runner.io, @@ -1022,6 +1084,7 @@ const Compiler = struct { const gpa = runner.gpa; const arena = runner.arena.allocator(); const io = runner.io; + const target = &comp.target.resolved; const config = &comp.config.?; const out_dir = ".zig-cache" ++ std.Io.Dir.path.sep_str ++ "o" ++ std.Io.Dir.path.sep_str ++ std.Build.Cache.binToHex(digest.*); @@ -1036,16 +1099,18 @@ const Compiler = struct { .stdout, .exit, .lldb => {}, } - const executor = executor: switch (std.zig.system.getExternalExecutor( - io, - &comp.target.resolved, - .{ - .host_cpu_arch = runner.host.cpu.arch, - .host_os_tag = runner.host.os.tag, - .link_mode = config.flags.link_mode, - .link_libc = config.flags.link_libc, - }, - )) { + var argv: std.ArrayList([]const u8) = .initBuffer(try arena.alloc([]const u8, 4)); + var environ_map: std.process.Environ.Map = .init(gpa); + defer environ_map.deinit(); + const need_cross_libc = + target.os.tag == .linux and config.flags.link_libc and config.flags.link_mode == .dynamic; + const use_executor = use_executor: switch (std.zig.system.getExternalExecutor(io, target, .{ + .host_cpu_arch = runner.host.cpu.arch, + .host_os_tag = runner.host.os.tag, + .qemu_fixes_dl = need_cross_libc and runner.args.libc_runtimes_dir != null, + .link_mode = config.flags.link_mode, + .link_libc = config.flags.link_libc, + })) { .bad_dl, .bad_os_or_cpu => { // This binary cannot be executed on this host. if (!runner.args.quiet) std.log.warn("skipping execution because host {q} cannot " ++ @@ -1054,24 +1119,57 @@ const Compiler = struct { }); return; }, - .native, .rosetta => null, - .qemu => |executor| if (runner.args.enable_qemu) - executor + .native => false, + .darling => |executor| if (runner.args.enable_darling) { + argv.appendAssumeCapacity(executor); + break :use_executor true; + } else continue :use_executor .bad_os_or_cpu, + .qemu => |executor| if (runner.args.enable_qemu) { + argv.appendAssumeCapacity(executor); + if (need_cross_libc) { + const libc_runtimes_dir = runner.args.libc_runtimes_dir orelse + continue :use_executor .bad_os_or_cpu; + var path_buffer: [std.Io.Dir.max_path_bytes]u8 = undefined; + const libc_runtimes_path = path_buffer[0 .. libc_runtimes_dir.realPath( + runner.io, + &path_buffer, + ) catch |err| switch (err) { + error.Canceled => |e| return e, + else => |e| return runner.fail("unable to get libc runtimes path: {t}", .{e}), + }]; + argv.appendSliceAssumeCapacity(&.{ "-L", try std.Io.Dir.path.join(arena, &.{ + libc_runtimes_path, + try if (target.isGnuLibC()) std.zig.target.glibcRuntimeTriple( + arena, + target.cpu.arch, + target.os.tag, + target.abi, + ) else if (target.isMuslLibC()) std.zig.target.muslRuntimeTriple( + arena, + target.cpu.arch, + target.abi, + ) else unreachable, + }) }); + } + break :use_executor true; + } else continue :use_executor .bad_os_or_cpu, + .rosetta => if (runner.args.enable_rosetta) + true else - continue :executor .bad_os_or_cpu, - .wine => |executor| if (runner.args.enable_wine) - executor - else - continue :executor .bad_os_or_cpu, - .wasmtime => |executor| if (runner.args.enable_wasmtime) - executor - else - continue :executor .bad_os_or_cpu, - .darling => |executor| if (runner.args.enable_darling) - executor - else - continue :executor .bad_os_or_cpu, + continue :use_executor .bad_os_or_cpu, + .wine => |executor| if (runner.args.enable_wine) { + if (!environ_map.contains("WINEDEBUG")) try environ_map.put("WINEDEBUG", "-all"); + argv.appendAssumeCapacity(executor); + break :use_executor true; + } else continue :use_executor .bad_os_or_cpu, + .wasmtime => |executor| if (runner.args.enable_wasmtime) { + if (!environ_map.contains("WASMTIME_BACKTRACE_DETAILS")) + try environ_map.put("WASMTIME_BACKTRACE_DETAILS", "1"); + argv.appendSliceAssumeCapacity(&.{ executor, "--dir=.", "-Sinherit-env" }); + break :use_executor true; + } else continue :use_executor .bad_os_or_cpu, }; + argv.appendAssumeCapacity(bin_path); var name_buffer: [std.Progress.Node.max_name_len]u8 = undefined; const run_prog_node = runner.prog_node.start(std.mem.print(&name_buffer, "run {s}", .{ @@ -1088,11 +1186,12 @@ const Compiler = struct { .errors => unreachable, .stdout, .exit => { const result = std.process.run(gpa, io, .{ - .exe = if (executor) |_| .search else .{ .file = bin_file }, - .argv = if (executor) |e| &.{ e, bin_path } else &.{bin_path}, + .exe = if (use_executor) .search else .{ .file = bin_file }, + .argv = argv.items, .cwd = .{ .dir = src_dir }, + .environ_map = &environ_map, .progress_node = run_prog_node, - }) catch |err| if (executor) |_| { + }) catch |err| if (use_executor) { // Chances are the foreign executor isn't available. Skip this evaluation. if (!runner.args.quiet) std.log.warn( "skipping execution of {q} via executor for foreign target {q}: {t}", @@ -1151,7 +1250,7 @@ const Compiler = struct { .{bin_path}, ), } - if (executor == null and result.stderr.len > 0) { + if (!use_executor and result.stderr.len > 0) { std.log.err("generated executable {q} had unexpected stderr:\n{s}", .{ bin_path, result.stderr, }); @@ -1257,10 +1356,12 @@ const ClientArgs = struct { src_dir: std.Io.Dir, targets: std.ArrayList([]const u8), keep_src: bool, + libc_runtimes_dir: ?std.Io.Dir, + enable_darling: bool, enable_qemu: bool, + enable_rosetta: bool, enable_wine: bool, enable_wasmtime: bool, - enable_darling: bool, quiet: bool, }; pub fn main(init: std.process.Init) (std.mem.Allocator.Error || std.Io.Cancelable)!u8 { @@ -1275,6 +1376,7 @@ pub fn main(init: std.process.Init) (std.mem.Allocator.Error || std.Io.Cancelabl var test_path_arg: ?[]const u8 = null; var zig_path_arg: ?[]const u8 = null; var lib_path_arg: ?[]const u8 = null; + var libc_runtimes_path_arg: ?[]const u8 = null; var args: ClientArgs = .{ .test_file = undefined, .test_kind = undefined, @@ -1283,10 +1385,12 @@ pub fn main(init: std.process.Init) (std.mem.Allocator.Error || std.Io.Cancelabl .src_dir = undefined, .targets = .empty, .keep_src = false, + .libc_runtimes_dir = null, + .enable_darling = false, .enable_qemu = false, + .enable_rosetta = false, .enable_wine = false, .enable_wasmtime = false, - .enable_darling = false, .quiet = false, }; defer args.targets.deinit(init.gpa); @@ -1312,10 +1416,12 @@ pub fn main(init: std.process.Init) (std.mem.Allocator.Error || std.Io.Cancelabl .src_dir = null, .targets = .empty, .target_bytes = .empty, + .libc_runtimes_dir = null, + .enable_darling = false, .enable_qemu = false, - .enable_wine = false, + .enable_rosetta = false, .enable_wasmtime = false, - .enable_darling = false, + .enable_wine = false, .quiet = false, }, .host = std.zig.system.resolveTargetQuery(init.io, .{}) catch |err| switch (err) { @@ -1361,18 +1467,24 @@ pub fn main(init: std.process.Init) (std.mem.Allocator.Error || std.Io.Cancelabl try args.targets.append(init.gpa, try arena.dupe(u8, target)); } else if (std.mem.eql(u8, arg, "--keep-src")) { args.keep_src = true; + } else if (std.mem.eql(u8, arg, "--libc-runtimes")) { + libc_runtimes_path_arg = arg_it.next() orelse fatal("missing arg after {q}", .{arg}); + } else if (std.mem.cutPrefix(u8, arg, "--libc-runtimes=")) |libc_runtimes_path| { + libc_runtimes_path_arg = libc_runtimes_path; + } else if (std.mem.eql(u8, arg, "-fdarling")) { + args.enable_darling = true; } else if (std.mem.eql(u8, arg, "-fqemu")) { args.enable_qemu = true; + } else if (std.mem.eql(u8, arg, "-frosetta")) { + args.enable_rosetta = true; } else if (std.mem.eql(u8, arg, "-fwine")) { args.enable_wine = true; } else if (std.mem.eql(u8, arg, "-fwasmtime")) { args.enable_wasmtime = true; - } else if (std.mem.eql(u8, arg, "-fdarling")) { - args.enable_darling = true; } else if (std.mem.eql(u8, arg, "--quiet")) { args.quiet = true; } else { - if (test_path_arg) |_| fatal("unknown arg {q}", .{arg}); + if (test_path_arg) |_| fatal("unexpected arg {q}", .{arg}); test_path_arg = arg; } } @@ -1403,6 +1515,15 @@ pub fn main(init: std.process.Init) (std.mem.Allocator.Error || std.Io.Cancelabl else => |e| fatal("unable to open {q}: {t}", .{ lib_path, e }), }; defer args.lib_dir.close(init.io); + if (libc_runtimes_path_arg) |libc_runtimes_path| args.libc_runtimes_dir = cwd.openDir( + init.io, + libc_runtimes_path, + .{}, + ) catch |err| switch (err) { + error.Canceled => |e| return e, + else => |e| fatal("unable to open {q}: {t}", .{ lib_path, e }), + }; + defer if (args.libc_runtimes_dir) |libc_runtimes_dir| libc_runtimes_dir.close(init.io); const src_dir_path = "src_" ++ std.fmt.hex(rand_int: { var rand_int: u64 = undefined; @@ -1479,21 +1600,18 @@ fn runClient( try argv.append(gpa, @backingInt(Arg.prefix)); try argv.appendSlice(gpa, "--zig="); try argv.append(gpa, 0); - try argv.append(gpa, @backingInt(Arg.input_file)); try argv.appendSlice(gpa, @ptrCast(&args.zig_exe.handle)); try argv.append(gpa, @backingInt(Arg.prefix)); try argv.appendSlice(gpa, "--lib="); try argv.append(gpa, 0); - try argv.append(gpa, @backingInt(Arg.input_dir)); try argv.appendSlice(gpa, @ptrCast(&args.lib_dir.handle)); try argv.append(gpa, @backingInt(Arg.prefix)); try argv.appendSlice(gpa, "--src="); try argv.append(gpa, 0); - try argv.append(gpa, @backingInt(Arg.output_dir)); try argv.appendSlice(gpa, @ptrCast(&args.src_dir.handle)); @@ -1507,11 +1625,28 @@ fn runClient( try argv.append(gpa, 0); } + if (args.libc_runtimes_dir) |libc_runtimes_dir| { + try argv.append(gpa, @backingInt(Arg.prefix)); + try argv.appendSlice(gpa, "--libc-runtimes="); + try argv.append(gpa, 0); + try argv.append(gpa, @backingInt(Arg.input_dir)); + try argv.appendSlice(gpa, @ptrCast(&libc_runtimes_dir.handle)); + } + if (args.enable_darling) { + try argv.append(gpa, @backingInt(Arg.string)); + try argv.appendSlice(gpa, "-fdarling"); + try argv.append(gpa, 0); + } if (args.enable_qemu) { try argv.append(gpa, @backingInt(Arg.string)); try argv.appendSlice(gpa, "-fqemu"); try argv.append(gpa, 0); } + if (args.enable_rosetta) { + try argv.append(gpa, @backingInt(Arg.string)); + try argv.appendSlice(gpa, "-frosetta"); + try argv.append(gpa, 0); + } if (args.enable_wine) { try argv.append(gpa, @backingInt(Arg.string)); try argv.appendSlice(gpa, "-fwine"); @@ -1522,11 +1657,6 @@ fn runClient( try argv.appendSlice(gpa, "-fwasmtime"); try argv.append(gpa, 0); } - if (args.enable_darling) { - try argv.append(gpa, @backingInt(Arg.string)); - try argv.appendSlice(gpa, "-fdarling"); - try argv.append(gpa, 0); - } if (args.quiet) { try argv.append(gpa, @backingInt(Arg.string)); diff --git a/test/tests.zig b/test/tests.zig index 3da8ef96442b31b91217fadc6334d5102dcaa76d..307a061ac885678ee2868821135896409e01e817 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -3411,6 +3411,7 @@ pub fn addIncrementalTests( run.addArgs(&.{ "--target", target_str }); } + run.addPrefixedDirectoryArg("--libc-runtimes=", .{ .relative = .{ .base = .libc_runtimes } }); run.addThirdPartyEnabledArgDarling(.{ .enabled = "-fdarling" }); run.addThirdPartyEnabledArgQemu(.{ .enabled = "-fqemu" }); run.addThirdPartyEnabledArgRosetta(.{ .enabled = "-frosetta" });