authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-31 16:02:44-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-04 00:27:08-08:00
log69d07472a12c8ec8f83a43ed63c1ab7e2ab71c14
tree2599e7a3ffecd39f14b8c72c0e51eb29a88fa286
parent3e6d6150d98658e6c46ad5c378f90fb628f97d2a

std lib tests passing on linux


8 files changed, 46 insertions(+), 55 deletions(-)

lib/std/Build/Step.zig+9-10
...@@ -448,7 +448,10 @@ pub fn evalZigProcess(...@@ -448,7 +448,10 @@ pub fn evalZigProcess(
448 try handleChildProcUnsupported(s);448 try handleChildProcUnsupported(s);
449 try handleVerbose(s.owner, null, argv);449 try handleVerbose(s.owner, null, argv);
450450
451 var child = std.process.spawn(io, .{451 const zp = try gpa.create(ZigProcess);
452 defer if (!watch) gpa.destroy(zp);
453
454 zp.child = std.process.spawn(io, .{
452 .argv = argv,455 .argv = argv,
453 .env_map = &b.graph.env_map,456 .env_map = &b.graph.env_map,
454 .stdin = .pipe,457 .stdin = .pipe,
...@@ -457,22 +460,18 @@ pub fn evalZigProcess(...@@ -457,22 +460,18 @@ pub fn evalZigProcess(
457 .request_resource_usage_statistics = true,460 .request_resource_usage_statistics = true,
458 .progress_node = prog_node,461 .progress_node = prog_node,
459 }) catch |err| return s.fail("failed to spawn zig compiler {s}: {t}", .{ argv[0], err });462 }) catch |err| return s.fail("failed to spawn zig compiler {s}: {t}", .{ argv[0], err });
460 defer if (!watch) child.kill(io);463 defer if (!watch) zp.child.kill(io);
461464
462 const zp = try gpa.create(ZigProcess);
463 zp.* = .{465 zp.* = .{
464 .child = child,466 .child = zp.child,
465 .poller = Io.poll(gpa, ZigProcess.StreamEnum, .{467 .poller = Io.poll(gpa, ZigProcess.StreamEnum, .{
466 .stdout = child.stdout.?,468 .stdout = zp.child.stdout.?,
467 .stderr = child.stderr.?,469 .stderr = zp.child.stderr.?,
468 }),470 }),
469 .progress_ipc_fd = if (std.Progress.have_ipc) prog_node.getIpcFd() else {},471 .progress_ipc_fd = if (std.Progress.have_ipc) prog_node.getIpcFd() else {},
470 };472 };
471 if (watch) s.setZigProcess(zp);473 if (watch) s.setZigProcess(zp);
472 defer if (!watch) {474 defer if (!watch) zp.poller.deinit();
473 zp.poller.deinit();
474 gpa.destroy(zp);
475 };
476475
477 const result = try zigProcessUpdate(s, zp, watch, web_server, gpa);476 const result = try zigProcessUpdate(s, zp, watch, web_server, gpa);
478477
lib/std/Io.zig-5
...@@ -2240,8 +2240,3 @@ pub fn tryLockStderr(io: Io, buffer: []u8, terminal_mode: ?Terminal.Mode) Cancel...@@ -2240,8 +2240,3 @@ pub fn tryLockStderr(io: Io, buffer: []u8, terminal_mode: ?Terminal.Mode) Cancel
2240pub fn unlockStderr(io: Io) void {2240pub fn unlockStderr(io: Io) void {
2241 return io.vtable.unlockStderr(io.userdata);2241 return io.vtable.unlockStderr(io.userdata);
2242}2242}
2243
2244pub fn environ(io: Io, name: []const u8) ?[]const u8 {
2245 _ = io;
2246 std.debug.panic("TODO: environ query: {s}", .{name});
2247}
lib/std/Io/Threaded.zig+20-30
...@@ -101,6 +101,9 @@ pub const Environ = struct {...@@ -101,6 +101,9 @@ pub const Environ = struct {
101 .windows, .wasi => struct {},101 .windows, .wasi => struct {},
102 else => struct {102 else => struct {
103 PATH: ?[:0]const u8 = null,103 PATH: ?[:0]const u8 = null,
104 DEBUGINFOD_CACHE_PATH: ?[:0]const u8 = null,
105 XDG_CACHE_HOME: ?[:0]const u8 = null,
106 HOME: ?[:0]const u8 = null,
104 },107 },
105 };108 };
106};109};
...@@ -12674,27 +12677,6 @@ fn scanEnviron(t: *Threaded) void {...@@ -12674,27 +12677,6 @@ fn scanEnviron(t: *Threaded) void {
12674 }12677 }
12675 comptime assert(@sizeOf(Environ.String) == 0);12678 comptime assert(@sizeOf(Environ.String) == 0);
12676 }12679 }
12677 } else if (builtin.link_libc) {
12678 var ptr = std.c.environ;
12679 while (ptr[0]) |line| : (ptr += 1) {
12680 var line_i: usize = 0;
12681 while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {}
12682 const key = line[0..line_i];
12683
12684 var end_i: usize = line_i;
12685 while (line[end_i] != 0) : (end_i += 1) {}
12686 const value = line[line_i + 1 .. end_i :0];
12687
12688 if (std.mem.eql(u8, key, "NO_COLOR")) {
12689 t.environ.exist.NO_COLOR = true;
12690 } else if (std.mem.eql(u8, key, "CLICOLOR_FORCE")) {
12691 t.environ.exist.CLICOLOR_FORCE = true;
12692 } else if (@hasField(Environ.String, "PATH") and std.mem.eql(u8, key, "PATH")) {
12693 t.environ.string.PATH = value;
12694 } else if (std.mem.eql(u8, key, "ZIG_PROGRESS")) {
12695 t.environ.zig_progress_handle = std.fmt.parseInt(u31, value, 10) catch error.UnrecognizedFormat;
12696 }
12697 }
12698 } else {12680 } else {
12699 for (t.environ.block) |opt_line| {12681 for (t.environ.block) |opt_line| {
12700 const line = opt_line.?;12682 const line = opt_line.?;
...@@ -12710,10 +12692,10 @@ fn scanEnviron(t: *Threaded) void {...@@ -12710,10 +12692,10 @@ fn scanEnviron(t: *Threaded) void {
12710 t.environ.exist.NO_COLOR = true;12692 t.environ.exist.NO_COLOR = true;
12711 } else if (std.mem.eql(u8, key, "CLICOLOR_FORCE")) {12693 } else if (std.mem.eql(u8, key, "CLICOLOR_FORCE")) {
12712 t.environ.exist.CLICOLOR_FORCE = true;12694 t.environ.exist.CLICOLOR_FORCE = true;
12713 } else if (@hasField(Environ.String, "PATH") and std.mem.eql(u8, key, "PATH")) {
12714 t.environ.string.PATH = value;
12715 } else if (std.mem.eql(u8, key, "ZIG_PROGRESS")) {12695 } else if (std.mem.eql(u8, key, "ZIG_PROGRESS")) {
12716 t.environ.zig_progress_handle = std.fmt.parseInt(u31, value, 10) catch error.UnrecognizedFormat;12696 t.environ.zig_progress_handle = std.fmt.parseInt(u31, value, 10) catch error.UnrecognizedFormat;
12697 } else inline for (@typeInfo(Environ.String).@"struct".fields) |field| {
12698 if (std.mem.eql(u8, key, field.name)) @field(t.environ.string, field.name) = value;
12717 }12699 }
12718 }12700 }
12719 }12701 }
...@@ -12966,12 +12948,10 @@ fn childKill(userdata: ?*anyopaque, child: *std.process.Child) void {...@@ -12966,12 +12948,10 @@ fn childKill(userdata: ?*anyopaque, child: *std.process.Child) void {
12966 if (is_windows) {12948 if (is_windows) {
12967 childKillWindows(t, child, 1) catch {12949 childKillWindows(t, child, 1) catch {
12968 childCleanupStreams(child);12950 childCleanupStreams(child);
12969 child.id = null;
12970 };12951 };
12971 } else {12952 } else {
12972 childKillPosix(t, child) catch {12953 childKillPosix(t, child) catch {
12973 childCleanupStreams(child);12954 childCleanupStreams(child);
12974 child.id = null;
12975 };12955 };
12976 }12956 }
12977}12957}
...@@ -13012,7 +12992,6 @@ fn childWaitWindows(t: *Threaded, child: *process.Child) process.Child.WaitError...@@ -13012,7 +12992,6 @@ fn childWaitWindows(t: *Threaded, child: *process.Child) process.Child.WaitError
13012 posix.close(child.id);12992 posix.close(child.id);
13013 posix.close(child.thread_handle);12993 posix.close(child.thread_handle);
13014 childCleanupStreams(child);12994 childCleanupStreams(child);
13015 child.id = null;
13016 return term;12995 return term;
13017}12996}
1301812997
...@@ -13028,10 +13007,8 @@ fn childWaitPosix(t: *Threaded, child: *process.Child) process.Child.WaitError!p...@@ -13028,10 +13007,8 @@ fn childWaitPosix(t: *Threaded, child: *process.Child) process.Child.WaitError!p
13028 }13007 }
13029 break :res posix.waitpid(pid, 0);13008 break :res posix.waitpid(pid, 0);
13030 };13009 };
13031 const status = res.status;
13032 childCleanupStreams(child);13010 childCleanupStreams(child);
13033 child.id = null;13011 return statusToTerm(res.status);
13034 return statusToTerm(status);
13035}13012}
1303613013
13037fn statusToTerm(status: u32) process.Child.Term {13014fn statusToTerm(status: u32) process.Child.Term {
...@@ -13046,7 +13023,14 @@ fn statusToTerm(status: u32) process.Child.Term {...@@ -13046,7 +13023,14 @@ fn statusToTerm(status: u32) process.Child.Term {
13046}13023}
1304713024
13048fn childKillPosix(t: *Threaded, child: *process.Child) !void {13025fn childKillPosix(t: *Threaded, child: *process.Child) !void {
13049 try posix.kill(child.id.?, posix.SIG.TERM);13026 while (true) switch (posix.errno(posix.system.kill(child.id.?, .TERM))) {
13027 .SUCCESS => break,
13028 .INTR => continue,
13029 .PERM => return error.PermissionDenied,
13030 .INVAL => |err| return errnoBug(err),
13031 .SRCH => |err| return errnoBug(err),
13032 else => |err| return posix.unexpectedErrno(err),
13033 };
13050 _ = try childWaitPosix(t, child);13034 _ = try childWaitPosix(t, child);
13051}13035}
1305213036
...@@ -13063,6 +13047,7 @@ fn childCleanupStreams(child: *process.Child) void {...@@ -13063,6 +13047,7 @@ fn childCleanupStreams(child: *process.Child) void {
13063 posix.close(stderr.handle);13047 posix.close(stderr.handle);
13064 child.stderr = null;13048 child.stderr = null;
13065 }13049 }
13050 child.id = null;
13066}13051}
1306713052
13068/// Errors that can occur between fork() and execv()13053/// Errors that can occur between fork() and execv()
...@@ -14367,6 +14352,11 @@ fn progressParentFile(userdata: ?*anyopaque) std.Progress.ParentFileError!File {...@@ -14367,6 +14352,11 @@ fn progressParentFile(userdata: ?*anyopaque) std.Progress.ParentFileError!File {
14367 } };14352 } };
14368}14353}
1436914354
14355pub fn environString(t: *Threaded, comptime name: []const u8) ?[:0]const u8 {
14356 t.scanEnviron();
14357 return @field(t.environ.string, name);
14358}
14359
14370test {14360test {
14371 _ = @import("Threaded/test.zig");14361 _ = @import("Threaded/test.zig");
14372}14362}
lib/std/debug/ElfFile.zig+7-5
...@@ -66,16 +66,17 @@ pub const DebugInfoSearchPaths = struct {...@@ -66,16 +66,17 @@ pub const DebugInfoSearchPaths = struct {
66 .exe_dir = null,66 .exe_dir = null,
67 };67 };
6868
69 pub fn native(exe_path: []const u8, io: Io) DebugInfoSearchPaths {69 pub fn native(exe_path: []const u8) DebugInfoSearchPaths {
70 return .{70 if (std.options.elf_debug_info_search_paths) |f| return f(exe_path);
71 if (std.Options.debug_threaded_io) |t| return .{
71 .debuginfod_client = p: {72 .debuginfod_client = p: {
72 if (io.environ("DEBUGINFOD_CACHE_PATH")) |p| {73 if (t.environString("DEBUGINFOD_CACHE_PATH")) |p| {
73 break :p .{ p, "" };74 break :p .{ p, "" };
74 }75 }
75 if (io.environ("XDG_CACHE_HOME")) |cache_path| {76 if (t.environString("XDG_CACHE_HOME")) |cache_path| {
76 break :p .{ cache_path, "/debuginfod_client" };77 break :p .{ cache_path, "/debuginfod_client" };
77 }78 }
78 if (io.environ("HOME")) |home_path| {79 if (t.environString("HOME")) |home_path| {
79 break :p .{ home_path, "/.cache/debuginfod_client" };80 break :p .{ home_path, "/.cache/debuginfod_client" };
80 }81 }
81 break :p null;82 break :p null;
...@@ -85,6 +86,7 @@ pub const DebugInfoSearchPaths = struct {...@@ -85,6 +86,7 @@ pub const DebugInfoSearchPaths = struct {
85 },86 },
86 .exe_dir = std.fs.path.dirname(exe_path) orelse ".",87 .exe_dir = std.fs.path.dirname(exe_path) orelse ".",
87 };88 };
89 @compileError("std.Options.elf_debug_info_search_paths must be provided");
88 }90 }
89};91};
9092
lib/std/debug/SelfInfo/Elf.zig+2-2
...@@ -327,7 +327,7 @@ const Module = struct {...@@ -327,7 +327,7 @@ const Module = struct {
327 const load_result = if (mod.name.len > 0) res: {327 const load_result = if (mod.name.len > 0) res: {
328 var file = Io.Dir.cwd().openFile(io, mod.name, .{}) catch return error.MissingDebugInfo;328 var file = Io.Dir.cwd().openFile(io, mod.name, .{}) catch return error.MissingDebugInfo;
329 defer file.close(io);329 defer file.close(io);
330 break :res std.debug.ElfFile.load(gpa, io, file, mod.build_id, &.native(mod.name, io));330 break :res std.debug.ElfFile.load(gpa, io, file, mod.build_id, &.native(mod.name));
331 } else res: {331 } else res: {
332 const path = std.process.executablePathAlloc(io, gpa) catch |err| switch (err) {332 const path = std.process.executablePathAlloc(io, gpa) catch |err| switch (err) {
333 error.OutOfMemory => |e| return e,333 error.OutOfMemory => |e| return e,
...@@ -336,7 +336,7 @@ const Module = struct {...@@ -336,7 +336,7 @@ const Module = struct {
336 defer gpa.free(path);336 defer gpa.free(path);
337 var file = Io.Dir.cwd().openFile(io, path, .{}) catch return error.MissingDebugInfo;337 var file = Io.Dir.cwd().openFile(io, path, .{}) catch return error.MissingDebugInfo;
338 defer file.close(io);338 defer file.close(io);
339 break :res std.debug.ElfFile.load(gpa, io, file, mod.build_id, &.native(path, io));339 break :res std.debug.ElfFile.load(gpa, io, file, mod.build_id, &.native(path));
340 };340 };
341341
342 var elf_file = load_result catch |err| switch (err) {342 var elf_file = load_result catch |err| switch (err) {
lib/std/process/Child.zig+1-1
...@@ -106,7 +106,7 @@ pub const Term = union(enum) {...@@ -106,7 +106,7 @@ pub const Term = union(enum) {
106///106///
107/// Uncancelable. Ignores unexpected errors from the operating system.107/// Uncancelable. Ignores unexpected errors from the operating system.
108pub fn kill(child: *Child, io: Io) void {108pub fn kill(child: *Child, io: Io) void {
109 if (child.id != null) {109 if (child.id == null) {
110 assert(child.stdin == null);110 assert(child.stdin == null);
111 assert(child.stdout == null);111 assert(child.stdout == null);
112 assert(child.stderr == null);112 assert(child.stderr == null);
lib/std/process/Environ.zig+2-2
...@@ -792,6 +792,6 @@ test "convert from Environ to Map and back again" {...@@ -792,6 +792,6 @@ test "convert from Environ to Map and back again" {
792 var map2 = try environ.createMap(gpa);792 var map2 = try environ.createMap(gpa);
793 defer map2.deinit();793 defer map2.deinit();
794794
795 try testing.expectEqualSlices([]const u8, map.keys(), map2.keys());795 try testing.expectEqualDeep(map.keys(), map2.keys());
796 try testing.expectEqualSlices([]const u8, map.values(), map2.values());796 try testing.expectEqualDeep(map.values(), map2.values());
797}797}
lib/std/std.zig+5
...@@ -173,6 +173,11 @@ pub const Options = struct {...@@ -173,6 +173,11 @@ pub const Options = struct {
173 /// stack traces will just print an error to the relevant `Io.Writer` and return.173 /// stack traces will just print an error to the relevant `Io.Writer` and return.
174 allow_stack_tracing: bool = !@import("builtin").strip_debug_info,174 allow_stack_tracing: bool = !@import("builtin").strip_debug_info,
175175
176 elf_debug_info_search_paths: ?fn (exe_path: []const u8) switch (@import("builtin").object_format) {
177 .elf => debug.ElfFile.DebugInfoSearchPaths,
178 else => void,
179 } = null,
180
176 pub const debug_threaded_io: ?*Io.Threaded = if (@hasDecl(root, "std_options_debug_threaded_io"))181 pub const debug_threaded_io: ?*Io.Threaded = if (@hasDecl(root, "std_options_debug_threaded_io"))
177 root.std_options_debug_threaded_io182 root.std_options_debug_threaded_io
178 else183 else