Progress: fix compile errors on windows

Works for `zig build-exe`, IPC still not implemented yet.
This commit is contained in:
Jacob Young 2024-05-26 07:07:44 -04:00 committed by Andrew Kelley
parent d403d8cb7a
commit d77f5e7aaa
5 changed files with 96 additions and 51 deletions

View file

@ -86,12 +86,20 @@ pub const Node = struct {
name: [max_name_len]u8, name: [max_name_len]u8,
fn getIpcFd(s: Storage) ?posix.fd_t { fn getIpcFd(s: Storage) ?posix.fd_t {
return if (s.estimated_total_count != std.math.maxInt(u32)) null else @bitCast(s.completed_count); return if (s.estimated_total_count == std.math.maxInt(u32)) switch (@typeInfo(posix.fd_t)) {
.Int => @bitCast(s.completed_count),
.Pointer => @ptrFromInt(s.completed_count),
else => @compileError("unsupported fd_t of " ++ @typeName(posix.fd_t)),
} else null;
} }
fn setIpcFd(s: *Storage, fd: posix.fd_t) void { fn setIpcFd(s: *Storage, fd: posix.fd_t) void {
s.estimated_total_count = std.math.maxInt(u32); s.estimated_total_count = std.math.maxInt(u32);
s.completed_count = @bitCast(fd); s.completed_count = switch (@typeInfo(posix.fd_t)) {
.Int => @bitCast(fd),
.Pointer => @intFromPtr(fd),
else => @compileError("unsupported fd_t of " ++ @typeName(posix.fd_t)),
};
} }
comptime { comptime {
@ -316,12 +324,16 @@ pub fn start(options: Options) Node {
global_progress.initial_delay_ns = options.initial_delay_ns; global_progress.initial_delay_ns = options.initial_delay_ns;
if (std.process.parseEnvVarInt("ZIG_PROGRESS", u31, 10)) |ipc_fd| { if (std.process.parseEnvVarInt("ZIG_PROGRESS", u31, 10)) |ipc_fd| {
if (std.Thread.spawn(.{}, ipcThreadRun, .{ipc_fd})) |thread| { global_progress.update_thread = std.Thread.spawn(.{}, ipcThreadRun, .{
global_progress.update_thread = thread; @as(posix.fd_t, switch (@typeInfo(posix.fd_t)) {
} else |err| { .Int => ipc_fd,
.Pointer => @ptrFromInt(ipc_fd),
else => @compileError("unsupported fd_t of " ++ @typeName(posix.fd_t)),
}),
}) catch |err| {
std.log.warn("failed to spawn IPC thread for communicating progress to parent: {s}", .{@errorName(err)}); std.log.warn("failed to spawn IPC thread for communicating progress to parent: {s}", .{@errorName(err)});
return .{ .index = .none }; return .{ .index = .none };
} };
} else |env_err| switch (env_err) { } else |env_err| switch (env_err) {
error.EnvironmentVariableNotFound => { error.EnvironmentVariableNotFound => {
if (options.disable_printing) { if (options.disable_printing) {
@ -572,6 +584,20 @@ const SavedMetadata = struct {
main_index: u16, main_index: u16,
start_index: u16, start_index: u16,
nodes_len: u16, nodes_len: u16,
fn getIpcFd(metadata: SavedMetadata) posix.fd_t {
return if (builtin.os.tag == .windows)
@ptrFromInt(@as(usize, metadata.ipc_fd) << 2)
else
metadata.ipc_fd;
}
fn setIpcFd(fd: posix.fd_t) u16 {
return @intCast(if (builtin.os.tag == .windows)
@shrExact(@intFromPtr(fd), 2)
else
fd);
}
}; };
fn serializeIpc(start_serialized_len: usize) usize { fn serializeIpc(start_serialized_len: usize) usize {
@ -638,7 +664,7 @@ fn serializeIpc(start_serialized_len: usize) usize {
// Remember in case the pipe is empty on next update. // Remember in case the pipe is empty on next update.
ipc_metadata[ipc_metadata_len] = .{ ipc_metadata[ipc_metadata_len] = .{
.ipc_fd = @intCast(fd), .ipc_fd = SavedMetadata.setIpcFd(fd),
.start_index = @intCast(serialized_len), .start_index = @intCast(serialized_len),
.nodes_len = @intCast(parents.len), .nodes_len = @intCast(parents.len),
.main_index = @intCast(main_index), .main_index = @intCast(main_index),
@ -687,7 +713,7 @@ fn copyRoot(dest: *Node.Storage, src: *align(2) Node.Storage) void {
fn findOld(ipc_fd: posix.fd_t, old_metadata: []const SavedMetadata) ?*const SavedMetadata { fn findOld(ipc_fd: posix.fd_t, old_metadata: []const SavedMetadata) ?*const SavedMetadata {
for (old_metadata) |*m| { for (old_metadata) |*m| {
if (m.ipc_fd == ipc_fd) if (m.getIpcFd() == ipc_fd)
return m; return m;
} }
return null; return null;
@ -711,7 +737,7 @@ fn useSavedIpcData(
const old_main_index = saved_metadata.main_index; const old_main_index = saved_metadata.main_index;
ipc_metadata[ipc_metadata_len] = .{ ipc_metadata[ipc_metadata_len] = .{
.ipc_fd = @intCast(ipc_fd), .ipc_fd = SavedMetadata.setIpcFd(ipc_fd),
.start_index = @intCast(start_serialized_len), .start_index = @intCast(start_serialized_len),
.nodes_len = nodes_len, .nodes_len = nodes_len,
.main_index = @intCast(main_index), .main_index = @intCast(main_index),
@ -911,21 +937,32 @@ fn writeIpc(fd: posix.fd_t, serialized: Serialized) error{BrokenPipe}!void {
fn maybeUpdateSize(resize_flag: bool) void { fn maybeUpdateSize(resize_flag: bool) void {
if (!resize_flag) return; if (!resize_flag) return;
var winsize: posix.winsize = .{
.ws_row = 0,
.ws_col = 0,
.ws_xpixel = 0,
.ws_ypixel = 0,
};
const fd = (global_progress.terminal orelse return).handle; const fd = (global_progress.terminal orelse return).handle;
const err = posix.system.ioctl(fd, posix.T.IOCGWINSZ, @intFromPtr(&winsize)); if (builtin.os.tag == .windows) {
if (posix.errno(err) == .SUCCESS) { var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
global_progress.rows = winsize.ws_row;
global_progress.cols = winsize.ws_col; if (windows.kernel32.GetConsoleScreenBufferInfo(fd, &info) == windows.FALSE) {
@panic("TODO: handle this failure");
}
global_progress.rows = @intCast(info.dwSize.Y);
global_progress.cols = @intCast(info.dwSize.X);
} else { } else {
@panic("TODO: handle this failure"); var winsize: posix.winsize = .{
.ws_row = 0,
.ws_col = 0,
.ws_xpixel = 0,
.ws_ypixel = 0,
};
const err = posix.system.ioctl(fd, posix.T.IOCGWINSZ, @intFromPtr(&winsize));
if (posix.errno(err) == .SUCCESS) {
global_progress.rows = winsize.ws_row;
global_progress.cols = winsize.ws_col;
} else {
@panic("TODO: handle this failure");
}
} }
} }

View file

@ -9,7 +9,7 @@ const assert = std.debug.assert;
const mem = std.mem; const mem = std.mem;
const unicode = std.unicode; const unicode = std.unicode;
const meta = std.meta; const meta = std.meta;
const lossyCast = std.math.lossyCast; const lossyCast = math.lossyCast;
const expectFmt = std.testing.expectFmt; const expectFmt = std.testing.expectFmt;
pub const default_max_depth = 3; pub const default_max_depth = 3;
@ -1494,10 +1494,20 @@ pub fn Formatter(comptime format_fn: anytype) type {
/// Ignores '_' character in `buf`. /// Ignores '_' character in `buf`.
/// See also `parseUnsigned`. /// See also `parseUnsigned`.
pub fn parseInt(comptime T: type, buf: []const u8, base: u8) ParseIntError!T { pub fn parseInt(comptime T: type, buf: []const u8, base: u8) ParseIntError!T {
return parseIntWithGenericCharacter(T, u8, buf, base);
}
/// Like `parseInt`, but with a generic `Character` type.
pub fn parseIntWithGenericCharacter(
comptime Result: type,
comptime Character: type,
buf: []const Character,
base: u8,
) ParseIntError!Result {
if (buf.len == 0) return error.InvalidCharacter; if (buf.len == 0) return error.InvalidCharacter;
if (buf[0] == '+') return parseWithSign(T, buf[1..], base, .pos); if (buf[0] == '+') return parseIntWithSign(Result, Character, buf[1..], base, .pos);
if (buf[0] == '-') return parseWithSign(T, buf[1..], base, .neg); if (buf[0] == '-') return parseIntWithSign(Result, Character, buf[1..], base, .neg);
return parseWithSign(T, buf, base, .pos); return parseIntWithSign(Result, Character, buf, base, .pos);
} }
test parseInt { test parseInt {
@ -1560,12 +1570,13 @@ test parseInt {
try std.testing.expectEqual(@as(i5, -16), try std.fmt.parseInt(i5, "-10", 16)); try std.testing.expectEqual(@as(i5, -16), try std.fmt.parseInt(i5, "-10", 16));
} }
fn parseWithSign( fn parseIntWithSign(
comptime T: type, comptime Result: type,
buf: []const u8, comptime Character: type,
buf: []const Character,
base: u8, base: u8,
comptime sign: enum { pos, neg }, comptime sign: enum { pos, neg },
) ParseIntError!T { ) ParseIntError!Result {
if (buf.len == 0) return error.InvalidCharacter; if (buf.len == 0) return error.InvalidCharacter;
var buf_base = base; var buf_base = base;
@ -1575,7 +1586,7 @@ fn parseWithSign(
buf_base = 10; buf_base = 10;
// Detect the base by looking at buf prefix. // Detect the base by looking at buf prefix.
if (buf.len > 2 and buf[0] == '0') { if (buf.len > 2 and buf[0] == '0') {
switch (std.ascii.toLower(buf[1])) { if (math.cast(u8, buf[1])) |c| switch (std.ascii.toLower(c)) {
'b' => { 'b' => {
buf_base = 2; buf_base = 2;
buf_start = buf[2..]; buf_start = buf[2..];
@ -1589,7 +1600,7 @@ fn parseWithSign(
buf_start = buf[2..]; buf_start = buf[2..];
}, },
else => {}, else => {},
} };
} }
} }
@ -1598,33 +1609,33 @@ fn parseWithSign(
.neg => math.sub, .neg => math.sub,
}; };
// accumulate into U which is always 8 bits or larger. this prevents // accumulate into Accumulate which is always 8 bits or larger. this prevents
// `buf_base` from overflowing T. // `buf_base` from overflowing Result.
const info = @typeInfo(T); const info = @typeInfo(Result);
const U = std.meta.Int(info.Int.signedness, @max(8, info.Int.bits)); const Accumulate = std.meta.Int(info.Int.signedness, @max(8, info.Int.bits));
var x: U = 0; var accumulate: Accumulate = 0;
if (buf_start[0] == '_' or buf_start[buf_start.len - 1] == '_') return error.InvalidCharacter; if (buf_start[0] == '_' or buf_start[buf_start.len - 1] == '_') return error.InvalidCharacter;
for (buf_start) |c| { for (buf_start) |c| {
if (c == '_') continue; if (c == '_') continue;
const digit = try charToDigit(c, buf_base); const digit = try charToDigit(math.cast(u8, c) orelse return error.InvalidCharacter, buf_base);
if (x != 0) { if (accumulate != 0) {
x = try math.mul(U, x, math.cast(U, buf_base) orelse return error.Overflow); accumulate = try math.mul(Accumulate, accumulate, math.cast(Accumulate, buf_base) orelse return error.Overflow);
} else if (sign == .neg) { } else if (sign == .neg) {
// The first digit of a negative number. // The first digit of a negative number.
// Consider parsing "-4" as an i3. // Consider parsing "-4" as an i3.
// This should work, but positive 4 overflows i3, so we can't cast the digit to T and subtract. // This should work, but positive 4 overflows i3, so we can't cast the digit to T and subtract.
x = math.cast(U, -@as(i8, @intCast(digit))) orelse return error.Overflow; accumulate = math.cast(Accumulate, -@as(i8, @intCast(digit))) orelse return error.Overflow;
continue; continue;
} }
x = try add(U, x, math.cast(U, digit) orelse return error.Overflow); accumulate = try add(Accumulate, accumulate, math.cast(Accumulate, digit) orelse return error.Overflow);
} }
return if (T == U) return if (Result == Accumulate)
x accumulate
else else
math.cast(T, x) orelse return error.Overflow; math.cast(Result, accumulate) orelse return error.Overflow;
} }
/// Parses the string `buf` as unsigned representation in the specified base /// Parses the string `buf` as unsigned representation in the specified base
@ -1639,7 +1650,7 @@ fn parseWithSign(
/// Ignores '_' character in `buf`. /// Ignores '_' character in `buf`.
/// See also `parseInt`. /// See also `parseInt`.
pub fn parseUnsigned(comptime T: type, buf: []const u8, base: u8) ParseIntError!T { pub fn parseUnsigned(comptime T: type, buf: []const u8, base: u8) ParseIntError!T {
return parseWithSign(T, buf, base, .pos); return parseIntWithSign(T, u8, buf, base, .pos);
} }
test parseUnsigned { test parseUnsigned {

View file

@ -24,7 +24,7 @@ pub fn detectConfig(file: File) Config {
if (native_os == .windows and file.isTty()) { if (native_os == .windows and file.isTty()) {
var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined; var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != windows.TRUE) { if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) == windows.FALSE) {
return if (force_color == true) .escape_codes else .no_color; return if (force_color == true) .escape_codes else .no_color;
} }
return .{ .windows_api = .{ return .{ .windows_api = .{

View file

@ -442,10 +442,7 @@ pub fn parseEnvVarInt(comptime key: []const u8, comptime I: type, base: u8) Pars
if (native_os == .windows) { if (native_os == .windows) {
const key_w = comptime std.unicode.utf8ToUtf16LeStringLiteral(key); const key_w = comptime std.unicode.utf8ToUtf16LeStringLiteral(key);
const text = getenvW(key_w) orelse return error.EnvironmentVariableNotFound; const text = getenvW(key_w) orelse return error.EnvironmentVariableNotFound;
// For this implementation perhaps std.fmt.parseInt can be expanded to be generic across return std.fmt.parseIntWithGenericCharacter(I, u16, text, base);
// []u8 and []u16 like how many std.mem functions work.
_ = text;
@compileError("TODO implement this");
} else if (native_os == .wasi and !builtin.link_libc) { } else if (native_os == .wasi and !builtin.link_libc) {
@compileError("parseEnvVarInt is not supported for WASI without libc"); @compileError("parseEnvVarInt is not supported for WASI without libc");
} else { } else {

View file

@ -4504,7 +4504,7 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
log.debug("finish func name '{}'", .{(decl.fullyQualifiedName(mod) catch break :blk).fmt(ip)}); log.debug("finish func name '{}'", .{(decl.fullyQualifiedName(mod) catch break :blk).fmt(ip)});
} }
const decl_prog_node = mod.sema_prog_ndoe.start((try decl.fullyQualifiedName(mod)).toSlice(ip), 0); const decl_prog_node = mod.sema_prog_node.start((try decl.fullyQualifiedName(mod)).toSlice(ip), 0);
defer decl_prog_node.end(); defer decl_prog_node.end();
mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .func = func_index })); mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .func = func_index }));