authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-09-25 12:20:18-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-09-26 19:08:50-04:00
log4dd645fdddec2c56f8eaabce9f358f95b54f8eec
treed1ec373560e390e2f1d9a505478114713c857d79
parentee0bd6c69ee01caf076e5c9f7461fe09fa8cf9ba

Runner: add --libc-runtimes support


9 files changed, 285 insertions(+), 112 deletions(-)

lib/compiler/Maker.zig+25-9
...@@ -3631,7 +3631,7 @@ pub fn resolveLazyPath(...@@ -3631,7 +3631,7 @@ pub fn resolveLazyPath(
3631 const c = &maker.scanned_config.configuration;3631 const c = &maker.scanned_config.configuration;
3632 return switch (lazy_path) {3632 return switch (lazy_path) {
3633 .source_path => |sp| try packagePath(maker, arena, sp.owner, sp.sub_path.slice(c)),3633 .source_path => |sp| try packagePath(maker, arena, sp.owner, sp.sub_path.slice(c)),
3634 .relative => |relative| relativePath(maker, arena, relative),3634 .relative => |relative| try relativePath(maker, arena, relative, stepByIndex(maker, asking_step_index)),
3635 .generated => |gen| {3635 .generated => |gen| {
3636 const base = generatedPath(maker, gen.index);3636 const base = generatedPath(maker, gen.index);
3637 var file_path = base;3637 var file_path = base;
...@@ -3768,7 +3768,12 @@ pub fn packagePath(...@@ -3768,7 +3768,12 @@ pub fn packagePath(
3768 };3768 };
3769}3769}
37703770
3771pub fn relativePath(maker: *const Maker, arena: Allocator, relative: Configuration.LazyPath.Relative) Allocator.Error!Path {3771pub fn relativePath(
3772 maker: *const Maker,
3773 arena: Allocator,
3774 relative: Configuration.LazyPath.Relative,
3775 asking_step: *Step,
3776) error{ OutOfMemory, MakeFailed }!Path {
3772 const graph = maker.graph;3777 const graph = maker.graph;
3773 const c = &maker.scanned_config.configuration;3778 const c = &maker.scanned_config.configuration;
3774 const sub_path = relative.sub_path.slice(c);3779 const sub_path = relative.sub_path.slice(c);
...@@ -3789,12 +3794,12 @@ pub fn relativePath(maker: *const Maker, arena: Allocator, relative: Configurati...@@ -3789,12 +3794,12 @@ pub fn relativePath(maker: *const Maker, arena: Allocator, relative: Configurati
3789 .root_dir = graph.build_root_directory,3794 .root_dir = graph.build_root_directory,
3790 .sub_path = sub_path,3795 .sub_path = sub_path,
3791 },3796 },
3792 .zig_exe => .{3797 .zig_exe => {
3793 .root_dir = .cwd(),3798 assert(sub_path.len == 0);
3794 .sub_path = if (sub_path.len == 0)3799 return .{
3795 graph.zig_exe3800 .root_dir = .cwd(),
3796 else3801 .sub_path = graph.zig_exe,
3797 try Io.Dir.path.join(arena, &.{ graph.zig_exe, sub_path }),3802 };
3798 },3803 },
3799 .zig_lib => .{3804 .zig_lib => .{
3800 .root_dir = graph.zig_lib_directory,3805 .root_dir = graph.zig_lib_directory,
...@@ -3804,6 +3809,10 @@ pub fn relativePath(maker: *const Maker, arena: Allocator, relative: Configurati...@@ -3804,6 +3809,10 @@ pub fn relativePath(maker: *const Maker, arena: Allocator, relative: Configurati
3804 .install_lib => try maker.install_paths.lib.join(arena, sub_path),3809 .install_lib => try maker.install_paths.lib.join(arena, sub_path),
3805 .install_bin => try maker.install_paths.bin.join(arena, sub_path),3810 .install_bin => try maker.install_paths.bin.join(arena, sub_path),
3806 .install_include => try maker.install_paths.include.join(arena, sub_path),3811 .install_include => try maker.install_paths.include.join(arena, sub_path),
3812 .libc_runtimes => if (maker.graph.libc_runtimes_dir) |libc_runtimes_dir| .{
3813 .root_dir = .cwd(),
3814 .sub_path = try Dir.path.join(arena, &.{ libc_runtimes_dir, sub_path }),
3815 } else asking_step.fail(maker, "unknown LazyPath: \"--libc-runtimes\" not specified", .{}),
3807 };3816 };
3808}3817}
38093818
...@@ -4391,15 +4400,22 @@ fn confPathDepToCachePath(...@@ -4391,15 +4400,22 @@ fn confPathDepToCachePath(
4391 else => |index| try Dir.path.join(arena, &.{ index.get(c).?.root_path.slice(c), sub_path }),4400 else => |index| try Dir.path.join(arena, &.{ index.get(c).?.root_path.slice(c), sub_path }),
4392 },4401 },
4393 },4402 },
4403 .zig_exe => {
4404 assert(sub_path.len == 0);
4405 return .{
4406 .root_dir = .cwd(),
4407 .sub_path = graph.zig_exe,
4408 };
4409 },
4394 .zig_lib => .{4410 .zig_lib => .{
4395 .root_dir = graph.zig_lib_directory,4411 .root_dir = graph.zig_lib_directory,
4396 .sub_path = sub_path,4412 .sub_path = sub_path,
4397 },4413 },
4398 .zig_exe => @panic("TODO"),
4399 .install_prefix => @panic("TODO"),4414 .install_prefix => @panic("TODO"),
4400 .install_lib => @panic("TODO"),4415 .install_lib => @panic("TODO"),
4401 .install_bin => @panic("TODO"),4416 .install_bin => @panic("TODO"),
4402 .install_include => @panic("TODO"),4417 .install_include => @panic("TODO"),
4418 .libc_runtimes => @panic("TODO"),
4403 };4419 };
4404}4420}
44054421
lib/compiler/Maker/Step.zig+5-5
...@@ -857,7 +857,7 @@ pub fn setWatchInputsFromManifestFiles(...@@ -857,7 +857,7 @@ pub fn setWatchInputsFromManifestFiles(
857}857}
858858
859/// For steps that have a single input that never changes when re-running `make`.859/// For steps that have a single input that never changes when re-running `make`.
860pub fn singleUnchangingWatchInput(step: *Step, maker: *Maker, arena: Allocator, lazy_path: LazyPath) Allocator.Error!void {860pub fn singleUnchangingWatchInput(step: *Step, maker: *Maker, arena: Allocator, lazy_path: LazyPath) FailError!void {
861 if (!step.inputs.populated()) try step.addWatchInput(maker, arena, lazy_path);861 if (!step.inputs.populated()) try step.addWatchInput(maker, arena, lazy_path);
862}862}
863863
...@@ -866,7 +866,7 @@ pub fn clearWatchInputs(step: *Step, maker: *Maker) void {...@@ -866,7 +866,7 @@ pub fn clearWatchInputs(step: *Step, maker: *Maker) void {
866}866}
867867
868/// Places a *file* dependency on the path.868/// Places a *file* dependency on the path.
869pub fn addWatchInput(step: *Step, maker: *Maker, arena: Allocator, lazy_file: LazyPath) Allocator.Error!void {869pub fn addWatchInput(step: *Step, maker: *Maker, arena: Allocator, lazy_file: LazyPath) FailError!void {
870 const conf = &maker.scanned_config.configuration;870 const conf = &maker.scanned_config.configuration;
871 switch (lazy_file) {871 switch (lazy_file) {
872 .source_path => |source_path| {872 .source_path => |source_path| {
...@@ -875,7 +875,7 @@ pub fn addWatchInput(step: *Step, maker: *Maker, arena: Allocator, lazy_file: La...@@ -875,7 +875,7 @@ pub fn addWatchInput(step: *Step, maker: *Maker, arena: Allocator, lazy_file: La
875 try addWatchInputPath(step, maker, pkg_path);875 try addWatchInputPath(step, maker, pkg_path);
876 },876 },
877 .relative => |relative| {877 .relative => |relative| {
878 const resolved_path = try maker.relativePath(arena, relative);878 const resolved_path = try maker.relativePath(arena, relative, step);
879 try addWatchInputPath(step, maker, resolved_path);879 try addWatchInputPath(step, maker, resolved_path);
880 },880 },
881 // Nothing to watch because this dependency edge is modeled instead via `dependants`.881 // 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...@@ -890,7 +890,7 @@ pub fn addWatchInput(step: *Step, maker: *Maker, arena: Allocator, lazy_file: La
890/// Paths derived from this directory should also be manually added via890/// Paths derived from this directory should also be manually added via
891/// `addDirectoryWatchInputFromPath` if and only if this function returns891/// `addDirectoryWatchInputFromPath` if and only if this function returns
892/// `true`.892/// `true`.
893pub fn addDirectoryWatchInput(step: *Step, maker: *Maker, lazy_directory: LazyPath) Allocator.Error!bool {893pub fn addDirectoryWatchInput(step: *Step, maker: *Maker, lazy_directory: LazyPath) FailError!bool {
894 const graph = maker.graph;894 const graph = maker.graph;
895 const arena = graph.arena; // TODO don't leak into the process arena895 const arena = graph.arena; // TODO don't leak into the process arena
896 switch (lazy_directory) {896 switch (lazy_directory) {
...@@ -901,7 +901,7 @@ pub fn addDirectoryWatchInput(step: *Step, maker: *Maker, lazy_directory: LazyPa...@@ -901,7 +901,7 @@ pub fn addDirectoryWatchInput(step: *Step, maker: *Maker, lazy_directory: LazyPa
901 try addDirectoryWatchInputFromPath(step, maker, pkg_path);901 try addDirectoryWatchInputFromPath(step, maker, pkg_path);
902 },902 },
903 .relative => |relative| {903 .relative => |relative| {
904 const resolved_path = try maker.relativePath(arena, relative);904 const resolved_path = try maker.relativePath(arena, relative, step);
905 try addDirectoryWatchInputFromPath(step, maker, resolved_path);905 try addDirectoryWatchInputFromPath(step, maker, resolved_path);
906 },906 },
907 // Nothing to watch because this dependency edge is modeled instead via `dependants`.907 // Nothing to watch because this dependency edge is modeled instead via `dependants`.
lib/compiler/Maker/Step/Run.zig+23-9
...@@ -250,9 +250,18 @@ pub fn make(...@@ -250,9 +250,18 @@ pub fn make(
250 protocol_args.appendAssumeCapacity(0);250 protocol_args.appendAssumeCapacity(0);
251 },251 },
252 .path_file => {252 .path_file => {
253 const lazy_path = arg.path.value.?.get(conf);
254 switch (lazy_path) {
255 else => {},
256 .relative => |relative| switch (relative.flags.base) {
257 else => {},
258 .libc_runtimes => if (graph.libc_runtimes_dir == null) continue,
259 },
260 }
261
253 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";262 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";
254 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";263 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
255 const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index);264 const file_path = try maker.resolveLazyPath(arena, lazy_path, run_index);
256265
257 try owned_files.resize(gpa, owned_files.bit_length + 1, true);266 try owned_files.resize(gpa, owned_files.bit_length + 1, true);
258 try inherit_files.ensureUnusedCapacity(gpa, 1);267 try inherit_files.ensureUnusedCapacity(gpa, 1);
...@@ -283,9 +292,18 @@ pub fn make(...@@ -283,9 +292,18 @@ pub fn make(
283 }292 }
284 },293 },
285 .path_directory => {294 .path_directory => {
295 const lazy_path = arg.path.value.?.get(conf);
296 switch (lazy_path) {
297 else => {},
298 .relative => |relative| switch (relative.flags.base) {
299 else => {},
300 .libc_runtimes => if (graph.libc_runtimes_dir == null) continue,
301 },
302 }
303
286 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";304 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";
287 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";305 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
288 const dir_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index);306 const dir_path = try maker.resolveLazyPath(arena, lazy_path, run_index);
289 try input_dirs.append(gpa, dir_path);307 try input_dirs.append(gpa, dir_path);
290308
291 const has_sub_path = dir_path.sub_path.len > 0;309 const has_sub_path = dir_path.sub_path.len > 0;
...@@ -2242,12 +2260,8 @@ fn runCommand(...@@ -2242,12 +2260,8 @@ fn runCommand(
2242 else => builtin.target,2260 else => builtin.target,
2243 };2261 };
22442262
2245 const need_cross_libc = config.flags.link_libc and root_target.os.tag == .linux and2263 const need_cross_libc = root_target.os.tag == .linux and
2246 switch (producer.flags2.linkage) {2264 config.flags.link_libc and config.flags.link_mode == .dynamic;
2247 .static => false,
2248 .dynamic => true,
2249 .default => root_target.isGnuLibC(),
2250 };
2251 switch (std.zig.system.getExternalExecutor(io, &root_target, .{2265 switch (std.zig.system.getExternalExecutor(io, &root_target, .{
2252 .host_cpu_arch = host.cpu.arch,2266 .host_cpu_arch = host.cpu.arch,
2253 .host_os_tag = host.os.tag,2267 .host_os_tag = host.os.tag,
...@@ -2316,7 +2330,7 @@ fn runCommand(...@@ -2316,7 +2330,7 @@ fn runCommand(
2316 interp_argv.appendAssumeCapacity(bin_name);2330 interp_argv.appendAssumeCapacity(bin_name);
2317 interp_argv.appendAssumeCapacity("--dir=.");2331 interp_argv.appendAssumeCapacity("--dir=.");
2318 for (conf_run.preopens.slice) |preopen| {2332 for (conf_run.preopens.slice) |preopen| {
2319 const path = try maker.resolveLazyPath(arena, preopen.path.get(conf), run_index);2333 const path = try maker.resolveLazyPathIndex(arena, preopen.path, run_index);
2320 path.root_dir.handle.createDirPath(io, path.subPathOrDot()) catch |e|2334 path.root_dir.handle.createDirPath(io, path.subPathOrDot()) catch |e|
2321 return step.fail(maker, "failed creating directory {f}: {t}", .{ path, e });2335 return step.fail(maker, "failed creating directory {f}: {t}", .{ path, e });
2322 interp_argv.appendAssumeCapacity(try arena.print("--dir={f}::{s}", .{ path, preopen.name.slice(conf) }));2336 interp_argv.appendAssumeCapacity(try arena.print("--dir={f}::{s}", .{ path, preopen.name.slice(conf) }));
lib/std/Build.zig+4-1
...@@ -2693,12 +2693,15 @@ fn validateConfigureDependency(lazy_path: LazyPath) void {...@@ -2693,12 +2693,15 @@ fn validateConfigureDependency(lazy_path: LazyPath) void {
2693 .src_path, .cwd_relative, .dependency => {}, // OK2693 .src_path, .cwd_relative, .dependency => {}, // OK
2694 .generated => @panic("configure phase cannot depend on files generated during make phase"),2694 .generated => @panic("configure phase cannot depend on files generated during make phase"),
2695 .relative => |relative| switch (relative.base) {2695 .relative => |relative| switch (relative.base) {
2696 .cwd, .build_root, .local_cache, .global_cache, .zig_exe, .zig_lib => {}, // OK2696 .cwd, .build_root, .local_cache, .global_cache, .zig_lib => {}, // OK
2697 .zig_exe => if (relative.sub_path.len > 0) @panic("file base cannot have a sub path"),
2697 .install_prefix,2698 .install_prefix,
2698 .install_lib,2699 .install_lib,
2699 .install_bin,2700 .install_bin,
2700 .install_include,2701 .install_include,
2701 => @panic("configure phase cannot depend on files installed during make phase"),2702 => @panic("configure phase cannot depend on files installed during make phase"),
2703 .libc_runtimes,
2704 => @panic("configure phase cannot depend on directory known only during make phase"),
2702 },2705 },
2703 }2706 }
2704}2707}
lib/std/Build/Configuration.zig+1
...@@ -1575,6 +1575,7 @@ pub const LazyPath = union(@This().Tag) {...@@ -1575,6 +1575,7 @@ pub const LazyPath = union(@This().Tag) {
1575 install_lib,1575 install_lib,
1576 install_bin,1576 install_bin,
1577 install_include,1577 install_include,
1578 libc_runtimes,
1578 };1579 };
1579 };1580 };
1580};1581};
lib/std/Io.zig+12-8
...@@ -218,8 +218,8 @@ pub const VTable = struct {...@@ -218,8 +218,8 @@ pub const VTable = struct {
218 childKill: *const fn (?*anyopaque, *std.process.Child) void,218 childKill: *const fn (?*anyopaque, *std.process.Child) void,
219219
220 progressParentFile: *const fn (?*anyopaque) std.Progress.ParentFileError!File,220 progressParentFile: *const fn (?*anyopaque) std.Progress.ParentFileError!File,
221 inheritParentDir: *const fn (?*anyopaque, handle: Dir.Handle) (Cancelable || UnexpectedError)!Dir,221 inheritParentDir: *const fn (?*anyopaque, handle: Dir.Handle) InheritParentHandleError!Dir,
222 inheritParentFile: *const fn (?*anyopaque, handle: File.Handle, flags: File.Flags) (Cancelable || UnexpectedError)!File,222 inheritParentFile: *const fn (?*anyopaque, handle: File.Handle, flags: File.Flags) InheritParentHandleError!File,
223223
224 now: *const fn (?*anyopaque, Clock) Timestamp,224 now: *const fn (?*anyopaque, Clock) Timestamp,
225 clockResolution: *const fn (?*anyopaque, Clock) Clock.ResolutionError!Duration,225 clockResolution: *const fn (?*anyopaque, Clock) Clock.ResolutionError!Duration,
...@@ -827,6 +827,10 @@ pub const UnexpectedError = error{...@@ -827,6 +827,10 @@ pub const UnexpectedError = error{
827 Unexpected,827 Unexpected,
828};828};
829829
830pub const InheritParentHandleError = error{
831 UnsupportedOperation,
832} || Cancelable || UnexpectedError;
833
830pub const Clock = enum {834pub const Clock = enum {
831 /// A settable system-wide clock that measures real (i.e. wall-clock)835 /// A settable system-wide clock that measures real (i.e. wall-clock)
832 /// time. This clock is affected by discontinuous jumps in the system836 /// time. This clock is affected by discontinuous jumps in the system
...@@ -2802,8 +2806,8 @@ pub const failing: std.Io = .{...@@ -2802,8 +2806,8 @@ pub const failing: std.Io = .{
2802 .childKill = unreachableChildKill,2806 .childKill = unreachableChildKill,
28032807
2804 .progressParentFile = failingProgressParentFile,2808 .progressParentFile = failingProgressParentFile,
2805 .inheritParentDir = unreachableInheritParentDir,2809 .inheritParentDir = failingInheritParentDir,
2806 .inheritParentFile = unreachableInheritParentFile,2810 .inheritParentFile = failingInheritParentFile,
28072811
2808 .random = noRandom,2812 .random = noRandom,
2809 .randomSecure = failingRandomSecure,2813 .randomSecure = failingRandomSecure,
...@@ -3474,17 +3478,17 @@ pub fn failingProgressParentFile(userdata: ?*anyopaque) std.Progress.ParentFileE...@@ -3474,17 +3478,17 @@ pub fn failingProgressParentFile(userdata: ?*anyopaque) std.Progress.ParentFileE
3474 return error.UnsupportedOperation;3478 return error.UnsupportedOperation;
3475}3479}
34763480
3477pub fn unreachableInheritParentDir(userdata: ?*anyopaque, handle: Dir.Handle) (Cancelable || UnexpectedError)!Dir {3481pub fn failingInheritParentDir(userdata: ?*anyopaque, handle: Dir.Handle) InheritParentHandleError!Dir {
3478 _ = userdata;3482 _ = userdata;
3479 _ = handle;3483 _ = handle;
3480 unreachable;3484 return error.UnsupportedOperation;
3481}3485}
34823486
3483pub fn unreachableInheritParentFile(userdata: ?*anyopaque, handle: File.Handle, flags: File.Flags) (Cancelable || UnexpectedError)!File {3487pub fn failingInheritParentFile(userdata: ?*anyopaque, handle: File.Handle, flags: File.Flags) InheritParentHandleError!File {
3484 _ = userdata;3488 _ = userdata;
3485 _ = handle;3489 _ = handle;
3486 _ = flags;3490 _ = flags;
3487 unreachable;3491 return error.UnsupportedOperation;
3488}3492}
34893493
3490pub fn noRandom(userdata: ?*anyopaque, buffer: []u8) void {3494pub fn noRandom(userdata: ?*anyopaque, buffer: []u8) void {
lib/std/Io/Threaded.zig+5-1
...@@ -1975,6 +1975,10 @@ const have_copy_file_range = switch (native_os) {...@@ -1975,6 +1975,10 @@ const have_copy_file_range = switch (native_os) {
1975 .linux, .freebsd => true,1975 .linux, .freebsd => true,
1976 else => false,1976 else => false,
1977};1977};
1978const have_fcntl = switch (native_os) {
1979 .linux, .dragonfly, .freebsd, .netbsd, .openbsd, .illumos, .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => true,
1980 else => false,
1981};
1978const have_fcopyfile = is_darwin;1982const have_fcopyfile = is_darwin;
1979const have_fchmodat2 = native_os == .linux and1983const have_fchmodat2 = native_os == .linux and
1980 (builtin.os.isAtLeast(.linux, .{ .major = 6, .minor = 6, .patch = 0 }) orelse true) and1984 (builtin.os.isAtLeast(.linux, .{ .major = 6, .minor = 6, .patch = 0 }) orelse true) and
...@@ -17195,7 +17199,7 @@ pub fn posixExecveat(...@@ -17195,7 +17199,7 @@ pub fn posixExecveat(
17195 break :err posix.errno(posix.system.execve(p, argv, env_block.slice.ptr));17199 break :err posix.errno(posix.system.execve(p, argv, env_block.slice.ptr));
17196 };17200 };
17197 if (comptime native_os == .linux and (!builtin.link_libc or17201 if (comptime native_os == .linux and (!builtin.link_libc or
17198 (builtin.target.abi.isGnu() and builtin.target.os.version_range.linux.glibc.order(17202 (builtin.target.isGnuLibC() and builtin.target.os.version_range.linux.glibc.order(
17199 .{ .major = 2, .minor = 34, .patch = 0 },17203 .{ .major = 2, .minor = 34, .patch = 0 },
17200 ).compare(.gte))))17204 ).compare(.gte))))
17201 {17205 {
test/src/Runner.zig+209-79
...@@ -22,10 +22,12 @@ const Args = struct {...@@ -22,10 +22,12 @@ const Args = struct {
22 src_dir: ?std.Io.Dir,22 src_dir: ?std.Io.Dir,
23 targets: std.ArrayList(u32),23 targets: std.ArrayList(u32),
24 target_bytes: std.ArrayList(u8),24 target_bytes: std.ArrayList(u8),
25 libc_runtimes_dir: ?std.Io.Dir,
26 enable_darling: bool,
25 enable_qemu: bool,27 enable_qemu: bool,
26 enable_wine: bool,28 enable_rosetta: bool,
27 enable_wasmtime: bool,29 enable_wasmtime: bool,
28 enable_darling: bool,30 enable_wine: bool,
29 quiet: bool,31 quiet: bool,
3032
31 fn deinit(args: *Args, gpa: std.mem.Allocator) void {33 fn deinit(args: *Args, gpa: std.mem.Allocator) void {
...@@ -73,7 +75,28 @@ pub fn runServer(runner: *Runner) ProtocolError {...@@ -73,7 +75,28 @@ pub fn runServer(runner: *Runner) ProtocolError {
73 .args => {75 .args => {
74 const args_body = try arena.alloc(u8, hdr.bytes_len);76 const args_body = try arena.alloc(u8, hdr.bytes_len);
75 runner.server.in.readSliceAll(args_body) catch unreachable;77 runner.server.in.readSliceAll(args_body) catch unreachable;
76 var state: enum { positional, zig, lib, src, target } = .positional;78 const State = enum {
79 positional,
80 @"--zig",
81 @"--lib",
82 @"--src",
83 @"--target",
84 @"--libc-runtimes",
85 };
86 var state: State = .positional;
87 const state_expected: std.enums.EnumArray(State, enum {
88 path,
89 dir,
90 file,
91 string,
92 }) = .init(.{
93 .positional = .path,
94 .@"--zig" = .file,
95 .@"--lib" = .dir,
96 .@"--src" = .dir,
97 .@"--target" = .string,
98 .@"--libc-runtimes" = .dir,
99 });
77 var input_dir: std.zig.Server.Message.InputDir = .cwd;100 var input_dir: std.zig.Server.Message.InputDir = .cwd;
78 var args_body_offset: usize = 0;101 var args_body_offset: usize = 0;
79 while (args_body.len - args_body_offset > 0) {102 while (args_body.len - args_body_offset > 0) {
...@@ -87,42 +110,56 @@ pub fn runServer(runner: *Runner) ProtocolError {...@@ -87,42 +110,56 @@ pub fn runServer(runner: *Runner) ProtocolError {
87 args_body_offset = end + 1;110 args_body_offset = end + 1;
88 switch (state) {111 switch (state) {
89 .positional => if (std.mem.eql(u8, string, "--target")) {112 .positional => if (std.mem.eql(u8, string, "--target")) {
90 state = .target;113 state = .@"--target";
91 continue;114 continue;
92 } else if (std.mem.cutPrefix(u8, string, "--target=")) |target| {115 } else if (std.mem.cutPrefix(u8, string, "--target=")) |target| {
93 try runner.args.addTarget(runner.gpa, target);116 try runner.args.addTarget(runner.gpa, target);
117 } else if (std.mem.eql(u8, string, "--libc-runtimes")) {
118 state = .@"--libc-runtimes";
119 continue;
120 } else if (std.mem.eql(u8, string, "-fdarling")) {
121 runner.args.enable_darling = true;
94 } else if (std.mem.eql(u8, string, "-fqemu")) {122 } else if (std.mem.eql(u8, string, "-fqemu")) {
95 runner.args.enable_qemu = true;123 runner.args.enable_qemu = true;
96 } else if (std.mem.eql(u8, string, "-fwine")) {124 } else if (std.mem.eql(u8, string, "-frosetta")) {
97 runner.args.enable_wine = true;125 runner.args.enable_rosetta = true;
98 } else if (std.mem.eql(u8, string, "-fwasmtime")) {126 } else if (std.mem.eql(u8, string, "-fwasmtime")) {
99 runner.args.enable_wasmtime = true;127 runner.args.enable_wasmtime = true;
100 } else if (std.mem.eql(u8, string, "-fdarling")) {128 } else if (std.mem.eql(u8, string, "-fwine")) {
101 runner.args.enable_darling = true;129 runner.args.enable_wine = true;
102 } else if (std.mem.eql(u8, string, "--quiet")) {130 } else if (std.mem.eql(u8, string, "--quiet")) {
103 runner.args.quiet = true;131 runner.args.quiet = true;
104 },132 },
105 .zig => unreachable,133 .@"--target" => try runner.args.addTarget(runner.gpa, string),
106 .lib => unreachable,134 else => return runner.fail(
107 .src => unreachable,135 "\"{t}\" expected {t}, got {t}",
108 .target => try runner.args.addTarget(runner.gpa, string),136 .{ state, state_expected.get(state), arg },
137 ),
109 }138 }
110 },139 },
111 .prefix => {140 .prefix => {
112 const end = std.mem.findScalarPos(u8, args_body, args_body_offset, 0).?;141 const end = std.mem.findScalarPos(u8, args_body, args_body_offset, 0).?;
113 const string = args_body[args_body_offset..end];142 const string = args_body[args_body_offset..end];
114 args_body_offset = end + 1;143 args_body_offset = end + 1;
144 assert(state == .positional);
115 state = if (std.mem.eql(u8, string, "--zig="))145 state = if (std.mem.eql(u8, string, "--zig="))
116 .zig146 .@"--zig"
117 else if (std.mem.eql(u8, string, "--lib="))147 else if (std.mem.eql(u8, string, "--lib="))
118 .lib148 .@"--lib"
119 else if (std.mem.eql(u8, string, "--src="))149 else if (std.mem.eql(u8, string, "--src="))
120 .src150 .@"--src"
151 else if (std.mem.eql(u8, string, "--libc-runtimes="))
152 .@"--libc-runtimes"
121 else153 else
122 unreachable;154 return runner.fail("unsupported arg prefix: {q}", .{string});
123 continue;155 continue;
124 },156 },
125 .suffix => unreachable,157 .suffix => {
158 const end = std.mem.findScalarPos(u8, args_body, args_body_offset, 0).?;
159 const string = args_body[args_body_offset..end];
160 args_body_offset = end + 1;
161 return runner.fail("unsupported arg suffix: {q}", .{string});
162 },
126 .input_dir => {163 .input_dir => {
127 input_dir = @fromBackingInt(@backingInt(input_dir) + 1);164 input_dir = @fromBackingInt(@backingInt(input_dir) + 1);
128 continue :arg .output_dir;165 continue :arg .output_dir;
...@@ -137,16 +174,19 @@ pub fn runServer(runner: *Runner) ProtocolError {...@@ -137,16 +174,19 @@ pub fn runServer(runner: *Runner) ProtocolError {
137 dir_handle.*,174 dir_handle.*,
138 ) catch |err| switch (err) {175 ) catch |err| switch (err) {
139 error.Canceled => |e| return e,176 error.Canceled => |e| return e,
140 error.Unexpected => |e| return runner.fail(177 else => |e| return runner.fail(
141 "unable to inherit parent dir: {t}",178 "unable to inherit parent dir: {t}",
142 .{e},179 .{e},
143 ),180 ),
144 };181 };
145 switch (state) {182 switch (state) {
146 .positional => {183 .positional => {
147 assert(runner.args.@"test" == null);184 if (runner.args.@"test" != null or
185 runner.args.manifest_file != null) return runner.fail(
186 "{t} specified multiple times",
187 .{state},
188 );
148 runner.args.@"test" = .{ .input_dir = input_dir, .dir = dir };189 runner.args.@"test" = .{ .input_dir = input_dir, .dir = dir };
149 assert(runner.args.manifest_file == null);
150 const manifest_path = "manifest";190 const manifest_path = "manifest";
151 runner.args.manifest_file = dir.openFile(191 runner.args.manifest_file = dir.openFile(
152 runner.io,192 runner.io,
...@@ -161,16 +201,31 @@ pub fn runServer(runner: *Runner) ProtocolError {...@@ -161,16 +201,31 @@ pub fn runServer(runner: *Runner) ProtocolError {
161 };201 };
162 try runner.discoverInput(input_dir, manifest_path);202 try runner.discoverInput(input_dir, manifest_path);
163 },203 },
164 .zig => unreachable,204 .@"--lib" => {
165 .lib => {205 if (runner.args.lib_dir != null) return runner.fail(
166 assert(runner.args.lib_dir == null);206 "\"{t}\" specified multiple times",
207 .{state},
208 );
167 runner.args.lib_dir = dir;209 runner.args.lib_dir = dir;
168 },210 },
169 .src => {211 .@"--src" => {
170 assert(runner.args.src_dir == null);212 if (runner.args.src_dir != null) return runner.fail(
213 "\"{t}\" specified multiple times",
214 .{state},
215 );
171 runner.args.src_dir = dir;216 runner.args.src_dir = dir;
172 },217 },
173 .target => unreachable,218 .@"--libc-runtimes" => {
219 if (runner.args.libc_runtimes_dir != null) return runner.fail(
220 "\"{t}\" specified multiple times",
221 .{state},
222 );
223 runner.args.libc_runtimes_dir = dir;
224 },
225 else => return runner.fail(
226 "\"{t}\" expected {t}, got {t}",
227 .{ state, state_expected.get(state), arg },
228 ),
174 }229 }
175 },230 },
176 .input_file, .input_file_content, .output_file => {231 .input_file, .input_file_content, .output_file => {
...@@ -184,23 +239,31 @@ pub fn runServer(runner: *Runner) ProtocolError {...@@ -184,23 +239,31 @@ pub fn runServer(runner: *Runner) ProtocolError {
184 .{ .nonblocking = false },239 .{ .nonblocking = false },
185 ) catch |err| switch (err) {240 ) catch |err| switch (err) {
186 error.Canceled => |e| return e,241 error.Canceled => |e| return e,
187 error.Unexpected => |e| return runner.fail(242 else => |e| return runner.fail(
188 "unable to inherit parent file: {t}",243 "unable to inherit parent file: {t}",
189 .{e},244 .{e},
190 ),245 ),
191 };246 };
192 switch (state) {247 switch (state) {
193 .positional => {248 .positional => {
194 assert(runner.args.manifest_file == null);249 if (runner.args.@"test" != null or
250 runner.args.manifest_file != null) return runner.fail(
251 "{t} specified multiple times",
252 .{state},
253 );
195 runner.args.manifest_file = file;254 runner.args.manifest_file = file;
196 },255 },
197 .zig => {256 .@"--zig" => {
198 assert(runner.args.zig_exe == null);257 if (runner.args.zig_exe != null) return runner.fail(
258 "\"{t}\" specified multiple times",
259 .{state},
260 );
199 runner.args.zig_exe = file;261 runner.args.zig_exe = file;
200 },262 },
201 .lib => unreachable,263 else => return runner.fail(
202 .src => unreachable,264 "\"{t}\" expected {t}, got {t}",
203 .target => unreachable,265 .{ state, state_expected.get(state), arg },
266 ),
204 }267 }
205 },268 },
206 }269 }
...@@ -480,7 +543,6 @@ fn testOne(runner: *Runner, test_index: u32) TestError!void {...@@ -480,7 +543,6 @@ fn testOne(runner: *Runner, test_index: u32) TestError!void {
480 .target_query = target_query,543 .target_query = target_query,
481 .manifest_sr = .init(&manifest_fr.interface, runner.gpa, &runner.eb_wip, src_path_string: {544 .manifest_sr = .init(&manifest_fr.interface, runner.gpa, &runner.eb_wip, src_path_string: {
482 var path_buffer: [std.Io.Dir.max_path_bytes]u8 = undefined;545 var path_buffer: [std.Io.Dir.max_path_bytes]u8 = undefined;
483
484 const src_path = src_path: {546 const src_path = src_path: {
485 break :src_path path_buffer[0 .. manifest_file.realPath(547 break :src_path path_buffer[0 .. manifest_file.realPath(
486 runner.io,548 runner.io,
...@@ -1022,6 +1084,7 @@ const Compiler = struct {...@@ -1022,6 +1084,7 @@ const Compiler = struct {
1022 const gpa = runner.gpa;1084 const gpa = runner.gpa;
1023 const arena = runner.arena.allocator();1085 const arena = runner.arena.allocator();
1024 const io = runner.io;1086 const io = runner.io;
1087 const target = &comp.target.resolved;
1025 const config = &comp.config.?;1088 const config = &comp.config.?;
1026 const out_dir = ".zig-cache" ++ std.Io.Dir.path.sep_str ++1089 const out_dir = ".zig-cache" ++ std.Io.Dir.path.sep_str ++
1027 "o" ++ std.Io.Dir.path.sep_str ++ std.Build.Cache.binToHex(digest.*);1090 "o" ++ std.Io.Dir.path.sep_str ++ std.Build.Cache.binToHex(digest.*);
...@@ -1036,16 +1099,18 @@ const Compiler = struct {...@@ -1036,16 +1099,18 @@ const Compiler = struct {
1036 .stdout, .exit, .lldb => {},1099 .stdout, .exit, .lldb => {},
1037 }1100 }
10381101
1039 const executor = executor: switch (std.zig.system.getExternalExecutor(1102 var argv: std.ArrayList([]const u8) = .initBuffer(try arena.alloc([]const u8, 4));
1040 io,1103 var environ_map: std.process.Environ.Map = .init(gpa);
1041 &comp.target.resolved,1104 defer environ_map.deinit();
1042 .{1105 const need_cross_libc =
1043 .host_cpu_arch = runner.host.cpu.arch,1106 target.os.tag == .linux and config.flags.link_libc and config.flags.link_mode == .dynamic;
1044 .host_os_tag = runner.host.os.tag,1107 const use_executor = use_executor: switch (std.zig.system.getExternalExecutor(io, target, .{
1045 .link_mode = config.flags.link_mode,1108 .host_cpu_arch = runner.host.cpu.arch,
1046 .link_libc = config.flags.link_libc,1109 .host_os_tag = runner.host.os.tag,
1047 },1110 .qemu_fixes_dl = need_cross_libc and runner.args.libc_runtimes_dir != null,
1048 )) {1111 .link_mode = config.flags.link_mode,
1112 .link_libc = config.flags.link_libc,
1113 })) {
1049 .bad_dl, .bad_os_or_cpu => {1114 .bad_dl, .bad_os_or_cpu => {
1050 // This binary cannot be executed on this host.1115 // This binary cannot be executed on this host.
1051 if (!runner.args.quiet) std.log.warn("skipping execution because host {q} cannot " ++1116 if (!runner.args.quiet) std.log.warn("skipping execution because host {q} cannot " ++
...@@ -1054,24 +1119,57 @@ const Compiler = struct {...@@ -1054,24 +1119,57 @@ const Compiler = struct {
1054 });1119 });
1055 return;1120 return;
1056 },1121 },
1057 .native, .rosetta => null,1122 .native => false,
1058 .qemu => |executor| if (runner.args.enable_qemu)1123 .darling => |executor| if (runner.args.enable_darling) {
1059 executor1124 argv.appendAssumeCapacity(executor);
1060 else1125 break :use_executor true;
1061 continue :executor .bad_os_or_cpu,1126 } else continue :use_executor .bad_os_or_cpu,
1062 .wine => |executor| if (runner.args.enable_wine)1127 .qemu => |executor| if (runner.args.enable_qemu) {
1063 executor1128 argv.appendAssumeCapacity(executor);
1064 else1129 if (need_cross_libc) {
1065 continue :executor .bad_os_or_cpu,1130 const libc_runtimes_dir = runner.args.libc_runtimes_dir orelse
1066 .wasmtime => |executor| if (runner.args.enable_wasmtime)1131 continue :use_executor .bad_os_or_cpu;
1067 executor1132 var path_buffer: [std.Io.Dir.max_path_bytes]u8 = undefined;
1068 else1133 const libc_runtimes_path = path_buffer[0 .. libc_runtimes_dir.realPath(
1069 continue :executor .bad_os_or_cpu,1134 runner.io,
1070 .darling => |executor| if (runner.args.enable_darling)1135 &path_buffer,
1071 executor1136 ) catch |err| switch (err) {
1137 error.Canceled => |e| return e,
1138 else => |e| return runner.fail("unable to get libc runtimes path: {t}", .{e}),
1139 }];
1140 argv.appendSliceAssumeCapacity(&.{ "-L", try std.Io.Dir.path.join(arena, &.{
1141 libc_runtimes_path,
1142 try if (target.isGnuLibC()) std.zig.target.glibcRuntimeTriple(
1143 arena,
1144 target.cpu.arch,
1145 target.os.tag,
1146 target.abi,
1147 ) else if (target.isMuslLibC()) std.zig.target.muslRuntimeTriple(
1148 arena,
1149 target.cpu.arch,
1150 target.abi,
1151 ) else unreachable,
1152 }) });
1153 }
1154 break :use_executor true;
1155 } else continue :use_executor .bad_os_or_cpu,
1156 .rosetta => if (runner.args.enable_rosetta)
1157 true
1072 else1158 else
1073 continue :executor .bad_os_or_cpu,1159 continue :use_executor .bad_os_or_cpu,
1160 .wine => |executor| if (runner.args.enable_wine) {
1161 if (!environ_map.contains("WINEDEBUG")) try environ_map.put("WINEDEBUG", "-all");
1162 argv.appendAssumeCapacity(executor);
1163 break :use_executor true;
1164 } else continue :use_executor .bad_os_or_cpu,
1165 .wasmtime => |executor| if (runner.args.enable_wasmtime) {
1166 if (!environ_map.contains("WASMTIME_BACKTRACE_DETAILS"))
1167 try environ_map.put("WASMTIME_BACKTRACE_DETAILS", "1");
1168 argv.appendSliceAssumeCapacity(&.{ executor, "--dir=.", "-Sinherit-env" });
1169 break :use_executor true;
1170 } else continue :use_executor .bad_os_or_cpu,
1074 };1171 };
1172 argv.appendAssumeCapacity(bin_path);
10751173
1076 var name_buffer: [std.Progress.Node.max_name_len]u8 = undefined;1174 var name_buffer: [std.Progress.Node.max_name_len]u8 = undefined;
1077 const run_prog_node = runner.prog_node.start(std.mem.print(&name_buffer, "run {s}", .{1175 const run_prog_node = runner.prog_node.start(std.mem.print(&name_buffer, "run {s}", .{
...@@ -1088,11 +1186,12 @@ const Compiler = struct {...@@ -1088,11 +1186,12 @@ const Compiler = struct {
1088 .errors => unreachable,1186 .errors => unreachable,
1089 .stdout, .exit => {1187 .stdout, .exit => {
1090 const result = std.process.run(gpa, io, .{1188 const result = std.process.run(gpa, io, .{
1091 .exe = if (executor) |_| .search else .{ .file = bin_file },1189 .exe = if (use_executor) .search else .{ .file = bin_file },
1092 .argv = if (executor) |e| &.{ e, bin_path } else &.{bin_path},1190 .argv = argv.items,
1093 .cwd = .{ .dir = src_dir },1191 .cwd = .{ .dir = src_dir },
1192 .environ_map = &environ_map,
1094 .progress_node = run_prog_node,1193 .progress_node = run_prog_node,
1095 }) catch |err| if (executor) |_| {1194 }) catch |err| if (use_executor) {
1096 // Chances are the foreign executor isn't available. Skip this evaluation.1195 // Chances are the foreign executor isn't available. Skip this evaluation.
1097 if (!runner.args.quiet) std.log.warn(1196 if (!runner.args.quiet) std.log.warn(
1098 "skipping execution of {q} via executor for foreign target {q}: {t}",1197 "skipping execution of {q} via executor for foreign target {q}: {t}",
...@@ -1151,7 +1250,7 @@ const Compiler = struct {...@@ -1151,7 +1250,7 @@ const Compiler = struct {
1151 .{bin_path},1250 .{bin_path},
1152 ),1251 ),
1153 }1252 }
1154 if (executor == null and result.stderr.len > 0) {1253 if (!use_executor and result.stderr.len > 0) {
1155 std.log.err("generated executable {q} had unexpected stderr:\n{s}", .{1254 std.log.err("generated executable {q} had unexpected stderr:\n{s}", .{
1156 bin_path, result.stderr,1255 bin_path, result.stderr,
1157 });1256 });
...@@ -1257,10 +1356,12 @@ const ClientArgs = struct {...@@ -1257,10 +1356,12 @@ const ClientArgs = struct {
1257 src_dir: std.Io.Dir,1356 src_dir: std.Io.Dir,
1258 targets: std.ArrayList([]const u8),1357 targets: std.ArrayList([]const u8),
1259 keep_src: bool,1358 keep_src: bool,
1359 libc_runtimes_dir: ?std.Io.Dir,
1360 enable_darling: bool,
1260 enable_qemu: bool,1361 enable_qemu: bool,
1362 enable_rosetta: bool,
1261 enable_wine: bool,1363 enable_wine: bool,
1262 enable_wasmtime: bool,1364 enable_wasmtime: bool,
1263 enable_darling: bool,
1264 quiet: bool,1365 quiet: bool,
1265};1366};
1266pub fn main(init: std.process.Init) (std.mem.Allocator.Error || std.Io.Cancelable)!u8 {1367pub 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...@@ -1275,6 +1376,7 @@ pub fn main(init: std.process.Init) (std.mem.Allocator.Error || std.Io.Cancelabl
1275 var test_path_arg: ?[]const u8 = null;1376 var test_path_arg: ?[]const u8 = null;
1276 var zig_path_arg: ?[]const u8 = null;1377 var zig_path_arg: ?[]const u8 = null;
1277 var lib_path_arg: ?[]const u8 = null;1378 var lib_path_arg: ?[]const u8 = null;
1379 var libc_runtimes_path_arg: ?[]const u8 = null;
1278 var args: ClientArgs = .{1380 var args: ClientArgs = .{
1279 .test_file = undefined,1381 .test_file = undefined,
1280 .test_kind = undefined,1382 .test_kind = undefined,
...@@ -1283,10 +1385,12 @@ pub fn main(init: std.process.Init) (std.mem.Allocator.Error || std.Io.Cancelabl...@@ -1283,10 +1385,12 @@ pub fn main(init: std.process.Init) (std.mem.Allocator.Error || std.Io.Cancelabl
1283 .src_dir = undefined,1385 .src_dir = undefined,
1284 .targets = .empty,1386 .targets = .empty,
1285 .keep_src = false,1387 .keep_src = false,
1388 .libc_runtimes_dir = null,
1389 .enable_darling = false,
1286 .enable_qemu = false,1390 .enable_qemu = false,
1391 .enable_rosetta = false,
1287 .enable_wine = false,1392 .enable_wine = false,
1288 .enable_wasmtime = false,1393 .enable_wasmtime = false,
1289 .enable_darling = false,
1290 .quiet = false,1394 .quiet = false,
1291 };1395 };
1292 defer args.targets.deinit(init.gpa);1396 defer args.targets.deinit(init.gpa);
...@@ -1312,10 +1416,12 @@ pub fn main(init: std.process.Init) (std.mem.Allocator.Error || std.Io.Cancelabl...@@ -1312,10 +1416,12 @@ pub fn main(init: std.process.Init) (std.mem.Allocator.Error || std.Io.Cancelabl
1312 .src_dir = null,1416 .src_dir = null,
1313 .targets = .empty,1417 .targets = .empty,
1314 .target_bytes = .empty,1418 .target_bytes = .empty,
1419 .libc_runtimes_dir = null,
1420 .enable_darling = false,
1315 .enable_qemu = false,1421 .enable_qemu = false,
1316 .enable_wine = false,1422 .enable_rosetta = false,
1317 .enable_wasmtime = false,1423 .enable_wasmtime = false,
1318 .enable_darling = false,1424 .enable_wine = false,
1319 .quiet = false,1425 .quiet = false,
1320 },1426 },
1321 .host = std.zig.system.resolveTargetQuery(init.io, .{}) catch |err| switch (err) {1427 .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...@@ -1361,18 +1467,24 @@ pub fn main(init: std.process.Init) (std.mem.Allocator.Error || std.Io.Cancelabl
1361 try args.targets.append(init.gpa, try arena.dupe(u8, target));1467 try args.targets.append(init.gpa, try arena.dupe(u8, target));
1362 } else if (std.mem.eql(u8, arg, "--keep-src")) {1468 } else if (std.mem.eql(u8, arg, "--keep-src")) {
1363 args.keep_src = true;1469 args.keep_src = true;
1470 } else if (std.mem.eql(u8, arg, "--libc-runtimes")) {
1471 libc_runtimes_path_arg = arg_it.next() orelse fatal("missing arg after {q}", .{arg});
1472 } else if (std.mem.cutPrefix(u8, arg, "--libc-runtimes=")) |libc_runtimes_path| {
1473 libc_runtimes_path_arg = libc_runtimes_path;
1474 } else if (std.mem.eql(u8, arg, "-fdarling")) {
1475 args.enable_darling = true;
1364 } else if (std.mem.eql(u8, arg, "-fqemu")) {1476 } else if (std.mem.eql(u8, arg, "-fqemu")) {
1365 args.enable_qemu = true;1477 args.enable_qemu = true;
1478 } else if (std.mem.eql(u8, arg, "-frosetta")) {
1479 args.enable_rosetta = true;
1366 } else if (std.mem.eql(u8, arg, "-fwine")) {1480 } else if (std.mem.eql(u8, arg, "-fwine")) {
1367 args.enable_wine = true;1481 args.enable_wine = true;
1368 } else if (std.mem.eql(u8, arg, "-fwasmtime")) {1482 } else if (std.mem.eql(u8, arg, "-fwasmtime")) {
1369 args.enable_wasmtime = true;1483 args.enable_wasmtime = true;
1370 } else if (std.mem.eql(u8, arg, "-fdarling")) {
1371 args.enable_darling = true;
1372 } else if (std.mem.eql(u8, arg, "--quiet")) {1484 } else if (std.mem.eql(u8, arg, "--quiet")) {
1373 args.quiet = true;1485 args.quiet = true;
1374 } else {1486 } else {
1375 if (test_path_arg) |_| fatal("unknown arg {q}", .{arg});1487 if (test_path_arg) |_| fatal("unexpected arg {q}", .{arg});
1376 test_path_arg = arg;1488 test_path_arg = arg;
1377 }1489 }
1378 }1490 }
...@@ -1403,6 +1515,15 @@ pub fn main(init: std.process.Init) (std.mem.Allocator.Error || std.Io.Cancelabl...@@ -1403,6 +1515,15 @@ pub fn main(init: std.process.Init) (std.mem.Allocator.Error || std.Io.Cancelabl
1403 else => |e| fatal("unable to open {q}: {t}", .{ lib_path, e }),1515 else => |e| fatal("unable to open {q}: {t}", .{ lib_path, e }),
1404 };1516 };
1405 defer args.lib_dir.close(init.io);1517 defer args.lib_dir.close(init.io);
1518 if (libc_runtimes_path_arg) |libc_runtimes_path| args.libc_runtimes_dir = cwd.openDir(
1519 init.io,
1520 libc_runtimes_path,
1521 .{},
1522 ) catch |err| switch (err) {
1523 error.Canceled => |e| return e,
1524 else => |e| fatal("unable to open {q}: {t}", .{ lib_path, e }),
1525 };
1526 defer if (args.libc_runtimes_dir) |libc_runtimes_dir| libc_runtimes_dir.close(init.io);
14061527
1407 const src_dir_path = "src_" ++ std.fmt.hex(rand_int: {1528 const src_dir_path = "src_" ++ std.fmt.hex(rand_int: {
1408 var rand_int: u64 = undefined;1529 var rand_int: u64 = undefined;
...@@ -1479,21 +1600,18 @@ fn runClient(...@@ -1479,21 +1600,18 @@ fn runClient(
1479 try argv.append(gpa, @backingInt(Arg.prefix));1600 try argv.append(gpa, @backingInt(Arg.prefix));
1480 try argv.appendSlice(gpa, "--zig=");1601 try argv.appendSlice(gpa, "--zig=");
1481 try argv.append(gpa, 0);1602 try argv.append(gpa, 0);
1482
1483 try argv.append(gpa, @backingInt(Arg.input_file));1603 try argv.append(gpa, @backingInt(Arg.input_file));
1484 try argv.appendSlice(gpa, @ptrCast(&args.zig_exe.handle));1604 try argv.appendSlice(gpa, @ptrCast(&args.zig_exe.handle));
14851605
1486 try argv.append(gpa, @backingInt(Arg.prefix));1606 try argv.append(gpa, @backingInt(Arg.prefix));
1487 try argv.appendSlice(gpa, "--lib=");1607 try argv.appendSlice(gpa, "--lib=");
1488 try argv.append(gpa, 0);1608 try argv.append(gpa, 0);
1489
1490 try argv.append(gpa, @backingInt(Arg.input_dir));1609 try argv.append(gpa, @backingInt(Arg.input_dir));
1491 try argv.appendSlice(gpa, @ptrCast(&args.lib_dir.handle));1610 try argv.appendSlice(gpa, @ptrCast(&args.lib_dir.handle));
14921611
1493 try argv.append(gpa, @backingInt(Arg.prefix));1612 try argv.append(gpa, @backingInt(Arg.prefix));
1494 try argv.appendSlice(gpa, "--src=");1613 try argv.appendSlice(gpa, "--src=");
1495 try argv.append(gpa, 0);1614 try argv.append(gpa, 0);
1496
1497 try argv.append(gpa, @backingInt(Arg.output_dir));1615 try argv.append(gpa, @backingInt(Arg.output_dir));
1498 try argv.appendSlice(gpa, @ptrCast(&args.src_dir.handle));1616 try argv.appendSlice(gpa, @ptrCast(&args.src_dir.handle));
14991617
...@@ -1507,11 +1625,28 @@ fn runClient(...@@ -1507,11 +1625,28 @@ fn runClient(
1507 try argv.append(gpa, 0);1625 try argv.append(gpa, 0);
1508 }1626 }
15091627
1628 if (args.libc_runtimes_dir) |libc_runtimes_dir| {
1629 try argv.append(gpa, @backingInt(Arg.prefix));
1630 try argv.appendSlice(gpa, "--libc-runtimes=");
1631 try argv.append(gpa, 0);
1632 try argv.append(gpa, @backingInt(Arg.input_dir));
1633 try argv.appendSlice(gpa, @ptrCast(&libc_runtimes_dir.handle));
1634 }
1635 if (args.enable_darling) {
1636 try argv.append(gpa, @backingInt(Arg.string));
1637 try argv.appendSlice(gpa, "-fdarling");
1638 try argv.append(gpa, 0);
1639 }
1510 if (args.enable_qemu) {1640 if (args.enable_qemu) {
1511 try argv.append(gpa, @backingInt(Arg.string));1641 try argv.append(gpa, @backingInt(Arg.string));
1512 try argv.appendSlice(gpa, "-fqemu");1642 try argv.appendSlice(gpa, "-fqemu");
1513 try argv.append(gpa, 0);1643 try argv.append(gpa, 0);
1514 }1644 }
1645 if (args.enable_rosetta) {
1646 try argv.append(gpa, @backingInt(Arg.string));
1647 try argv.appendSlice(gpa, "-frosetta");
1648 try argv.append(gpa, 0);
1649 }
1515 if (args.enable_wine) {1650 if (args.enable_wine) {
1516 try argv.append(gpa, @backingInt(Arg.string));1651 try argv.append(gpa, @backingInt(Arg.string));
1517 try argv.appendSlice(gpa, "-fwine");1652 try argv.appendSlice(gpa, "-fwine");
...@@ -1522,11 +1657,6 @@ fn runClient(...@@ -1522,11 +1657,6 @@ fn runClient(
1522 try argv.appendSlice(gpa, "-fwasmtime");1657 try argv.appendSlice(gpa, "-fwasmtime");
1523 try argv.append(gpa, 0);1658 try argv.append(gpa, 0);
1524 }1659 }
1525 if (args.enable_darling) {
1526 try argv.append(gpa, @backingInt(Arg.string));
1527 try argv.appendSlice(gpa, "-fdarling");
1528 try argv.append(gpa, 0);
1529 }
15301660
1531 if (args.quiet) {1661 if (args.quiet) {
1532 try argv.append(gpa, @backingInt(Arg.string));1662 try argv.append(gpa, @backingInt(Arg.string));
test/tests.zig+1
...@@ -3411,6 +3411,7 @@ pub fn addIncrementalTests(...@@ -3411,6 +3411,7 @@ pub fn addIncrementalTests(
3411 run.addArgs(&.{ "--target", target_str });3411 run.addArgs(&.{ "--target", target_str });
3412 }3412 }
34133413
3414 run.addPrefixedDirectoryArg("--libc-runtimes=", .{ .relative = .{ .base = .libc_runtimes } });
3414 run.addThirdPartyEnabledArgDarling(.{ .enabled = "-fdarling" });3415 run.addThirdPartyEnabledArgDarling(.{ .enabled = "-fdarling" });
3415 run.addThirdPartyEnabledArgQemu(.{ .enabled = "-fqemu" });3416 run.addThirdPartyEnabledArgQemu(.{ .enabled = "-fqemu" });
3416 run.addThirdPartyEnabledArgRosetta(.{ .enabled = "-frosetta" });3417 run.addThirdPartyEnabledArgRosetta(.{ .enabled = "-frosetta" });