Merge pull request #20059 from ziglang/progress

rework std.Progress
This commit is contained in:
Andrew Kelley 2024-05-28 19:27:14 -04:00 committed by GitHub
commit 963ffe9d57
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
62 changed files with 1790 additions and 851 deletions

View File

@ -528,7 +528,7 @@ const MsgWriter = struct {
config: std.io.tty.Config,
fn init(config: std.io.tty.Config) MsgWriter {
std.debug.getStderrMutex().lock();
std.debug.lockStdErr();
return .{
.w = std.io.bufferedWriter(std.io.getStdErr().writer()),
.config = config,
@ -537,7 +537,7 @@ const MsgWriter = struct {
pub fn deinit(m: *MsgWriter) void {
m.w.flush() catch {};
std.debug.getStderrMutex().unlock();
std.debug.unlockStdErr();
}
pub fn print(m: *MsgWriter, comptime fmt: []const u8, args: anytype) void {

View File

@ -289,13 +289,14 @@ pub fn main() !void {
.windows_api => {},
}
var progress: std.Progress = .{ .dont_print_on_dumb = true };
const main_progress_node = progress.start("", 0);
const main_progress_node = std.Progress.start(.{
.disable_printing = (color == .off),
});
builder.debug_log_scopes = debug_log_scopes.items;
builder.resolveInstallPrefix(install_prefix, dir_list);
{
var prog_node = main_progress_node.start("user build.zig logic", 0);
var prog_node = main_progress_node.start("Configure", 0);
defer prog_node.end();
try builder.runBuild(root);
}
@ -385,7 +386,7 @@ fn runStepNames(
arena: std.mem.Allocator,
b: *std.Build,
step_names: []const []const u8,
parent_prog_node: *std.Progress.Node,
parent_prog_node: std.Progress.Node,
thread_pool_options: std.Thread.Pool.Options,
run: *Run,
seed: u32,
@ -452,7 +453,7 @@ fn runStepNames(
{
defer parent_prog_node.end();
var step_prog = parent_prog_node.start("steps", step_stack.count());
const step_prog = parent_prog_node.start("steps", step_stack.count());
defer step_prog.end();
var wait_group: std.Thread.WaitGroup = .{};
@ -467,7 +468,7 @@ fn runStepNames(
if (step.state == .skipped_oom) continue;
thread_pool.spawnWg(&wait_group, workerMakeOneStep, .{
&wait_group, &thread_pool, b, step, &step_prog, run,
&wait_group, &thread_pool, b, step, step_prog, run,
});
}
}
@ -891,7 +892,7 @@ fn workerMakeOneStep(
thread_pool: *std.Thread.Pool,
b: *std.Build,
s: *Step,
prog_node: *std.Progress.Node,
prog_node: std.Progress.Node,
run: *Run,
) void {
// First, check the conditions for running this step. If they are not met,
@ -941,11 +942,10 @@ fn workerMakeOneStep(
}
}
var sub_prog_node = prog_node.start(s.name, 0);
sub_prog_node.activate();
const sub_prog_node = prog_node.start(s.name, 0);
defer sub_prog_node.end();
const make_result = s.make(&sub_prog_node);
const make_result = s.make(sub_prog_node);
// No matter the result, we want to display error/warning messages.
const show_compile_errors = !run.prominent_compile_errors and
@ -954,8 +954,8 @@ fn workerMakeOneStep(
const show_stderr = s.result_stderr.len > 0;
if (show_error_msgs or show_compile_errors or show_stderr) {
sub_prog_node.context.lock_stderr();
defer sub_prog_node.context.unlock_stderr();
std.debug.lockStdErr();
defer std.debug.unlockStdErr();
printErrorMessages(b, s, run) catch {};
}
@ -1225,7 +1225,7 @@ fn cleanExit() void {
process.exit(0);
}
const Color = enum { auto, off, on };
const Color = std.zig.Color;
const Summary = enum { all, new, failures, none };
fn get_tty_conf(color: Color, stderr: File) std.io.tty.Config {

View File

@ -108,8 +108,8 @@ pub const Diagnostics = struct {
}
pub fn renderToStdErr(self: *Diagnostics, args: []const []const u8, config: std.io.tty.Config) void {
std.debug.getStderrMutex().lock();
defer std.debug.getStderrMutex().unlock();
std.debug.lockStdErr();
defer std.debug.unlockStdErr();
const stderr = std.io.getStdErr().writer();
self.renderToWriter(args, stderr, config) catch return;
}

View File

@ -60,8 +60,8 @@ pub const Diagnostics = struct {
}
pub fn renderToStdErr(self: *Diagnostics, cwd: std.fs.Dir, source: []const u8, tty_config: std.io.tty.Config, source_mappings: ?SourceMappings) void {
std.debug.getStderrMutex().lock();
defer std.debug.getStderrMutex().unlock();
std.debug.lockStdErr();
defer std.debug.unlockStdErr();
const stderr = std.io.getStdErr().writer();
for (self.errors.items) |err_details| {
renderErrorMessage(self.allocator, stderr, tty_config, cwd, err_details, source, self.strings.items, source_mappings) catch return;

View File

@ -50,12 +50,6 @@ pub fn main() !void {
},
};
if (zig_integration) {
// Send progress with a special string to indicate that the building of the
// resinator binary is finished and we've moved on to actually compiling the .rc file
try error_handler.server.serveStringMessage(.progress, "<resinator>");
}
var options = options: {
var cli_diagnostics = cli.Diagnostics.init(allocator);
defer cli_diagnostics.deinit();

View File

@ -129,12 +129,11 @@ fn mainTerminal() void {
var ok_count: usize = 0;
var skip_count: usize = 0;
var fail_count: usize = 0;
var progress = std.Progress{
.dont_print_on_dumb = true,
};
const root_node = progress.start("Test", test_fn_list.len);
const have_tty = progress.terminal != null and
(progress.supports_ansi_escape_codes or progress.is_windows_terminal);
const root_node = std.Progress.start(.{
.root_name = "Test",
.estimated_total_items = test_fn_list.len,
});
const have_tty = std.io.getStdErr().isTty();
var async_frame_buffer: []align(builtin.target.stackAlignment()) u8 = undefined;
// TODO this is on the next line (using `undefined` above) because otherwise zig incorrectly
@ -151,11 +150,9 @@ fn mainTerminal() void {
}
std.testing.log_level = .warn;
var test_node = root_node.start(test_fn.name, 0);
test_node.activate();
progress.refresh();
const test_node = root_node.start(test_fn.name, 0);
if (!have_tty) {
std.debug.print("{d}/{d} {s}... ", .{ i + 1, test_fn_list.len, test_fn.name });
std.debug.print("{d}/{d} {s}...", .{ i + 1, test_fn_list.len, test_fn.name });
}
if (test_fn.func()) |_| {
ok_count += 1;
@ -164,12 +161,22 @@ fn mainTerminal() void {
} else |err| switch (err) {
error.SkipZigTest => {
skip_count += 1;
progress.log("SKIP\n", .{});
if (have_tty) {
std.debug.print("{d}/{d} {s}...SKIP\n", .{ i + 1, test_fn_list.len, test_fn.name });
} else {
std.debug.print("SKIP\n", .{});
}
test_node.end();
},
else => {
fail_count += 1;
progress.log("FAIL ({s})\n", .{@errorName(err)});
if (have_tty) {
std.debug.print("{d}/{d} {s}...FAIL ({s})\n", .{
i + 1, test_fn_list.len, test_fn.name, @errorName(err),
});
} else {
std.debug.print("FAIL ({s})\n", .{@errorName(err)});
}
if (@errorReturnTrace()) |trace| {
std.debug.dumpStackTrace(trace.*);
}

View File

@ -1059,7 +1059,7 @@ pub fn getUninstallStep(b: *Build) *Step {
return &b.uninstall_tls.step;
}
fn makeUninstall(uninstall_step: *Step, prog_node: *std.Progress.Node) anyerror!void {
fn makeUninstall(uninstall_step: *Step, prog_node: std.Progress.Node) anyerror!void {
_ = prog_node;
const uninstall_tls: *TopLevelStep = @fieldParentPtr("step", uninstall_step);
const b: *Build = @fieldParentPtr("uninstall_tls", uninstall_tls);
@ -2281,10 +2281,10 @@ pub const LazyPath = union(enum) {
.cwd_relative => |p| return src_builder.pathFromCwd(p),
.generated => |gen| {
var file_path: []const u8 = gen.file.step.owner.pathFromRoot(gen.file.path orelse {
std.debug.getStderrMutex().lock();
std.debug.lockStdErr();
const stderr = std.io.getStdErr();
dumpBadGetPathHelp(gen.file.step, stderr, src_builder, asking_step) catch {};
std.debug.getStderrMutex().unlock();
std.debug.unlockStdErr();
@panic("misconfigured build script");
});
@ -2351,8 +2351,8 @@ fn dumpBadDirnameHelp(
comptime msg: []const u8,
args: anytype,
) anyerror!void {
debug.getStderrMutex().lock();
defer debug.getStderrMutex().unlock();
debug.lockStdErr();
defer debug.unlockStdErr();
const stderr = io.getStdErr();
const w = stderr.writer();

View File

@ -58,7 +58,7 @@ pub const TestResults = struct {
}
};
pub const MakeFn = *const fn (step: *Step, prog_node: *std.Progress.Node) anyerror!void;
pub const MakeFn = *const fn (step: *Step, prog_node: std.Progress.Node) anyerror!void;
pub const State = enum {
precheck_unstarted,
@ -176,7 +176,7 @@ pub fn init(options: StepOptions) Step {
/// If the Step's `make` function reports `error.MakeFailed`, it indicates they
/// have already reported the error. Otherwise, we add a simple error report
/// here.
pub fn make(s: *Step, prog_node: *std.Progress.Node) error{ MakeFailed, MakeSkipped }!void {
pub fn make(s: *Step, prog_node: std.Progress.Node) error{ MakeFailed, MakeSkipped }!void {
const arena = s.owner.allocator;
s.makeFn(s, prog_node) catch |err| switch (err) {
@ -217,7 +217,7 @@ pub fn getStackTrace(s: *Step) ?std.builtin.StackTrace {
};
}
fn makeNoOp(step: *Step, prog_node: *std.Progress.Node) anyerror!void {
fn makeNoOp(step: *Step, prog_node: std.Progress.Node) anyerror!void {
_ = prog_node;
var all_cached = true;
@ -303,7 +303,7 @@ pub fn addError(step: *Step, comptime fmt: []const u8, args: anytype) error{OutO
pub fn evalZigProcess(
s: *Step,
argv: []const []const u8,
prog_node: *std.Progress.Node,
prog_node: std.Progress.Node,
) !?[]const u8 {
assert(argv.len != 0);
const b = s.owner;
@ -319,6 +319,7 @@ pub fn evalZigProcess(
child.stdout_behavior = .Pipe;
child.stderr_behavior = .Pipe;
child.request_resource_usage_statistics = true;
child.progress_node = prog_node;
child.spawn() catch |err| return s.fail("unable to spawn {s}: {s}", .{
argv[0], @errorName(err),
@ -337,11 +338,6 @@ pub fn evalZigProcess(
const Header = std.zig.Server.Message.Header;
var result: ?[]const u8 = null;
var node_name: std.ArrayListUnmanaged(u8) = .{};
defer node_name.deinit(gpa);
var sub_prog_node = prog_node.start("", 0);
defer sub_prog_node.end();
const stdout = poller.fifo(.stdout);
poll: while (true) {
@ -379,11 +375,6 @@ pub fn evalZigProcess(
.extra = extra_array,
};
},
.progress => {
node_name.clearRetainingCapacity();
try node_name.appendSlice(gpa, body);
sub_prog_node.setName(node_name.items);
},
.emit_bin_path => {
const EbpHdr = std.zig.Server.Message.EmitBinPath;
const ebp_hdr = @as(*align(1) const EbpHdr, @ptrCast(body));

View File

@ -46,7 +46,7 @@ pub fn setName(check_file: *CheckFile, name: []const u8) void {
check_file.step.name = name;
}
fn make(step: *Step, prog_node: *std.Progress.Node) !void {
fn make(step: *Step, prog_node: std.Progress.Node) !void {
_ = prog_node;
const b = step.owner;
const check_file: *CheckFile = @fieldParentPtr("step", step);

View File

@ -550,7 +550,7 @@ pub fn checkComputeCompare(
check_object.checks.append(check) catch @panic("OOM");
}
fn make(step: *Step, prog_node: *std.Progress.Node) !void {
fn make(step: *Step, prog_node: std.Progress.Node) !void {
_ = prog_node;
const b = step.owner;
const gpa = b.allocator;

View File

@ -967,7 +967,7 @@ fn getGeneratedFilePath(compile: *Compile, comptime tag_name: []const u8, asking
const maybe_path: ?*GeneratedFile = @field(compile, tag_name);
const generated_file = maybe_path orelse {
std.debug.getStderrMutex().lock();
std.debug.lockStdErr();
const stderr = std.io.getStdErr();
std.Build.dumpBadGetPathHelp(&compile.step, stderr, compile.step.owner, asking_step) catch {};
@ -976,7 +976,7 @@ fn getGeneratedFilePath(compile: *Compile, comptime tag_name: []const u8, asking
};
const path = generated_file.path orelse {
std.debug.getStderrMutex().lock();
std.debug.lockStdErr();
const stderr = std.io.getStdErr();
std.Build.dumpBadGetPathHelp(&compile.step, stderr, compile.step.owner, asking_step) catch {};
@ -987,7 +987,7 @@ fn getGeneratedFilePath(compile: *Compile, comptime tag_name: []const u8, asking
return path;
}
fn make(step: *Step, prog_node: *std.Progress.Node) !void {
fn make(step: *Step, prog_node: std.Progress.Node) !void {
const b = step.owner;
const arena = b.allocator;
const compile: *Compile = @fieldParentPtr("step", step);

View File

@ -164,7 +164,7 @@ fn putValue(config_header: *ConfigHeader, field_name: []const u8, comptime T: ty
}
}
fn make(step: *Step, prog_node: *std.Progress.Node) !void {
fn make(step: *Step, prog_node: std.Progress.Node) !void {
_ = prog_node;
const b = step.owner;
const config_header: *ConfigHeader = @fieldParentPtr("step", step);

View File

@ -36,7 +36,7 @@ pub fn create(owner: *std.Build, options: Options) *Fmt {
return fmt;
}
fn make(step: *Step, prog_node: *std.Progress.Node) !void {
fn make(step: *Step, prog_node: std.Progress.Node) !void {
// zig fmt is fast enough that no progress is needed.
_ = prog_node;

View File

@ -115,7 +115,7 @@ pub fn create(owner: *std.Build, artifact: *Step.Compile, options: Options) *Ins
return install_artifact;
}
fn make(step: *Step, prog_node: *std.Progress.Node) !void {
fn make(step: *Step, prog_node: std.Progress.Node) !void {
_ = prog_node;
const install_artifact: *InstallArtifact = @fieldParentPtr("step", step);
const b = step.owner;

View File

@ -56,7 +56,7 @@ pub fn create(owner: *std.Build, options: Options) *InstallDir {
return install_dir;
}
fn make(step: *Step, prog_node: *std.Progress.Node) !void {
fn make(step: *Step, prog_node: std.Progress.Node) !void {
_ = prog_node;
const b = step.owner;
const install_dir: *InstallDir = @fieldParentPtr("step", step);

View File

@ -36,7 +36,7 @@ pub fn create(
return install_file;
}
fn make(step: *Step, prog_node: *std.Progress.Node) !void {
fn make(step: *Step, prog_node: std.Progress.Node) !void {
_ = prog_node;
const b = step.owner;
const install_file: *InstallFile = @fieldParentPtr("step", step);

View File

@ -90,7 +90,7 @@ pub fn getOutputSeparatedDebug(objcopy: *const ObjCopy) ?std.Build.LazyPath {
return if (objcopy.output_file_debug) |*file| .{ .generated = .{ .file = file } } else null;
}
fn make(step: *Step, prog_node: *std.Progress.Node) !void {
fn make(step: *Step, prog_node: std.Progress.Node) !void {
const b = step.owner;
const objcopy: *ObjCopy = @fieldParentPtr("step", step);

View File

@ -410,7 +410,7 @@ pub fn getOutput(options: *Options) LazyPath {
return .{ .generated = .{ .file = &options.generated_file } };
}
fn make(step: *Step, prog_node: *std.Progress.Node) !void {
fn make(step: *Step, prog_node: std.Progress.Node) !void {
// This step completes so quickly that no progress is necessary.
_ = prog_node;

View File

@ -22,7 +22,7 @@ pub fn create(owner: *std.Build, dir_path: []const u8) *RemoveDir {
return remove_dir;
}
fn make(step: *Step, prog_node: *std.Progress.Node) !void {
fn make(step: *Step, prog_node: std.Progress.Node) !void {
// TODO update progress node while walking file system.
// Should the standard library support this use case??
_ = prog_node;

View File

@ -23,6 +23,11 @@ cwd: ?Build.LazyPath,
/// Override this field to modify the environment, or use setEnvironmentVariable
env_map: ?*EnvMap,
/// When `true` prevents `ZIG_PROGRESS` environment variable from being passed
/// to the child process, which otherwise would be used for the child to send
/// progress updates to the parent.
disable_zig_progress: bool,
/// Configures whether the Run step is considered to have side-effects, and also
/// whether the Run step will inherit stdio streams, forwarding them to the
/// parent process, in which case will require a global lock to prevent other
@ -152,6 +157,7 @@ pub fn create(owner: *std.Build, name: []const u8) *Run {
.argv = .{},
.cwd = null,
.env_map = null,
.disable_zig_progress = false,
.stdio = .infer_from_args,
.stdin = .none,
.extra_file_dependencies = &.{},
@ -574,7 +580,7 @@ const IndexedOutput = struct {
tag: @typeInfo(Arg).Union.tag_type.?,
output: *Output,
};
fn make(step: *Step, prog_node: *std.Progress.Node) !void {
fn make(step: *Step, prog_node: std.Progress.Node) !void {
const b = step.owner;
const arena = b.allocator;
const run: *Run = @fieldParentPtr("step", step);
@ -878,7 +884,7 @@ fn runCommand(
argv: []const []const u8,
has_side_effects: bool,
output_dir_path: []const u8,
prog_node: *std.Progress.Node,
prog_node: std.Progress.Node,
) !void {
const step = &run.step;
const b = step.owner;
@ -1195,7 +1201,7 @@ fn spawnChildAndCollect(
run: *Run,
argv: []const []const u8,
has_side_effects: bool,
prog_node: *std.Progress.Node,
prog_node: std.Progress.Node,
) !ChildProcResult {
const b = run.step.owner;
const arena = b.allocator;
@ -1235,6 +1241,10 @@ fn spawnChildAndCollect(
child.stdin_behavior = .Pipe;
}
if (run.stdio != .zig_test and !run.disable_zig_progress) {
child.progress_node = prog_node;
}
try child.spawn();
var timer = try std.time.Timer.start();
@ -1264,7 +1274,7 @@ const StdIoResult = struct {
fn evalZigTest(
run: *Run,
child: *std.process.Child,
prog_node: *std.Progress.Node,
prog_node: std.Progress.Node,
) !StdIoResult {
const gpa = run.step.owner.allocator;
const arena = run.step.owner.allocator;
@ -1291,7 +1301,7 @@ fn evalZigTest(
var metadata: ?TestMetadata = null;
var sub_prog_node: ?std.Progress.Node = null;
defer if (sub_prog_node) |*n| n.end();
defer if (sub_prog_node) |n| n.end();
poll: while (true) {
while (stdout.readableLength() < @sizeOf(Header)) {
@ -1406,7 +1416,7 @@ const TestMetadata = struct {
expected_panic_msgs: []const u32,
string_bytes: []const u8,
next_index: u32,
prog_node: *std.Progress.Node,
prog_node: std.Progress.Node,
fn testName(tm: TestMetadata, index: u32) []const u8 {
return std.mem.sliceTo(tm.string_bytes[tm.names[index]..], 0);
@ -1421,7 +1431,7 @@ fn requestNextTest(in: fs.File, metadata: *TestMetadata, sub_prog_node: *?std.Pr
if (metadata.expected_panic_msgs[i] != 0) continue;
const name = metadata.testName(i);
if (sub_prog_node.*) |*n| n.end();
if (sub_prog_node.*) |n| n.end();
sub_prog_node.* = metadata.prog_node.start(name, 0);
try sendRunTestMessage(in, i);

View File

@ -116,7 +116,7 @@ pub fn defineCMacroRaw(translate_c: *TranslateC, name_and_value: []const u8) voi
translate_c.c_macros.append(translate_c.step.owner.dupe(name_and_value)) catch @panic("OOM");
}
fn make(step: *Step, prog_node: *std.Progress.Node) !void {
fn make(step: *Step, prog_node: std.Progress.Node) !void {
const b = step.owner;
const translate_c: *TranslateC = @fieldParentPtr("step", step);

View File

@ -198,7 +198,7 @@ fn maybeUpdateName(write_file: *WriteFile) void {
}
}
fn make(step: *Step, prog_node: *std.Progress.Node) !void {
fn make(step: *Step, prog_node: std.Progress.Node) !void {
_ = prog_node;
const b = step.owner;
const write_file: *WriteFile = @fieldParentPtr("step", step);

File diff suppressed because it is too large Load Diff

View File

@ -77,19 +77,28 @@ const PdbOrDwarf = union(enum) {
}
};
var stderr_mutex = std.Thread.Mutex{};
/// Allows the caller to freely write to stderr until `unlockStdErr` is called.
///
/// During the lock, any `std.Progress` information is cleared from the terminal.
pub fn lockStdErr() void {
std.Progress.lockStdErr();
}
pub fn unlockStdErr() void {
std.Progress.unlockStdErr();
}
/// Print to stderr, unbuffered, and silently returning on failure. Intended
/// for use in "printf debugging." Use `std.log` functions for proper logging.
pub fn print(comptime fmt: []const u8, args: anytype) void {
stderr_mutex.lock();
defer stderr_mutex.unlock();
lockStdErr();
defer unlockStdErr();
const stderr = io.getStdErr().writer();
nosuspend stderr.print(fmt, args) catch return;
}
pub fn getStderrMutex() *std.Thread.Mutex {
return &stderr_mutex;
@compileError("deprecated. call std.debug.lockStdErr() and std.debug.unlockStdErr() instead which will integrate properly with std.Progress");
}
/// TODO multithreaded awareness
@ -107,8 +116,8 @@ pub fn getSelfDebugInfo() !*DebugInfo {
/// Tries to print a hexadecimal view of the bytes, unbuffered, and ignores any error returned.
/// Obtains the stderr mutex while dumping.
pub fn dump_hex(bytes: []const u8) void {
stderr_mutex.lock();
defer stderr_mutex.unlock();
lockStdErr();
defer unlockStdErr();
dump_hex_fallible(bytes) catch {};
}
@ -2750,13 +2759,19 @@ pub const Trace = ConfigurableTrace(2, 4, builtin.mode == .Debug);
pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize, comptime is_enabled: bool) type {
return struct {
addrs: [actual_size][stack_frame_count]usize = undefined,
notes: [actual_size][]const u8 = undefined,
index: Index = 0,
addrs: [actual_size][stack_frame_count]usize,
notes: [actual_size][]const u8,
index: Index,
const actual_size = if (enabled) size else 0;
const Index = if (enabled) usize else u0;
pub const init: @This() = .{
.addrs = undefined,
.notes = undefined,
.index = 0,
};
pub const enabled = is_enabled;
pub const add = if (enabled) addNoInline else addNoOp;

View File

@ -9,7 +9,7 @@ const assert = std.debug.assert;
const mem = std.mem;
const unicode = std.unicode;
const meta = std.meta;
const lossyCast = std.math.lossyCast;
const lossyCast = math.lossyCast;
const expectFmt = std.testing.expectFmt;
pub const default_max_depth = 3;
@ -1494,10 +1494,20 @@ pub fn Formatter(comptime format_fn: anytype) type {
/// Ignores '_' character in `buf`.
/// See also `parseUnsigned`.
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[0] == '+') return parseWithSign(T, buf[1..], base, .pos);
if (buf[0] == '-') return parseWithSign(T, buf[1..], base, .neg);
return parseWithSign(T, buf, base, .pos);
if (buf[0] == '+') return parseIntWithSign(Result, Character, buf[1..], base, .pos);
if (buf[0] == '-') return parseIntWithSign(Result, Character, buf[1..], base, .neg);
return parseIntWithSign(Result, Character, buf, base, .pos);
}
test parseInt {
@ -1560,12 +1570,13 @@ test parseInt {
try std.testing.expectEqual(@as(i5, -16), try std.fmt.parseInt(i5, "-10", 16));
}
fn parseWithSign(
comptime T: type,
buf: []const u8,
fn parseIntWithSign(
comptime Result: type,
comptime Character: type,
buf: []const Character,
base: u8,
comptime sign: enum { pos, neg },
) ParseIntError!T {
) ParseIntError!Result {
if (buf.len == 0) return error.InvalidCharacter;
var buf_base = base;
@ -1575,7 +1586,7 @@ fn parseWithSign(
buf_base = 10;
// Detect the base by looking at buf prefix.
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' => {
buf_base = 2;
buf_start = buf[2..];
@ -1589,7 +1600,7 @@ fn parseWithSign(
buf_start = buf[2..];
},
else => {},
}
};
}
}
@ -1598,33 +1609,33 @@ fn parseWithSign(
.neg => math.sub,
};
// accumulate into U which is always 8 bits or larger. this prevents
// `buf_base` from overflowing T.
const info = @typeInfo(T);
const U = std.meta.Int(info.Int.signedness, @max(8, info.Int.bits));
var x: U = 0;
// accumulate into Accumulate which is always 8 bits or larger. this prevents
// `buf_base` from overflowing Result.
const info = @typeInfo(Result);
const Accumulate = std.meta.Int(info.Int.signedness, @max(8, info.Int.bits));
var accumulate: Accumulate = 0;
if (buf_start[0] == '_' or buf_start[buf_start.len - 1] == '_') return error.InvalidCharacter;
for (buf_start) |c| {
if (c == '_') continue;
const digit = try charToDigit(c, buf_base);
if (x != 0) {
x = try math.mul(U, x, math.cast(U, buf_base) orelse return error.Overflow);
const digit = try charToDigit(math.cast(u8, c) orelse return error.InvalidCharacter, buf_base);
if (accumulate != 0) {
accumulate = try math.mul(Accumulate, accumulate, math.cast(Accumulate, buf_base) orelse return error.Overflow);
} else if (sign == .neg) {
// The first digit of a negative number.
// 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.
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;
}
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)
x
return if (Result == Accumulate)
accumulate
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
@ -1639,7 +1650,7 @@ fn parseWithSign(
/// Ignores '_' character in `buf`.
/// See also `parseInt`.
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 {

View File

@ -24,7 +24,7 @@ pub fn detectConfig(file: File) Config {
if (native_os == .windows and file.isTty()) {
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 .{ .windows_api = .{

View File

@ -52,8 +52,8 @@ pub const Value = union(enum) {
}
pub fn dump(self: Value) void {
std.debug.getStderrMutex().lock();
defer std.debug.getStderrMutex().unlock();
std.debug.lockStdErr();
defer std.debug.unlockStdErr();
const stderr = std.io.getStdErr().writer();
stringify(self, .{}, stderr) catch return;

View File

@ -45,8 +45,8 @@
//! const prefix = "[" ++ comptime level.asText() ++ "] " ++ scope_prefix;
//!
//! // Print the message to stderr, silently ignoring any errors
//! std.debug.getStderrMutex().lock();
//! defer std.debug.getStderrMutex().unlock();
//! std.debug.lockStdErr();
//! defer std.debug.unlockStdErr();
//! const stderr = std.io.getStdErr().writer();
//! nosuspend stderr.print(prefix ++ format ++ "\n", args) catch return;
//! }
@ -152,8 +152,8 @@ pub fn defaultLog(
var bw = std.io.bufferedWriter(stderr);
const writer = bw.writer();
std.debug.getStderrMutex().lock();
defer std.debug.getStderrMutex().unlock();
std.debug.lockStdErr();
defer std.debug.unlockStdErr();
nosuspend {
writer.print(level_txt ++ prefix2 ++ format ++ "\n", args) catch return;
bw.flush() catch return;

View File

@ -175,6 +175,15 @@ pub extern "kernel32" fn FillConsoleOutputCharacterW(hConsoleOutput: HANDLE, cCh
pub extern "kernel32" fn FillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: WORD, nLength: DWORD, dwWriteCoord: COORD, lpNumberOfAttrsWritten: *DWORD) callconv(WINAPI) BOOL;
pub extern "kernel32" fn SetConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD) callconv(WINAPI) BOOL;
pub extern "kernel32" fn WriteConsoleW(hConsoleOutput: HANDLE, lpBuffer: [*]const u16, nNumberOfCharsToWrite: DWORD, lpNumberOfCharsWritten: ?*DWORD, lpReserved: ?LPVOID) callconv(WINAPI) BOOL;
pub extern "kernel32" fn ReadConsoleOutputCharacterW(
hConsoleOutput: windows.HANDLE,
lpCharacter: [*]u16,
nLength: windows.DWORD,
dwReadCoord: windows.COORD,
lpNumberOfCharsRead: *windows.DWORD,
) callconv(windows.WINAPI) windows.BOOL;
pub extern "kernel32" fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: ?[*]WCHAR) callconv(WINAPI) DWORD;
pub extern "kernel32" fn GetCurrentThread() callconv(WINAPI) HANDLE;

View File

@ -431,6 +431,26 @@ pub fn hasEnvVarConstant(comptime key: []const u8) bool {
}
}
pub const ParseEnvVarIntError = std.fmt.ParseIntError || error{EnvironmentVariableNotFound};
/// Parses an environment variable as an integer.
///
/// Since the key is comptime-known, no allocation is needed.
///
/// On Windows, `key` must be valid UTF-8.
pub fn parseEnvVarInt(comptime key: []const u8, comptime I: type, base: u8) ParseEnvVarIntError!I {
if (native_os == .windows) {
const key_w = comptime std.unicode.utf8ToUtf16LeStringLiteral(key);
const text = getenvW(key_w) orelse return error.EnvironmentVariableNotFound;
return std.fmt.parseIntWithGenericCharacter(I, u16, text, base);
} else if (native_os == .wasi and !builtin.link_libc) {
@compileError("parseEnvVarInt is not supported for WASI without libc");
} else {
const text = posix.getenv(key) orelse return error.EnvironmentVariableNotFound;
return std.fmt.parseInt(I, text, base);
}
}
pub const HasEnvVarError = error{
OutOfMemory,
@ -1740,6 +1760,7 @@ pub fn cleanExit() void {
if (builtin.mode == .Debug) {
return;
} else {
std.debug.lockStdErr();
exit(0);
}
}
@ -1790,24 +1811,143 @@ test raiseFileDescriptorLimit {
raiseFileDescriptorLimit();
}
pub fn createNullDelimitedEnvMap(arena: mem.Allocator, env_map: *const EnvMap) ![:null]?[*:0]u8 {
const envp_count = env_map.count();
const envp_buf = try arena.allocSentinel(?[*:0]u8, envp_count, null);
{
var it = env_map.iterator();
var i: usize = 0;
while (it.next()) |pair| : (i += 1) {
const env_buf = try arena.allocSentinel(u8, pair.key_ptr.len + pair.value_ptr.len + 1, 0);
@memcpy(env_buf[0..pair.key_ptr.len], pair.key_ptr.*);
env_buf[pair.key_ptr.len] = '=';
@memcpy(env_buf[pair.key_ptr.len + 1 ..][0..pair.value_ptr.len], pair.value_ptr.*);
envp_buf[i] = env_buf.ptr;
pub const CreateEnvironOptions = struct {
/// `null` means to leave the `ZIG_PROGRESS` environment variable unmodified.
/// If non-null, negative means to remove the environment variable, and >= 0
/// means to provide it with the given integer.
zig_progress_fd: ?i32 = null,
};
/// Creates a null-deliminated environment variable block in the format
/// expected by POSIX, from a hash map plus options.
pub fn createEnvironFromMap(
arena: Allocator,
map: *const EnvMap,
options: CreateEnvironOptions,
) Allocator.Error![:null]?[*:0]u8 {
const ZigProgressAction = enum { nothing, edit, delete, add };
const zig_progress_action: ZigProgressAction = a: {
const fd = options.zig_progress_fd orelse break :a .nothing;
const contains = map.get("ZIG_PROGRESS") != null;
if (fd >= 0) {
break :a if (contains) .edit else .add;
} else {
if (contains) break :a .delete;
}
assert(i == envp_count);
break :a .nothing;
};
const envp_count: usize = c: {
var count: usize = map.count();
switch (zig_progress_action) {
.add => count += 1,
.delete => count -= 1,
.nothing, .edit => {},
}
break :c count;
};
const envp_buf = try arena.allocSentinel(?[*:0]u8, envp_count, null);
var i: usize = 0;
if (zig_progress_action == .add) {
envp_buf[i] = try std.fmt.allocPrintZ(arena, "ZIG_PROGRESS={d}", .{options.zig_progress_fd.?});
i += 1;
}
{
var it = map.iterator();
while (it.next()) |pair| {
if (mem.eql(u8, pair.key_ptr.*, "ZIG_PROGRESS")) switch (zig_progress_action) {
.add => unreachable,
.delete => continue,
.edit => {
envp_buf[i] = try std.fmt.allocPrintZ(arena, "{s}={d}", .{
pair.key_ptr.*, options.zig_progress_fd.?,
});
i += 1;
continue;
},
.nothing => {},
};
envp_buf[i] = try std.fmt.allocPrintZ(arena, "{s}={s}", .{ pair.key_ptr.*, pair.value_ptr.* });
i += 1;
}
}
assert(i == envp_count);
return envp_buf;
}
/// Creates a null-deliminated environment variable block in the format
/// expected by POSIX, from a hash map plus options.
pub fn createEnvironFromExisting(
arena: Allocator,
existing: [*:null]const ?[*:0]const u8,
options: CreateEnvironOptions,
) Allocator.Error![:null]?[*:0]u8 {
const existing_count, const contains_zig_progress = c: {
var count: usize = 0;
var contains = false;
while (existing[count]) |line| : (count += 1) {
contains = contains or mem.eql(u8, mem.sliceTo(line, '='), "ZIG_PROGRESS");
}
break :c .{ count, contains };
};
const ZigProgressAction = enum { nothing, edit, delete, add };
const zig_progress_action: ZigProgressAction = a: {
const fd = options.zig_progress_fd orelse break :a .nothing;
if (fd >= 0) {
break :a if (contains_zig_progress) .edit else .add;
} else {
if (contains_zig_progress) break :a .delete;
}
break :a .nothing;
};
const envp_count: usize = c: {
var count: usize = existing_count;
switch (zig_progress_action) {
.add => count += 1,
.delete => count -= 1,
.nothing, .edit => {},
}
break :c count;
};
const envp_buf = try arena.allocSentinel(?[*:0]u8, envp_count, null);
var i: usize = 0;
var existing_index: usize = 0;
if (zig_progress_action == .add) {
envp_buf[i] = try std.fmt.allocPrintZ(arena, "ZIG_PROGRESS={d}", .{options.zig_progress_fd.?});
i += 1;
}
while (existing[existing_index]) |line| : (existing_index += 1) {
if (mem.eql(u8, mem.sliceTo(line, '='), "ZIG_PROGRESS")) switch (zig_progress_action) {
.add => unreachable,
.delete => continue,
.edit => {
envp_buf[i] = try std.fmt.allocPrintZ(arena, "ZIG_PROGRESS={d}", .{options.zig_progress_fd.?});
i += 1;
continue;
},
.nothing => {},
};
envp_buf[i] = try arena.dupeZ(u8, mem.span(line));
i += 1;
}
assert(i == envp_count);
return envp_buf;
}
pub fn createNullDelimitedEnvMap(arena: mem.Allocator, env_map: *const EnvMap) Allocator.Error![:null]?[*:0]u8 {
return createEnvironFromMap(arena, env_map, .{});
}
test createNullDelimitedEnvMap {
const allocator = testing.allocator;
var envmap = EnvMap.init(allocator);

View File

@ -12,6 +12,7 @@ const EnvMap = std.process.EnvMap;
const maxInt = std.math.maxInt;
const assert = std.debug.assert;
const native_os = builtin.os.tag;
const Allocator = std.mem.Allocator;
const ChildProcess = @This();
pub const Id = switch (native_os) {
@ -92,6 +93,16 @@ request_resource_usage_statistics: bool = false,
/// `spawn`.
resource_usage_statistics: ResourceUsageStatistics = .{},
/// When populated, a pipe will be created for the child process to
/// communicate progress back to the parent. The file descriptor of the
/// write end of the pipe will be specified in the `ZIG_PROGRESS`
/// environment variable inside the child process. The progress reported by
/// the child will be attached to this progress node in the parent process.
///
/// The child's progress tree will be grafted into the parent's progress tree,
/// by substituting this node with the child's root node.
progress_node: std.Progress.Node = .{ .index = .none },
pub const ResourceUsageStatistics = struct {
rusage: @TypeOf(rusage_init) = rusage_init,
@ -205,9 +216,9 @@ pub fn init(argv: []const []const u8, allocator: mem.Allocator) ChildProcess {
.stdin = null,
.stdout = null,
.stderr = null,
.stdin_behavior = StdIo.Inherit,
.stdout_behavior = StdIo.Inherit,
.stderr_behavior = StdIo.Inherit,
.stdin_behavior = .Inherit,
.stdout_behavior = .Inherit,
.stderr_behavior = .Inherit,
.expand_arg0 = .no_expand,
};
}
@ -538,22 +549,22 @@ fn spawnPosix(self: *ChildProcess) SpawnError!void {
// turns out, we `dup2` everything anyway, so there's no need!
const pipe_flags: posix.O = .{ .CLOEXEC = true };
const stdin_pipe = if (self.stdin_behavior == StdIo.Pipe) try posix.pipe2(pipe_flags) else undefined;
errdefer if (self.stdin_behavior == StdIo.Pipe) {
const stdin_pipe = if (self.stdin_behavior == .Pipe) try posix.pipe2(pipe_flags) else undefined;
errdefer if (self.stdin_behavior == .Pipe) {
destroyPipe(stdin_pipe);
};
const stdout_pipe = if (self.stdout_behavior == StdIo.Pipe) try posix.pipe2(pipe_flags) else undefined;
errdefer if (self.stdout_behavior == StdIo.Pipe) {
const stdout_pipe = if (self.stdout_behavior == .Pipe) try posix.pipe2(pipe_flags) else undefined;
errdefer if (self.stdout_behavior == .Pipe) {
destroyPipe(stdout_pipe);
};
const stderr_pipe = if (self.stderr_behavior == StdIo.Pipe) try posix.pipe2(pipe_flags) else undefined;
errdefer if (self.stderr_behavior == StdIo.Pipe) {
const stderr_pipe = if (self.stderr_behavior == .Pipe) try posix.pipe2(pipe_flags) else undefined;
errdefer if (self.stderr_behavior == .Pipe) {
destroyPipe(stderr_pipe);
};
const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore);
const any_ignore = (self.stdin_behavior == .Ignore or self.stdout_behavior == .Ignore or self.stderr_behavior == .Ignore);
const dev_null_fd = if (any_ignore)
posix.openZ("/dev/null", .{ .ACCMODE = .RDWR }, 0) catch |err| switch (err) {
error.PathAlreadyExists => unreachable,
@ -572,6 +583,16 @@ fn spawnPosix(self: *ChildProcess) SpawnError!void {
if (any_ignore) posix.close(dev_null_fd);
}
const prog_pipe: [2]posix.fd_t = p: {
if (self.progress_node.index == .none) {
break :p .{ -1, -1 };
} else {
// We use CLOEXEC for the same reason as in `pipe_flags`.
break :p try posix.pipe2(.{ .NONBLOCK = true, .CLOEXEC = true });
}
};
errdefer destroyPipe(prog_pipe);
var arena_allocator = std.heap.ArenaAllocator.init(self.allocator);
defer arena_allocator.deinit();
const arena = arena_allocator.allocator();
@ -588,16 +609,25 @@ fn spawnPosix(self: *ChildProcess) SpawnError!void {
const argv_buf = try arena.allocSentinel(?[*:0]const u8, self.argv.len, null);
for (self.argv, 0..) |arg, i| argv_buf[i] = (try arena.dupeZ(u8, arg)).ptr;
const envp = m: {
const prog_fileno = 3;
comptime assert(@max(posix.STDIN_FILENO, posix.STDOUT_FILENO, posix.STDERR_FILENO) + 1 == prog_fileno);
const envp: [*:null]const ?[*:0]const u8 = m: {
const prog_fd: i32 = if (prog_pipe[1] == -1) -1 else prog_fileno;
if (self.env_map) |env_map| {
const envp_buf = try process.createNullDelimitedEnvMap(arena, env_map);
break :m envp_buf.ptr;
break :m (try process.createEnvironFromMap(arena, env_map, .{
.zig_progress_fd = prog_fd,
})).ptr;
} else if (builtin.link_libc) {
break :m std.c.environ;
break :m (try process.createEnvironFromExisting(arena, std.c.environ, .{
.zig_progress_fd = prog_fd,
})).ptr;
} else if (builtin.output_mode == .Exe) {
// Then we have Zig start code and this works.
// TODO type-safety for null-termination of `os.environ`.
break :m @as([*:null]const ?[*:0]const u8, @ptrCast(std.os.environ.ptr));
break :m (try process.createEnvironFromExisting(arena, @ptrCast(std.os.environ.ptr), .{
.zig_progress_fd = prog_fd,
})).ptr;
} else {
// TODO come up with a solution for this.
@compileError("missing std lib enhancement: ChildProcess implementation has no way to collect the environment variables to forward to the child process");
@ -631,6 +661,10 @@ fn spawnPosix(self: *ChildProcess) SpawnError!void {
posix.chdir(cwd) catch |err| forkChildErrReport(err_pipe[1], err);
}
// Must happen after fchdir above, the cwd file descriptor might be
// equal to prog_fileno and be clobbered by this dup2 call.
if (prog_pipe[1] != -1) posix.dup2(prog_pipe[1], prog_fileno) catch |err| forkChildErrReport(err_pipe[1], err);
if (self.gid) |gid| {
posix.setregid(gid, gid) catch |err| forkChildErrReport(err_pipe[1], err);
}
@ -648,18 +682,18 @@ fn spawnPosix(self: *ChildProcess) SpawnError!void {
// we are the parent
const pid: i32 = @intCast(pid_result);
if (self.stdin_behavior == StdIo.Pipe) {
self.stdin = File{ .handle = stdin_pipe[1] };
if (self.stdin_behavior == .Pipe) {
self.stdin = .{ .handle = stdin_pipe[1] };
} else {
self.stdin = null;
}
if (self.stdout_behavior == StdIo.Pipe) {
self.stdout = File{ .handle = stdout_pipe[0] };
if (self.stdout_behavior == .Pipe) {
self.stdout = .{ .handle = stdout_pipe[0] };
} else {
self.stdout = null;
}
if (self.stderr_behavior == StdIo.Pipe) {
self.stderr = File{ .handle = stderr_pipe[0] };
if (self.stderr_behavior == .Pipe) {
self.stderr = .{ .handle = stderr_pipe[0] };
} else {
self.stderr = null;
}
@ -668,15 +702,20 @@ fn spawnPosix(self: *ChildProcess) SpawnError!void {
self.err_pipe = err_pipe;
self.term = null;
if (self.stdin_behavior == StdIo.Pipe) {
if (self.stdin_behavior == .Pipe) {
posix.close(stdin_pipe[0]);
}
if (self.stdout_behavior == StdIo.Pipe) {
if (self.stdout_behavior == .Pipe) {
posix.close(stdout_pipe[1]);
}
if (self.stderr_behavior == StdIo.Pipe) {
if (self.stderr_behavior == .Pipe) {
posix.close(stderr_pipe[1]);
}
if (prog_pipe[1] != -1) {
posix.close(prog_pipe[1]);
}
self.progress_node.setIpcFd(prog_pipe[0]);
}
fn spawnWindows(self: *ChildProcess) SpawnError!void {
@ -962,7 +1001,7 @@ fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) !
}
fn destroyPipe(pipe: [2]posix.fd_t) void {
posix.close(pipe[0]);
if (pipe[0] != -1) posix.close(pipe[0]);
if (pipe[0] != pipe[1]) posix.close(pipe[1]);
}

View File

@ -718,7 +718,7 @@ pub const LazySrcLoc = union(enum) {
/// where in semantic analysis the value got set.
pub const TracedOffset = struct {
x: i32,
trace: std.debug.Trace = .{},
trace: std.debug.Trace = std.debug.Trace.init,
const want_tracing = false;
};

View File

@ -155,8 +155,8 @@ pub const RenderOptions = struct {
};
pub fn renderToStdErr(eb: ErrorBundle, options: RenderOptions) void {
std.debug.getStderrMutex().lock();
defer std.debug.getStderrMutex().unlock();
std.debug.lockStdErr();
defer std.debug.unlockStdErr();
const stderr = std.io.getStdErr();
return renderToWriter(eb, options, stderr.writer()) catch return;
}

View File

@ -14,8 +14,6 @@ pub const Message = struct {
zig_version,
/// Body is an ErrorBundle.
error_bundle,
/// Body is a UTF-8 string.
progress,
/// Body is a EmitBinPath.
emit_bin_path,
/// Body is a TestMetadata

View File

@ -1273,8 +1273,8 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
if (options.verbose_llvm_cpu_features) {
if (options.root_mod.resolved_target.llvm_cpu_features) |cf| print: {
const target = options.root_mod.resolved_target.result;
std.debug.getStderrMutex().lock();
defer std.debug.getStderrMutex().unlock();
std.debug.lockStdErr();
defer std.debug.unlockStdErr();
const stderr = std.io.getStdErr().writer();
nosuspend {
stderr.print("compilation: {s}\n", .{options.root_name}) catch break :print;
@ -1934,7 +1934,7 @@ pub fn getTarget(self: Compilation) Target {
/// Only legal to call when cache mode is incremental and a link file is present.
pub fn hotCodeSwap(
comp: *Compilation,
prog_node: *std.Progress.Node,
prog_node: std.Progress.Node,
pid: std.process.Child.Id,
) !void {
const lf = comp.bin_file.?;
@ -1966,7 +1966,7 @@ fn cleanupAfterUpdate(comp: *Compilation) void {
}
/// Detect changes to source files, perform semantic analysis, and update the output files.
pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void {
pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
const tracy_trace = trace(@src());
defer tracy_trace.end();
@ -2256,7 +2256,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void
}
}
fn flush(comp: *Compilation, arena: Allocator, prog_node: *std.Progress.Node) !void {
fn flush(comp: *Compilation, arena: Allocator, prog_node: std.Progress.Node) !void {
if (comp.bin_file) |lf| {
// This is needed before reading the error flags.
lf.flush(arena, prog_node) catch |err| switch (err) {
@ -2566,13 +2566,11 @@ pub fn emitLlvmObject(
default_emit: Emit,
bin_emit_loc: ?EmitLoc,
llvm_object: *LlvmObject,
prog_node: *std.Progress.Node,
prog_node: std.Progress.Node,
) !void {
if (build_options.only_c) @compileError("unreachable");
var sub_prog_node = prog_node.start("LLVM Emit Object", 0);
sub_prog_node.activate();
sub_prog_node.context.refresh();
const sub_prog_node = prog_node.start("LLVM Emit Object", 0);
defer sub_prog_node.end();
try llvm_object.emit(.{
@ -3249,32 +3247,20 @@ pub fn addZirErrorMessages(eb: *ErrorBundle.Wip, file: *Module.File) !void {
pub fn performAllTheWork(
comp: *Compilation,
main_progress_node: *std.Progress.Node,
main_progress_node: std.Progress.Node,
) error{ TimerUnsupported, OutOfMemory }!void {
// Here we queue up all the AstGen tasks first, followed by C object compilation.
// We wait until the AstGen tasks are all completed before proceeding to the
// (at least for now) single-threaded main work queue. However, C object compilation
// only needs to be finished by the end of this function.
var zir_prog_node = main_progress_node.start("AST Lowering", 0);
defer zir_prog_node.end();
var wasm_prog_node = main_progress_node.start("Compile Autodocs", 0);
defer wasm_prog_node.end();
var c_obj_prog_node = main_progress_node.start("Compile C Objects", comp.c_source_files.len);
defer c_obj_prog_node.end();
var win32_resource_prog_node = main_progress_node.start("Compile Win32 Resources", comp.rc_source_files.len);
defer win32_resource_prog_node.end();
comp.work_queue_wait_group.reset();
defer comp.work_queue_wait_group.wait();
if (!build_options.only_c and !build_options.only_core_functionality) {
if (comp.docs_emit != null) {
comp.thread_pool.spawnWg(&comp.work_queue_wait_group, workerDocsCopy, .{comp});
comp.work_queue_wait_group.spawnManager(workerDocsWasm, .{ comp, &wasm_prog_node });
comp.work_queue_wait_group.spawnManager(workerDocsWasm, .{ comp, main_progress_node });
}
}
@ -3282,6 +3268,9 @@ pub fn performAllTheWork(
const astgen_frame = tracy.namedFrame("astgen");
defer astgen_frame.end();
const zir_prog_node = main_progress_node.start("AST Lowering", 0);
defer zir_prog_node.end();
comp.astgen_wait_group.reset();
defer comp.astgen_wait_group.wait();
@ -3313,7 +3302,7 @@ pub fn performAllTheWork(
while (comp.astgen_work_queue.readItem()) |file| {
comp.thread_pool.spawnWg(&comp.astgen_wait_group, workerAstGenFile, .{
comp, file, &zir_prog_node, &comp.astgen_wait_group, .root,
comp, file, zir_prog_node, &comp.astgen_wait_group, .root,
});
}
@ -3325,14 +3314,14 @@ pub fn performAllTheWork(
while (comp.c_object_work_queue.readItem()) |c_object| {
comp.thread_pool.spawnWg(&comp.work_queue_wait_group, workerUpdateCObject, .{
comp, c_object, &c_obj_prog_node,
comp, c_object, main_progress_node,
});
}
if (!build_options.only_core_functionality) {
while (comp.win32_resource_work_queue.readItem()) |win32_resource| {
comp.thread_pool.spawnWg(&comp.work_queue_wait_group, workerUpdateWin32Resource, .{
comp, win32_resource, &win32_resource_prog_node,
comp, win32_resource, main_progress_node,
});
}
}
@ -3342,11 +3331,13 @@ pub fn performAllTheWork(
try reportMultiModuleErrors(mod);
try mod.flushRetryableFailures();
mod.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);
mod.sema_prog_node.activate();
mod.codegen_prog_node = main_progress_node.start("Code Generation", 0);
}
defer if (comp.module) |mod| {
mod.sema_prog_node.end();
mod.sema_prog_node = undefined;
mod.codegen_prog_node.end();
mod.codegen_prog_node = undefined;
};
while (true) {
@ -3379,7 +3370,7 @@ pub fn performAllTheWork(
}
}
fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !void {
fn processOneJob(comp: *Compilation, job: Job, prog_node: std.Progress.Node) !void {
switch (job) {
.codegen_decl => |decl_index| {
const module = comp.module.?;
@ -3803,7 +3794,10 @@ fn docsCopyModule(comp: *Compilation, module: *Package.Module, name: []const u8,
}
}
fn workerDocsWasm(comp: *Compilation, prog_node: *std.Progress.Node) void {
fn workerDocsWasm(comp: *Compilation, parent_prog_node: std.Progress.Node) void {
const prog_node = parent_prog_node.start("Compile Autodocs", 0);
defer prog_node.end();
workerDocsWasmFallible(comp, prog_node) catch |err| {
comp.lockAndSetMiscFailure(.docs_wasm, "unable to build autodocs: {s}", .{
@errorName(err),
@ -3811,7 +3805,7 @@ fn workerDocsWasm(comp: *Compilation, prog_node: *std.Progress.Node) void {
};
}
fn workerDocsWasmFallible(comp: *Compilation, prog_node: *std.Progress.Node) anyerror!void {
fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) anyerror!void {
const gpa = comp.gpa;
var arena_allocator = std.heap.ArenaAllocator.init(gpa);
@ -3952,12 +3946,11 @@ const AstGenSrc = union(enum) {
fn workerAstGenFile(
comp: *Compilation,
file: *Module.File,
prog_node: *std.Progress.Node,
prog_node: std.Progress.Node,
wg: *WaitGroup,
src: AstGenSrc,
) void {
var child_prog_node = prog_node.start(file.sub_file_path, 0);
child_prog_node.activate();
const child_prog_node = prog_node.start(file.sub_file_path, 0);
defer child_prog_node.end();
const mod = comp.module.?;
@ -4265,7 +4258,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module
fn workerUpdateCObject(
comp: *Compilation,
c_object: *CObject,
progress_node: *std.Progress.Node,
progress_node: std.Progress.Node,
) void {
comp.updateCObject(c_object, progress_node) catch |err| switch (err) {
error.AnalysisFail => return,
@ -4282,7 +4275,7 @@ fn workerUpdateCObject(
fn workerUpdateWin32Resource(
comp: *Compilation,
win32_resource: *Win32Resource,
progress_node: *std.Progress.Node,
progress_node: std.Progress.Node,
) void {
comp.updateWin32Resource(win32_resource, progress_node) catch |err| switch (err) {
error.AnalysisFail => return,
@ -4300,7 +4293,7 @@ fn buildCompilerRtOneShot(
comp: *Compilation,
output_mode: std.builtin.OutputMode,
out: *?CRTFile,
prog_node: *std.Progress.Node,
prog_node: std.Progress.Node,
) void {
comp.buildOutputFromZig(
"compiler_rt.zig",
@ -4427,7 +4420,7 @@ fn reportRetryableEmbedFileError(
}
}
fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.Progress.Node) !void {
fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Progress.Node) !void {
if (comp.config.c_frontend == .aro) {
return comp.failCObj(c_object, "aro does not support compiling C objects yet", .{});
}
@ -4467,9 +4460,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
const c_source_basename = std.fs.path.basename(c_object.src.src_path);
c_obj_prog_node.activate();
var child_progress_node = c_obj_prog_node.start(c_source_basename, 0);
child_progress_node.activate();
const child_progress_node = c_obj_prog_node.start(c_source_basename, 0);
defer child_progress_node.end();
// Special case when doing build-obj for just one C file. When there are more than one object
@ -4731,7 +4722,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
};
}
fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32_resource_prog_node: *std.Progress.Node) !void {
fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32_resource_prog_node: std.Progress.Node) !void {
if (!std.process.can_spawn) {
return comp.failWin32Resource(win32_resource, "{s} does not support spawning a child process", .{@tagName(builtin.os.tag)});
}
@ -4763,9 +4754,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
_ = comp.failed_win32_resources.swapRemove(win32_resource);
}
win32_resource_prog_node.activate();
var child_progress_node = win32_resource_prog_node.start(src_basename, 0);
child_progress_node.activate();
const child_progress_node = win32_resource_prog_node.start(src_basename, 0);
defer child_progress_node.end();
var man = comp.obtainWin32ResourceCacheManifest();
@ -4833,7 +4822,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
});
try argv.appendSlice(&.{ "--", in_rc_path, out_res_path });
try spawnZigRc(comp, win32_resource, src_basename, arena, argv.items, &child_progress_node);
try spawnZigRc(comp, win32_resource, arena, argv.items, child_progress_node);
break :blk digest;
};
@ -4901,7 +4890,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
try argv.appendSlice(rc_src.extra_flags);
try argv.appendSlice(&.{ "--", rc_src.src_path, out_res_path });
try spawnZigRc(comp, win32_resource, src_basename, arena, argv.items, &child_progress_node);
try spawnZigRc(comp, win32_resource, arena, argv.items, child_progress_node);
// Read depfile and update cache manifest
{
@ -4966,10 +4955,9 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
fn spawnZigRc(
comp: *Compilation,
win32_resource: *Win32Resource,
src_basename: []const u8,
arena: Allocator,
argv: []const []const u8,
child_progress_node: *std.Progress.Node,
child_progress_node: std.Progress.Node,
) !void {
var node_name: std.ArrayListUnmanaged(u8) = .{};
defer node_name.deinit(arena);
@ -4978,6 +4966,7 @@ fn spawnZigRc(
child.stdin_behavior = .Ignore;
child.stdout_behavior = .Pipe;
child.stderr_behavior = .Pipe;
child.progress_node = child_progress_node;
child.spawn() catch |err| {
return comp.failWin32Resource(win32_resource, "unable to spawn {s} rc: {s}", .{ argv[0], @errorName(err) });
@ -5019,22 +5008,6 @@ fn spawnZigRc(
};
return comp.failWin32ResourceWithOwnedBundle(win32_resource, error_bundle);
},
.progress => {
node_name.clearRetainingCapacity();
// <resinator> is a special string that indicates that the child
// process has reached resinator's main function
if (std.mem.eql(u8, body, "<resinator>")) {
child_progress_node.setName(src_basename);
}
// Ignore 0-length strings since if multiple zig rc commands
// are executed at the same time, only one will send progress strings
// while the other(s) will send empty strings.
else if (body.len > 0) {
try node_name.appendSlice(arena, "build 'zig rc'... ");
try node_name.appendSlice(arena, body);
child_progress_node.setName(node_name.items);
}
},
else => {}, // ignore other messages
}
@ -5937,8 +5910,8 @@ pub fn lockAndParseLldStderr(comp: *Compilation, prefix: []const u8, stderr: []c
}
pub fn dump_argv(argv: []const []const u8) void {
std.debug.getStderrMutex().lock();
defer std.debug.getStderrMutex().unlock();
std.debug.lockStdErr();
defer std.debug.unlockStdErr();
const stderr = std.io.getStdErr().writer();
for (argv[0 .. argv.len - 1]) |arg| {
nosuspend stderr.print("{s} ", .{arg}) catch return;
@ -5989,14 +5962,13 @@ pub fn updateSubCompilation(
parent_comp: *Compilation,
sub_comp: *Compilation,
misc_task: MiscTask,
prog_node: *std.Progress.Node,
prog_node: std.Progress.Node,
) !void {
{
var sub_node = prog_node.start(@tagName(misc_task), 0);
sub_node.activate();
const sub_node = prog_node.start(@tagName(misc_task), 0);
defer sub_node.end();
try sub_comp.update(prog_node);
try sub_comp.update(sub_node);
}
// Look for compilation errors in this sub compilation
@ -6024,7 +5996,7 @@ fn buildOutputFromZig(
output_mode: std.builtin.OutputMode,
out: *?CRTFile,
misc_task_tag: MiscTask,
prog_node: *std.Progress.Node,
prog_node: std.Progress.Node,
) !void {
const tracy_trace = trace(@src());
defer tracy_trace.end();
@ -6131,7 +6103,7 @@ pub fn build_crt_file(
root_name: []const u8,
output_mode: std.builtin.OutputMode,
misc_task_tag: MiscTask,
prog_node: *std.Progress.Node,
prog_node: std.Progress.Node,
/// These elements have to get mutated to add the owner module after it is
/// created within this function.
c_source_files: []CSourceFile,

View File

@ -66,6 +66,7 @@ root_mod: *Package.Module,
main_mod: *Package.Module,
std_mod: *Package.Module,
sema_prog_node: std.Progress.Node = undefined,
codegen_prog_node: std.Progress.Node = undefined,
/// Used by AstGen worker to load and store ZIR cache.
global_zir_cache: Compilation.Directory,
@ -2942,11 +2943,12 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
const tracy = trace(@src());
defer tracy.end();
const ip = &mod.intern_pool;
const decl = mod.declPtr(decl_index);
log.debug("ensureDeclAnalyzed '{d}' (name '{}')", .{
@intFromEnum(decl_index),
decl.name.fmt(&mod.intern_pool),
decl.name.fmt(ip),
});
// Determine whether or not this Decl is outdated, i.e. requires re-analysis
@ -2991,10 +2993,6 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
try mod.deleteDeclExports(decl_index);
}
var decl_prog_node = mod.sema_prog_node.start("", 0);
decl_prog_node.activate();
defer decl_prog_node.end();
const sema_result: SemaDeclResult = blk: {
if (decl.zir_decl_index == .none and !mod.declIsRoot(decl_index)) {
// Anonymous decl. We don't semantically analyze these.
@ -3012,6 +3010,9 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
};
}
const decl_prog_node = mod.sema_prog_node.start((try decl.fullyQualifiedName(mod)).toSlice(ip), 0);
defer decl_prog_node.end();
break :blk mod.semaDecl(decl_index) catch |err| switch (err) {
error.AnalysisFail => {
if (decl.analysis == .in_progress) {
@ -3215,6 +3216,9 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In
};
}
const codegen_prog_node = zcu.codegen_prog_node.start((try decl.fullyQualifiedName(zcu)).toSlice(ip), 0);
defer codegen_prog_node.end();
if (comp.bin_file) |lf| {
lf.updateFunc(zcu, func_index, air, liveness) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
@ -4500,6 +4504,9 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
log.debug("finish func name '{}'", .{(decl.fullyQualifiedName(mod) catch break :blk).fmt(ip)});
}
const decl_prog_node = mod.sema_prog_node.start((try decl.fullyQualifiedName(mod)).toSlice(ip), 0);
defer decl_prog_node.end();
mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .func = func_index }));
var comptime_err_ret_trace = std.ArrayList(SrcLoc).init(gpa);
@ -5316,7 +5323,7 @@ fn handleUpdateExports(
pub fn populateTestFunctions(
mod: *Module,
main_progress_node: *std.Progress.Node,
main_progress_node: std.Progress.Node,
) !void {
const gpa = mod.gpa;
const ip = &mod.intern_pool;
@ -5333,13 +5340,13 @@ pub fn populateTestFunctions(
// We have to call `ensureDeclAnalyzed` here in case `builtin.test_functions`
// was not referenced by start code.
mod.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);
mod.sema_prog_node.activate();
defer {
mod.sema_prog_node.end();
mod.sema_prog_node = undefined;
}
try mod.ensureDeclAnalyzed(decl_index);
}
const decl = mod.declPtr(decl_index);
const test_fn_ty = decl.typeOf(mod).slicePtrFieldType(mod).childType(mod);
@ -5440,21 +5447,32 @@ pub fn populateTestFunctions(
decl.val = new_val;
decl.has_tv = true;
}
try mod.linkerUpdateDecl(decl_index);
{
mod.codegen_prog_node = main_progress_node.start("Code Generation", 0);
defer {
mod.codegen_prog_node.end();
mod.codegen_prog_node = undefined;
}
try mod.linkerUpdateDecl(decl_index);
}
}
pub fn linkerUpdateDecl(zcu: *Zcu, decl_index: Decl.Index) !void {
const comp = zcu.comp;
const decl = zcu.declPtr(decl_index);
const codegen_prog_node = zcu.codegen_prog_node.start((try decl.fullyQualifiedName(zcu)).toSlice(&zcu.intern_pool), 0);
defer codegen_prog_node.end();
if (comp.bin_file) |lf| {
lf.updateDecl(zcu, decl_index) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
error.AnalysisFail => {
const decl = zcu.declPtr(decl_index);
decl.analysis = .codegen_failure;
},
else => {
const decl = zcu.declPtr(decl_index);
const gpa = zcu.gpa;
try zcu.failed_decls.ensureUnusedCapacity(gpa, 1);
zcu.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create(
@ -5472,7 +5490,6 @@ pub fn linkerUpdateDecl(zcu: *Zcu, decl_index: Decl.Index) !void {
llvm_object.updateDecl(zcu, decl_index) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
error.AnalysisFail => {
const decl = zcu.declPtr(decl_index);
decl.analysis = .codegen_failure;
},
};

View File

@ -35,7 +35,7 @@ name_tok: std.zig.Ast.TokenIndex,
lazy_status: LazyStatus,
parent_package_root: Cache.Path,
parent_manifest_ast: ?*const std.zig.Ast,
prog_node: *std.Progress.Node,
prog_node: std.Progress.Node,
job_queue: *JobQueue,
/// If true, don't add an error for a missing hash. This flag is not passed
/// down to recursive dependencies. It's intended to be used only be the CLI.
@ -720,8 +720,7 @@ fn queueJobsForDeps(f: *Fetch) RunError!void {
};
}
// job_queue mutex is locked so this is OK.
f.prog_node.unprotected_estimated_total_items += new_fetch_index;
f.prog_node.increaseEstimatedTotalItems(new_fetch_index);
break :nf .{ new_fetches[0..new_fetch_index], prog_names[0..new_fetch_index] };
};
@ -751,9 +750,8 @@ pub fn relativePathDigest(
}
pub fn workerRun(f: *Fetch, prog_name: []const u8) void {
var prog_node = f.prog_node.start(prog_name, 0);
const prog_node = f.prog_node.start(prog_name, 0);
defer prog_node.end();
prog_node.activate();
run(f) catch |err| switch (err) {
error.OutOfMemory => f.oom_flag = true,
@ -1311,9 +1309,8 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource) anyerror!Unpac
var index_file = try pack_dir.createFile("pkg.idx", .{ .read = true });
defer index_file.close();
{
var index_prog_node = f.prog_node.start("Index pack", 0);
const index_prog_node = f.prog_node.start("Index pack", 0);
defer index_prog_node.end();
index_prog_node.activate();
var index_buffered_writer = std.io.bufferedWriter(index_file.writer());
try git.indexPack(gpa, pack_file, index_buffered_writer.writer());
try index_buffered_writer.flush();
@ -1321,9 +1318,8 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource) anyerror!Unpac
}
{
var checkout_prog_node = f.prog_node.start("Checkout", 0);
const checkout_prog_node = f.prog_node.start("Checkout", 0);
defer checkout_prog_node.end();
checkout_prog_node.activate();
var repository = try git.Repository.init(gpa, pack_file, index_file);
defer repository.deinit();
var diagnostics: git.Diagnostics = .{ .allocator = arena };

View File

@ -160,7 +160,7 @@ pub const CRTFile = enum {
libc_nonshared_a,
};
pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progress.Node) !void {
pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: std.Progress.Node) !void {
if (!build_options.have_llvm) {
return error.ZigCompilerNotBuiltWithLLVMExtensions;
}
@ -658,7 +658,7 @@ pub const BuiltSharedObjects = struct {
const all_map_basename = "all.map";
pub fn buildSharedObjects(comp: *Compilation, prog_node: *std.Progress.Node) !void {
pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !void {
const tracy = trace(@src());
defer tracy.end();
@ -1065,7 +1065,7 @@ fn buildSharedLib(
bin_directory: Compilation.Directory,
asm_file_basename: []const u8,
lib: Lib,
prog_node: *std.Progress.Node,
prog_node: std.Progress.Node,
) !void {
const tracy = trace(@src());
defer tracy.end();

View File

@ -113,7 +113,7 @@ pub const BuildError = error{
ZigCompilerNotBuiltWithLLVMExtensions,
};
pub fn buildLibCXX(comp: *Compilation, prog_node: *std.Progress.Node) BuildError!void {
pub fn buildLibCXX(comp: *Compilation, prog_node: std.Progress.Node) BuildError!void {
if (!build_options.have_llvm) {
return error.ZigCompilerNotBuiltWithLLVMExtensions;
}
@ -357,7 +357,7 @@ pub fn buildLibCXX(comp: *Compilation, prog_node: *std.Progress.Node) BuildError
comp.libcxx_static_lib = try sub_compilation.toCrtFile();
}
pub fn buildLibCXXABI(comp: *Compilation, prog_node: *std.Progress.Node) BuildError!void {
pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildError!void {
if (!build_options.have_llvm) {
return error.ZigCompilerNotBuiltWithLLVMExtensions;
}

View File

@ -13,7 +13,7 @@ pub const BuildError = error{
TSANUnsupportedCPUArchitecture,
};
pub fn buildTsan(comp: *Compilation, prog_node: *std.Progress.Node) BuildError!void {
pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!void {
if (!build_options.have_llvm) {
return error.ZigCompilerNotBuiltWithLLVMExtensions;
}

View File

@ -14,7 +14,7 @@ pub const BuildError = error{
ZigCompilerNotBuiltWithLLVMExtensions,
};
pub fn buildStaticLib(comp: *Compilation, prog_node: *std.Progress.Node) BuildError!void {
pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildError!void {
if (!build_options.have_llvm) {
return error.ZigCompilerNotBuiltWithLLVMExtensions;
}

View File

@ -535,7 +535,7 @@ pub const File = struct {
/// Commit pending changes and write headers. Takes into account final output mode
/// and `use_lld`, not only `effectiveOutputMode`.
/// `arena` has the lifetime of the call to `Compilation.update`.
pub fn flush(base: *File, arena: Allocator, prog_node: *std.Progress.Node) FlushError!void {
pub fn flush(base: *File, arena: Allocator, prog_node: std.Progress.Node) FlushError!void {
if (build_options.only_c) {
assert(base.tag == .c);
return @as(*C, @fieldParentPtr("base", base)).flush(arena, prog_node);
@ -572,7 +572,7 @@ pub const File = struct {
/// Commit pending changes and write headers. Works based on `effectiveOutputMode`
/// rather than final output mode.
pub fn flushModule(base: *File, arena: Allocator, prog_node: *std.Progress.Node) FlushError!void {
pub fn flushModule(base: *File, arena: Allocator, prog_node: std.Progress.Node) FlushError!void {
switch (base.tag) {
inline else => |tag| {
if (tag != .c and build_options.only_c) unreachable;
@ -688,7 +688,7 @@ pub const File = struct {
}
}
pub fn linkAsArchive(base: *File, arena: Allocator, prog_node: *std.Progress.Node) FlushError!void {
pub fn linkAsArchive(base: *File, arena: Allocator, prog_node: std.Progress.Node) FlushError!void {
const tracy = trace(@src());
defer tracy.end();
@ -966,7 +966,7 @@ pub const File = struct {
base: File,
arena: Allocator,
llvm_object: *LlvmObject,
prog_node: *std.Progress.Node,
prog_node: std.Progress.Node,
) !void {
return base.comp.emitLlvmObject(arena, base.emit, .{
.directory = null,

View File

@ -370,7 +370,7 @@ pub fn updateDeclLineNumber(self: *C, zcu: *Zcu, decl_index: InternPool.DeclInde
_ = decl_index;
}
pub fn flush(self: *C, arena: Allocator, prog_node: *std.Progress.Node) !void {
pub fn flush(self: *C, arena: Allocator, prog_node: std.Progress.Node) !void {
return self.flushModule(arena, prog_node);
}
@ -389,14 +389,13 @@ fn abiDefines(self: *C, target: std.Target) !std.ArrayList(u8) {
return defines;
}
pub fn flushModule(self: *C, arena: Allocator, prog_node: *std.Progress.Node) !void {
pub fn flushModule(self: *C, arena: Allocator, prog_node: std.Progress.Node) !void {
_ = arena; // Has the same lifetime as the call to Compilation.update.
const tracy = trace(@src());
defer tracy.end();
var sub_prog_node = prog_node.start("Flush Module", 0);
sub_prog_node.activate();
const sub_prog_node = prog_node.start("Flush Module", 0);
defer sub_prog_node.end();
const comp = self.base.comp;

View File

@ -1702,7 +1702,7 @@ fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void {
gop.value_ptr.* = current;
}
pub fn flush(self: *Coff, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void {
pub fn flush(self: *Coff, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void {
const comp = self.base.comp;
const use_lld = build_options.have_llvm and comp.config.use_lld;
if (use_lld) {
@ -1714,7 +1714,7 @@ pub fn flush(self: *Coff, arena: Allocator, prog_node: *std.Progress.Node) link.
}
}
pub fn flushModule(self: *Coff, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void {
pub fn flushModule(self: *Coff, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void {
const tracy = trace(@src());
defer tracy.end();
@ -1726,8 +1726,7 @@ pub fn flushModule(self: *Coff, arena: Allocator, prog_node: *std.Progress.Node)
return;
}
var sub_prog_node = prog_node.start("COFF Flush", 0);
sub_prog_node.activate();
const sub_prog_node = prog_node.start("COFF Flush", 0);
defer sub_prog_node.end();
const module = comp.module orelse return error.LinkingWithoutZigSourceUnimplemented;

View File

@ -16,7 +16,7 @@ const Allocator = mem.Allocator;
const Coff = @import("../Coff.zig");
const Compilation = @import("../../Compilation.zig");
pub fn linkWithLLD(self: *Coff, arena: Allocator, prog_node: *std.Progress.Node) !void {
pub fn linkWithLLD(self: *Coff, arena: Allocator, prog_node: std.Progress.Node) !void {
const tracy = trace(@src());
defer tracy.end();
@ -38,9 +38,7 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, prog_node: *std.Progress.Node)
}
} else null;
var sub_prog_node = prog_node.start("LLD Link", 0);
sub_prog_node.activate();
sub_prog_node.context.refresh();
const sub_prog_node = prog_node.start("LLD Link", 0);
defer sub_prog_node.end();
const is_lib = comp.config.output_mode == .Lib;

View File

@ -1064,7 +1064,7 @@ pub fn markDirty(self: *Elf, shdr_index: u32) void {
}
}
pub fn flush(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void {
pub fn flush(self: *Elf, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void {
const use_lld = build_options.have_llvm and self.base.comp.config.use_lld;
if (use_lld) {
return self.linkWithLLD(arena, prog_node);
@ -1072,7 +1072,7 @@ pub fn flush(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) link.F
try self.flushModule(arena, prog_node);
}
pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void {
pub fn flushModule(self: *Elf, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void {
const tracy = trace(@src());
defer tracy.end();
@ -1085,8 +1085,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)
if (use_lld) return;
}
var sub_prog_node = prog_node.start("ELF Flush", 0);
sub_prog_node.activate();
const sub_prog_node = prog_node.start("ELF Flush", 0);
defer sub_prog_node.end();
const target = comp.root_mod.resolved_target.result;
@ -2147,7 +2146,7 @@ fn scanRelocs(self: *Elf) !void {
}
}
fn linkWithLLD(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) !void {
fn linkWithLLD(self: *Elf, arena: Allocator, prog_node: std.Progress.Node) !void {
const tracy = trace(@src());
defer tracy.end();
@ -2169,9 +2168,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) !voi
}
} else null;
var sub_prog_node = prog_node.start("LLD Link", 0);
sub_prog_node.activate();
sub_prog_node.context.refresh();
const sub_prog_node = prog_node.start("LLD Link", 0);
defer sub_prog_node.end();
const output_mode = comp.config.output_mode;

View File

@ -360,11 +360,11 @@ pub fn deinit(self: *MachO) void {
self.unwind_records.deinit(gpa);
}
pub fn flush(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void {
pub fn flush(self: *MachO, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void {
try self.flushModule(arena, prog_node);
}
pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void {
pub fn flushModule(self: *MachO, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void {
const tracy = trace(@src());
defer tracy.end();
@ -375,8 +375,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node
try self.base.emitLlvmObject(arena, llvm_object, prog_node);
}
var sub_prog_node = prog_node.start("MachO Flush", 0);
sub_prog_node.activate();
const sub_prog_node = prog_node.start("MachO Flush", 0);
defer sub_prog_node.end();
const directory = self.base.emit.directory;

View File

@ -106,11 +106,11 @@ pub fn freeDecl(self: *NvPtx, decl_index: InternPool.DeclIndex) void {
return self.llvm_object.freeDecl(decl_index);
}
pub fn flush(self: *NvPtx, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void {
pub fn flush(self: *NvPtx, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void {
return self.flushModule(arena, prog_node);
}
pub fn flushModule(self: *NvPtx, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void {
pub fn flushModule(self: *NvPtx, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void {
if (build_options.skip_non_native)
@panic("Attempted to compile for architecture that was disabled by build configuration");

View File

@ -604,7 +604,7 @@ fn allocateGotIndex(self: *Plan9) usize {
}
}
pub fn flush(self: *Plan9, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void {
pub fn flush(self: *Plan9, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void {
const comp = self.base.comp;
const use_lld = build_options.have_llvm and comp.config.use_lld;
assert(!use_lld);
@ -663,7 +663,7 @@ fn atomCount(self: *Plan9) usize {
return data_decl_count + fn_decl_count + unnamed_const_count + lazy_atom_count + extern_atom_count + anon_atom_count;
}
pub fn flushModule(self: *Plan9, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void {
pub fn flushModule(self: *Plan9, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void {
if (build_options.skip_non_native and builtin.object_format != .plan9) {
@panic("Attempted to compile for object format that was disabled by build configuration");
}
@ -677,8 +677,7 @@ pub fn flushModule(self: *Plan9, arena: Allocator, prog_node: *std.Progress.Node
const tracy = trace(@src());
defer tracy.end();
var sub_prog_node = prog_node.start("Flush Module", 0);
sub_prog_node.activate();
const sub_prog_node = prog_node.start("Flush Module", 0);
defer sub_prog_node.end();
log.debug("flushModule", .{});

View File

@ -193,11 +193,11 @@ pub fn freeDecl(self: *SpirV, decl_index: InternPool.DeclIndex) void {
_ = decl_index;
}
pub fn flush(self: *SpirV, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void {
pub fn flush(self: *SpirV, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void {
return self.flushModule(arena, prog_node);
}
pub fn flushModule(self: *SpirV, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void {
pub fn flushModule(self: *SpirV, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void {
if (build_options.skip_non_native) {
@panic("Attempted to compile for architecture that was disabled by build configuration");
}
@ -205,8 +205,7 @@ pub fn flushModule(self: *SpirV, arena: Allocator, prog_node: *std.Progress.Node
const tracy = trace(@src());
defer tracy.end();
var sub_prog_node = prog_node.start("Flush Module", 0);
sub_prog_node.activate();
const sub_prog_node = prog_node.start("Flush Module", 0);
defer sub_prog_node.end();
const spv = &self.object.spv;
@ -253,7 +252,7 @@ pub fn flushModule(self: *SpirV, arena: Allocator, prog_node: *std.Progress.Node
const module = try spv.finalize(arena, target);
errdefer arena.free(module);
const linked_module = self.linkModule(arena, module, &sub_prog_node) catch |err| switch (err) {
const linked_module = self.linkModule(arena, module, sub_prog_node) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
else => |other| {
log.err("error while linking: {s}\n", .{@errorName(other)});
@ -264,7 +263,7 @@ pub fn flushModule(self: *SpirV, arena: Allocator, prog_node: *std.Progress.Node
try self.base.file.?.writeAll(std.mem.sliceAsBytes(linked_module));
}
fn linkModule(self: *SpirV, a: Allocator, module: []Word, progress: *std.Progress.Node) ![]Word {
fn linkModule(self: *SpirV, a: Allocator, module: []Word, progress: std.Progress.Node) ![]Word {
_ = self;
const lower_invocation_globals = @import("SpirV/lower_invocation_globals.zig");

View File

@ -418,9 +418,8 @@ const EntityHashContext = struct {
}
};
pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule, progress: *std.Progress.Node) !void {
var sub_node = progress.start("deduplicate", 0);
sub_node.activate();
pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule, progress: std.Progress.Node) !void {
const sub_node = progress.start("deduplicate", 0);
defer sub_node.end();
var arena = std.heap.ArenaAllocator.init(parser.a);

View File

@ -682,9 +682,8 @@ const ModuleBuilder = struct {
}
};
pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule, progress: *std.Progress.Node) !void {
var sub_node = progress.start("Lower invocation globals", 6);
sub_node.activate();
pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule, progress: std.Progress.Node) !void {
const sub_node = progress.start("Lower invocation globals", 6);
defer sub_node.end();
var arena = std.heap.ArenaAllocator.init(parser.a);

View File

@ -255,9 +255,8 @@ fn removeIdsFromMap(a: Allocator, map: anytype, info: ModuleInfo, alive_marker:
}
}
pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule, progress: *std.Progress.Node) !void {
var sub_node = progress.start("Prune unused IDs", 0);
sub_node.activate();
pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule, progress: std.Progress.Node) !void {
const sub_node = progress.start("Prune unused IDs", 0);
defer sub_node.end();
var arena = std.heap.ArenaAllocator.init(parser.a);

View File

@ -2464,7 +2464,7 @@ fn appendDummySegment(wasm: *Wasm) !void {
});
}
pub fn flush(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void {
pub fn flush(wasm: *Wasm, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void {
const comp = wasm.base.comp;
const use_lld = build_options.have_llvm and comp.config.use_lld;
@ -2475,7 +2475,7 @@ pub fn flush(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) link.
}
/// Uses the in-house linker to link one or multiple object -and archive files into a WebAssembly binary.
pub fn flushModule(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void {
pub fn flushModule(wasm: *Wasm, arena: Allocator, prog_node: std.Progress.Node) link.File.FlushError!void {
const tracy = trace(@src());
defer tracy.end();
@ -2486,8 +2486,7 @@ pub fn flushModule(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node)
if (use_lld) return;
}
var sub_prog_node = prog_node.start("Wasm Flush", 0);
sub_prog_node.activate();
const sub_prog_node = prog_node.start("Wasm Flush", 0);
defer sub_prog_node.end();
const directory = wasm.base.emit.directory; // Just an alias to make it shorter to type.
@ -3323,7 +3322,7 @@ fn emitImport(wasm: *Wasm, writer: anytype, import: types.Import) !void {
}
}
fn linkWithLLD(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) !void {
fn linkWithLLD(wasm: *Wasm, arena: Allocator, prog_node: std.Progress.Node) !void {
const tracy = trace(@src());
defer tracy.end();
@ -3350,9 +3349,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) !vo
}
} else null;
var sub_prog_node = prog_node.start("LLD Link", 0);
sub_prog_node.activate();
sub_prog_node.context.refresh();
const sub_prog_node = prog_node.start("LLD Link", 0);
defer sub_prog_node.end();
const is_obj = comp.config.output_mode == .Obj;

View File

@ -3404,11 +3404,16 @@ fn buildOutputType(
},
}
const root_prog_node = std.Progress.start(.{
.disable_printing = (color == .off),
});
defer root_prog_node.end();
if (arg_mode == .translate_c) {
return cmdTranslateC(comp, arena, null);
return cmdTranslateC(comp, arena, null, root_prog_node);
}
updateModule(comp, color) catch |err| switch (err) {
updateModule(comp, color, root_prog_node) catch |err| switch (err) {
error.SemanticAnalyzeFail => {
assert(listen == .none);
saveState(comp, debug_incremental);
@ -4028,22 +4033,7 @@ fn serve(
var child_pid: ?std.process.Child.Id = null;
var progress: std.Progress = .{
.terminal = null,
.root = .{
.context = undefined,
.parent = null,
.name = "",
.unprotected_estimated_total_items = 0,
.unprotected_completed_items = 0,
},
.columns_written = 0,
.prev_refresh_timestamp = 0,
.timer = null,
.done = false,
};
const main_progress_node = &progress.root;
main_progress_node.context = &progress;
const main_progress_node = std.Progress.start(.{});
while (true) {
const hdr = try server.receiveMessage();
@ -4051,7 +4041,6 @@ fn serve(
switch (hdr.tag) {
.exit => return cleanExit(),
.update => {
assert(main_progress_node.recently_updated_child == null);
tracy.frameMark();
if (arg_mode == .translate_c) {
@ -4059,7 +4048,7 @@ fn serve(
defer arena_instance.deinit();
const arena = arena_instance.allocator();
var output: Compilation.CImportResult = undefined;
try cmdTranslateC(comp, arena, &output);
try cmdTranslateC(comp, arena, &output, main_progress_node);
defer output.deinit(gpa);
if (output.errors.errorMessageCount() != 0) {
try server.serveErrorBundle(output.errors);
@ -4075,21 +4064,7 @@ fn serve(
try comp.makeBinFileWritable();
}
if (builtin.single_threaded) {
try comp.update(main_progress_node);
} else {
var reset: std.Thread.ResetEvent = .{};
var progress_thread = try std.Thread.spawn(.{}, progressThread, .{
&progress, &server, &reset,
});
defer {
reset.set();
progress_thread.join();
}
try comp.update(main_progress_node);
}
try comp.update(main_progress_node);
try comp.makeBinFileExecutable();
try serveUpdateResults(&server, comp);
@ -4116,7 +4091,6 @@ fn serve(
},
.hot_update => {
tracy.frameMark();
assert(main_progress_node.recently_updated_child == null);
if (child_pid) |pid| {
try comp.hotCodeSwap(main_progress_node, pid);
try serveUpdateResults(&server, comp);
@ -4146,63 +4120,6 @@ fn serve(
}
}
fn progressThread(progress: *std.Progress, server: *const Server, reset: *std.Thread.ResetEvent) void {
while (true) {
if (reset.timedWait(500 * std.time.ns_per_ms)) |_| {
// The Compilation update has completed.
return;
} else |err| switch (err) {
error.Timeout => {},
}
var buf: std.BoundedArray(u8, 160) = .{};
{
progress.update_mutex.lock();
defer progress.update_mutex.unlock();
var need_ellipse = false;
var maybe_node: ?*std.Progress.Node = &progress.root;
while (maybe_node) |node| {
if (need_ellipse) {
buf.appendSlice("... ") catch {};
}
need_ellipse = false;
const eti = @atomicLoad(usize, &node.unprotected_estimated_total_items, .monotonic);
const completed_items = @atomicLoad(usize, &node.unprotected_completed_items, .monotonic);
const current_item = completed_items + 1;
if (node.name.len != 0 or eti > 0) {
if (node.name.len != 0) {
buf.appendSlice(node.name) catch {};
need_ellipse = true;
}
if (eti > 0) {
if (need_ellipse) buf.appendSlice(" ") catch {};
buf.writer().print("[{d}/{d}] ", .{ current_item, eti }) catch {};
need_ellipse = false;
} else if (completed_items != 0) {
if (need_ellipse) buf.appendSlice(" ") catch {};
buf.writer().print("[{d}] ", .{current_item}) catch {};
need_ellipse = false;
}
}
maybe_node = @atomicLoad(?*std.Progress.Node, &node.recently_updated_child, .acquire);
}
}
const progress_string = buf.slice();
server.serveMessage(.{
.tag = .progress,
.bytes_len = @as(u32, @intCast(progress_string.len)),
}, &.{
progress_string,
}) catch |err| {
fatal("unable to write to client: {s}", .{@errorName(err)});
};
}
}
fn serveUpdateResults(s: *Server, comp: *Compilation) !void {
const gpa = comp.gpa;
var error_bundle = try comp.getAllErrorsAlloc();
@ -4469,25 +4386,8 @@ fn runOrTestHotSwap(
}
}
fn updateModule(comp: *Compilation, color: Color) !void {
{
// If the terminal is dumb, we dont want to show the user all the output.
var progress: std.Progress = .{ .dont_print_on_dumb = true };
const main_progress_node = progress.start("", 0);
defer main_progress_node.end();
switch (color) {
.off => {
progress.terminal = null;
},
.on => {
progress.terminal = std.io.getStdErr();
progress.supports_ansi_escape_codes = true;
},
.auto => {},
}
try comp.update(main_progress_node);
}
fn updateModule(comp: *Compilation, color: Color, prog_node: std.Progress.Node) !void {
try comp.update(prog_node);
var errors = try comp.getAllErrorsAlloc();
defer errors.deinit(comp.gpa);
@ -4498,7 +4398,12 @@ fn updateModule(comp: *Compilation, color: Color) !void {
}
}
fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilation.CImportResult) !void {
fn cmdTranslateC(
comp: *Compilation,
arena: Allocator,
fancy_output: ?*Compilation.CImportResult,
prog_node: std.Progress.Node,
) !void {
if (build_options.only_core_functionality) @panic("@translate-c is not available in a zig2.c build");
const color: Color = .auto;
assert(comp.c_source_files.len == 1);
@ -4559,6 +4464,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilati
.root_src_path = "aro_translate_c.zig",
.depend_on_aro = true,
.capture = &stdout,
.progress_node = prog_node,
});
break :f stdout;
},
@ -4736,8 +4642,6 @@ const usage_build =
;
fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
var progress: std.Progress = .{ .dont_print_on_dumb = true };
var build_file: ?[]const u8 = null;
var override_lib_dir: ?[]const u8 = try EnvVar.ZIG_LIB_DIR.get(arena);
var override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena);
@ -4798,6 +4702,8 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
const results_tmp_file_nonce = Package.Manifest.hex64(std.crypto.random.int(u64));
try child_argv.append("-Z" ++ results_tmp_file_nonce);
var color: Color = .auto;
{
var i: usize = 0;
while (i < args.len) : (i += 1) {
@ -4882,6 +4788,14 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
verbose_cimport = true;
} else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) {
verbose_llvm_cpu_features = true;
} else if (mem.eql(u8, arg, "--color")) {
if (i + 1 >= args.len) fatal("expected [auto|on|off] after {s}", .{arg});
i += 1;
color = std.meta.stringToEnum(Color, args[i]) orelse {
fatal("expected [auto|on|off] after {s}, found '{s}'", .{ arg, args[i] });
};
try child_argv.appendSlice(&.{ arg, args[i] });
continue;
} else if (mem.eql(u8, arg, "--seed")) {
if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
i += 1;
@ -4895,7 +4809,11 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
const work_around_btrfs_bug = native_os == .linux and
EnvVar.ZIG_BTRFS_WORKAROUND.isSet();
const color: Color = .auto;
const root_prog_node = std.Progress.start(.{
.disable_printing = (color == .off),
.root_name = "Compile Build Script",
});
defer root_prog_node.end();
const target_query: std.Target.Query = .{};
const resolved_target: Package.Module.ResolvedTarget = .{
@ -5051,8 +4969,8 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
config,
);
} else {
const root_prog_node = progress.start("Fetch Packages", 0);
defer root_prog_node.end();
const fetch_prog_node = root_prog_node.start("Fetch Packages", 0);
defer fetch_prog_node.end();
var job_queue: Package.Fetch.JobQueue = .{
.http_client = &http_client,
@ -5093,7 +5011,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
.lazy_status = .eager,
.parent_package_root = build_mod.root,
.parent_manifest_ast = null,
.prog_node = root_prog_node,
.prog_node = fetch_prog_node,
.job_queue = &job_queue,
.omit_missing_hash_error = true,
.allow_missing_paths_field = false,
@ -5232,7 +5150,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
};
defer comp.destroy();
updateModule(comp, color) catch |err| switch (err) {
updateModule(comp, color, root_prog_node) catch |err| switch (err) {
error.SemanticAnalyzeFail => process.exit(2),
else => |e| return e,
};
@ -5250,7 +5168,12 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
child.stdout_behavior = .Inherit;
child.stderr_behavior = .Inherit;
const term = try child.spawnAndWait();
const term = t: {
std.debug.lockStdErr();
defer std.debug.unlockStdErr();
break :t try child.spawnAndWait();
};
switch (term) {
.Exited => |code| {
if (code == 0) return cleanExit();
@ -5326,8 +5249,9 @@ const JitCmdOptions = struct {
prepend_zig_exe_path: bool = false,
depend_on_aro: bool = false,
capture: ?*[]u8 = null,
/// Send progress and error bundles via std.zig.Server over stdout
/// Send error bundles via std.zig.Server over stdout
server: bool = false,
progress_node: ?std.Progress.Node = null,
};
fn jitCmd(
@ -5337,6 +5261,9 @@ fn jitCmd(
options: JitCmdOptions,
) !void {
const color: Color = .auto;
const root_prog_node = if (options.progress_node) |node| node else std.Progress.start(.{
.disable_printing = (color == .off),
});
const target_query: std.Target.Query = .{};
const resolved_target: Package.Module.ResolvedTarget = .{
@ -5473,39 +5400,14 @@ fn jitCmd(
};
defer comp.destroy();
if (options.server and !builtin.single_threaded) {
var reset: std.Thread.ResetEvent = .{};
var progress: std.Progress = .{
.terminal = null,
.root = .{
.context = undefined,
.parent = null,
.name = "",
.unprotected_estimated_total_items = 0,
.unprotected_completed_items = 0,
},
.columns_written = 0,
.prev_refresh_timestamp = 0,
.timer = null,
.done = false,
};
const main_progress_node = &progress.root;
main_progress_node.context = &progress;
if (options.server) {
var server = std.zig.Server{
.out = std.io.getStdOut(),
.in = undefined, // won't be receiving messages
.receive_fifo = undefined, // won't be receiving messages
};
var progress_thread = try std.Thread.spawn(.{}, progressThread, .{
&progress, &server, &reset,
});
defer {
reset.set();
progress_thread.join();
}
try comp.update(main_progress_node);
try comp.update(root_prog_node);
var error_bundle = try comp.getAllErrorsAlloc();
defer error_bundle.deinit(comp.gpa);
@ -5514,7 +5416,7 @@ fn jitCmd(
process.exit(2);
}
} else {
updateModule(comp, color) catch |err| switch (err) {
updateModule(comp, color, root_prog_node) catch |err| switch (err) {
error.SemanticAnalyzeFail => process.exit(2),
else => |e| return e,
};
@ -6963,8 +6865,9 @@ fn cmdFetch(
try http_client.initDefaultProxies(arena);
var progress: std.Progress = .{ .dont_print_on_dumb = true };
const root_prog_node = progress.start("Fetch", 0);
var root_prog_node = std.Progress.start(.{
.root_name = "Fetch",
});
defer root_prog_node.end();
var global_cache_directory: Compilation.Directory = l: {
@ -7028,8 +6931,8 @@ fn cmdFetch(
const hex_digest = Package.Manifest.hexDigest(fetch.actual_hash);
progress.done = true;
progress.refresh();
root_prog_node.end();
root_prog_node = .{ .index = .none };
const name = switch (save) {
.no => {

View File

@ -16,7 +16,7 @@ pub const CRTFile = enum {
mingw32_lib,
};
pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progress.Node) !void {
pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: std.Progress.Node) !void {
if (!build_options.have_llvm) {
return error.ZigCompilerNotBuiltWithLLVMExtensions;
}
@ -234,8 +234,8 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
const include_dir = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "mingw", "def-include" });
if (comp.verbose_cc) print: {
std.debug.getStderrMutex().lock();
defer std.debug.getStderrMutex().unlock();
std.debug.lockStdErr();
defer std.debug.unlockStdErr();
const stderr = std.io.getStdErr().writer();
nosuspend stderr.print("def file: {s}\n", .{def_file_path}) catch break :print;
nosuspend stderr.print("include dir: {s}\n", .{include_dir}) catch break :print;

View File

@ -19,7 +19,7 @@ pub const CRTFile = enum {
libc_so,
};
pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progress.Node) !void {
pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: std.Progress.Node) !void {
if (!build_options.have_llvm) {
return error.ZigCompilerNotBuiltWithLLVMExtensions;
}

View File

@ -57,7 +57,7 @@ pub fn execModelCrtFileFullName(wasi_exec_model: std.builtin.WasiExecModel) []co
};
}
pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progress.Node) !void {
pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: std.Progress.Node) !void {
if (!build_options.have_llvm) {
return error.ZigCompilerNotBuiltWithLLVMExtensions;
}

View File

@ -561,7 +561,7 @@ pub fn lowerToTranslateCSteps(
for (self.translate.items) |case| switch (case.kind) {
.run => |output| {
if (translate_c_options.skip_run_translated_c) continue;
const annotated_case_name = b.fmt("run-translated-c {s}", .{case.name});
const annotated_case_name = b.fmt("run-translated-c {s}", .{case.name});
for (test_filters) |test_filter| {
if (std.mem.indexOf(u8, annotated_case_name, test_filter)) |_| break;
} else if (test_filters.len > 0) continue;

View File

@ -91,6 +91,7 @@ pub fn addCase(self: *RunTranslatedCContext, case: *const TestCase) void {
run.expectStdErrEqual("");
}
run.expectStdOutEqual(case.expected_stdout);
run.skip_foreign_checks = true;
self.step.dependOn(&run.step);
}

View File

@ -80,7 +80,7 @@ pub fn build(b: *std.Build) void {
test_step.dependOn(&wrapper_header.step);
}
fn compare_headers(step: *std.Build.Step, prog_node: *std.Progress.Node) !void {
fn compare_headers(step: *std.Build.Step, prog_node: std.Progress.Node) !void {
_ = prog_node;
const allocator = step.owner.allocator;
const expected_fmt = "expected_{s}";

View File

@ -21,6 +21,7 @@ pub fn build(b: *std.Build) void {
const run = b.addRunArtifact(main);
run.clearEnvironment();
run.disable_zig_progress = true;
test_step.dependOn(&run.step);
}