Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

introduce a new tool for testing incremental compilation #20688

Merged
merged 7 commits into from
Jul 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 3 additions & 12 deletions lib/std/Build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2522,7 +2522,7 @@ pub const InstallDir = union(enum) {
/// function.
pub fn makeTempPath(b: *Build) []const u8 {
const rand_int = std.crypto.random.int(u64);
const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ hex64(rand_int);
const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(rand_int);
const result_path = b.cache_root.join(b.allocator, &.{tmp_dir_sub_path}) catch @panic("OOM");
b.cache_root.handle.makePath(tmp_dir_sub_path) catch |err| {
std.debug.print("unable to make tmp path '{s}': {s}\n", .{
Expand All @@ -2532,18 +2532,9 @@ pub fn makeTempPath(b: *Build) []const u8 {
return result_path;
}

/// There are a few copies of this function in miscellaneous places. Would be nice to find
/// a home for them.
/// Deprecated; use `std.fmt.hex` instead.
pub fn hex64(x: u64) [16]u8 {
const hex_charset = "0123456789abcdef";
var result: [16]u8 = undefined;
var i: usize = 0;
while (i < 8) : (i += 1) {
const byte: u8 = @truncate(x >> @as(u6, @intCast(8 * i)));
result[i * 2 + 0] = hex_charset[byte >> 4];
result[i * 2 + 1] = hex_charset[byte & 15];
}
return result;
return std.fmt.hex(x);
}

/// A pair of target query and fully resolved target.
Expand Down
2 changes: 1 addition & 1 deletion lib/std/Build/Step/Options.zig
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {

const rand_int = std.crypto.random.int(u64);
const tmp_sub_path = "tmp" ++ fs.path.sep_str ++
std.Build.hex64(rand_int) ++ fs.path.sep_str ++
std.fmt.hex(rand_int) ++ fs.path.sep_str ++
basename;
const tmp_sub_path_dirname = fs.path.dirname(tmp_sub_path).?;

Expand Down
2 changes: 1 addition & 1 deletion lib/std/Build/Step/Run.zig
Original file line number Diff line number Diff line change
Expand Up @@ -743,7 +743,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {

// We do not know the final output paths yet, use temp paths to run the command.
const rand_int = std.crypto.random.int(u64);
const tmp_dir_path = "tmp" ++ fs.path.sep_str ++ std.Build.hex64(rand_int);
const tmp_dir_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(rand_int);

for (output_placeholders.items) |placeholder| {
const output_components = .{ tmp_dir_path, placeholder.output.basename };
Expand Down
29 changes: 29 additions & 0 deletions lib/std/fmt.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2718,3 +2718,32 @@ test "recursive format function" {
var r = R{ .Leaf = 1 };
try expectFmt("Leaf(1)\n", "{}\n", .{&r});
}

pub const hex_charset = "0123456789abcdef";

/// Converts an unsigned integer of any multiple of u8 to an array of lowercase
/// hex bytes, little endian.
pub fn hex(x: anytype) [@sizeOf(@TypeOf(x)) * 2]u8 {
comptime assert(@typeInfo(@TypeOf(x)).Int.signedness == .unsigned);
var result: [@sizeOf(@TypeOf(x)) * 2]u8 = undefined;
var i: usize = 0;
while (i < result.len / 2) : (i += 1) {
const byte: u8 = @truncate(x >> @intCast(8 * i));
result[i * 2 + 0] = hex_charset[byte >> 4];
result[i * 2 + 1] = hex_charset[byte & 15];
}
return result;
}

test hex {
{
const x = hex(@as(u32, 0xdeadbeef));
try std.testing.expect(x.len == 8);
try std.testing.expectEqualStrings("efbeadde", &x);
}
{
const s = "[" ++ hex(@as(u64, 0x12345678_abcdef00)) ++ "]";
try std.testing.expect(s.len == 18);
try std.testing.expectEqualStrings("[00efcdab78563412]", s);
}
}
6 changes: 6 additions & 0 deletions lib/std/process.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2032,3 +2032,9 @@ pub fn createWindowsEnvBlock(allocator: mem.Allocator, env_map: *const EnvMap) !
i += 1;
return try allocator.realloc(result, i);
}

/// Logs an error and then terminates the process with exit code 1.
pub fn fatal(comptime format: []const u8, format_arguments: anytype) noreturn {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this move. Wouldn't this be better on std.log itself? That is what Go does if that counts for anything https://pkg.go.dev/log#Fatal

Copy link
Member

@mlugg mlugg Jul 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What another language does is entirely irrelevant, especially one as different as Go. Why would this live in std.log? Just because it happens to use that API doesn't mean it's part of it. std.process seems like an entirely reasonable place for this to live given its other task of terminating the process with exit code 1.

Copy link
Contributor

@sno2 sno2 Jul 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Go and Zig both allow creating custom loggers. This is important because I would like to be able to call fatal on my custom logger without duplicating this function.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if std.log.fatal was going to exist, i would still expect this one to exist and for std.log.fatal to call it

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it belongs in process since it exits the process.

std.log.err(format, format_arguments);
exit(1);
}
6 changes: 2 additions & 4 deletions lib/std/zig.zig
Original file line number Diff line number Diff line change
Expand Up @@ -667,10 +667,8 @@ pub fn parseTargetQueryOrReportFatalError(
};
}

pub fn fatal(comptime format: []const u8, args: anytype) noreturn {
std.log.err(format, args);
std.process.exit(1);
}
/// Deprecated; see `std.process.fatal`.
pub const fatal = std.process.fatal;

/// Collects all the environment variables that Zig could possibly inspect, so
/// that we can do reflection on this and print them with `zig env`.
Expand Down
5 changes: 5 additions & 0 deletions lib/std/zig/Server.zig
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ pub fn deinit(s: *Server) void {
pub fn receiveMessage(s: *Server) !InMessage.Header {
const Header = InMessage.Header;
const fifo = &s.receive_fifo;
var last_amt_zero = false;

while (true) {
const buf = fifo.readableSlice(0);
Expand Down Expand Up @@ -136,6 +137,10 @@ pub fn receiveMessage(s: *Server) !InMessage.Header {
const write_buffer = try fifo.writableWithSize(256);
const amt = try s.in.read(write_buffer);
fifo.update(amt);
if (amt == 0) {
if (last_amt_zero) return error.BrokenPipe;
last_amt_zero = true;
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/Compilation.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2106,7 +2106,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
const tmp_artifact_directory = d: {
const s = std.fs.path.sep_str;
tmp_dir_rand_int = std.crypto.random.int(u64);
const tmp_dir_sub_path = "tmp" ++ s ++ Package.Manifest.hex64(tmp_dir_rand_int);
const tmp_dir_sub_path = "tmp" ++ s ++ std.fmt.hex(tmp_dir_rand_int);

const path = try comp.local_cache_directory.join(gpa, &.{tmp_dir_sub_path});
errdefer gpa.free(path);
Expand Down Expand Up @@ -2298,7 +2298,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
} else unreachable;

const s = std.fs.path.sep_str;
const tmp_dir_sub_path = "tmp" ++ s ++ Package.Manifest.hex64(tmp_dir_rand_int);
const tmp_dir_sub_path = "tmp" ++ s ++ std.fmt.hex(tmp_dir_rand_int);
const o_sub_path = "o" ++ s ++ digest;

// Work around windows `AccessDenied` if any files within this
Expand Down
2 changes: 1 addition & 1 deletion src/Package/Fetch.zig
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ fn runResource(
const s = fs.path.sep_str;
const cache_root = f.job_queue.global_cache;
const rand_int = std.crypto.random.int(u64);
const tmp_dir_sub_path = "tmp" ++ s ++ Manifest.hex64(rand_int);
const tmp_dir_sub_path = "tmp" ++ s ++ std.fmt.hex(rand_int);

const package_sub_path = blk: {
const tmp_directory_path = try cache_root.join(arena, &.{tmp_dir_sub_path});
Expand Down
35 changes: 9 additions & 26 deletions src/Package/Manifest.zig
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
const Manifest = @This();
const std = @import("std");
const mem = std.mem;
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const Ast = std.zig.Ast;
const testing = std.testing;
const hex_charset = std.fmt.hex_charset;

pub const max_bytes = 10 * 1024 * 1024;
pub const basename = "build.zig.zon";
pub const Hash = std.crypto.hash.sha2.Sha256;
Expand Down Expand Up @@ -153,24 +162,6 @@ pub fn copyErrorsIntoBundle(
}
}

const hex_charset = "0123456789abcdef";

pub fn hex64(x: u64) [16]u8 {
var result: [16]u8 = undefined;
var i: usize = 0;
while (i < 8) : (i += 1) {
const byte = @as(u8, @truncate(x >> @as(u6, @intCast(8 * i))));
result[i * 2 + 0] = hex_charset[byte >> 4];
result[i * 2 + 1] = hex_charset[byte & 15];
}
return result;
}

test hex64 {
const s = "[" ++ hex64(0x12345678_abcdef00) ++ "]";
try std.testing.expectEqualStrings("[00efcdab78563412]", s);
}

pub fn hexDigest(digest: Digest) MultiHashHexDigest {
var result: MultiHashHexDigest = undefined;

Expand Down Expand Up @@ -590,14 +581,6 @@ const Parse = struct {
}
};

const Manifest = @This();
const std = @import("std");
const mem = std.mem;
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const Ast = std.zig.Ast;
const testing = std.testing;

test "basic" {
const gpa = testing.allocator;

Expand Down
2 changes: 1 addition & 1 deletion src/link.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1031,7 +1031,7 @@ pub fn spawnLld(
error.NameTooLong => err: {
const s = fs.path.sep_str;
const rand_int = std.crypto.random.int(u64);
const rsp_path = "tmp" ++ s ++ Package.Manifest.hex64(rand_int) ++ ".rsp";
const rsp_path = "tmp" ++ s ++ std.fmt.hex(rand_int) ++ ".rsp";

const rsp_file = try comp.local_cache_directory.handle.createFileZ(rsp_path, .{});
defer comp.local_cache_directory.handle.deleteFileZ(rsp_path) catch |err|
Expand Down
5 changes: 2 additions & 3 deletions src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4746,7 +4746,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
// the strategy is to choose a temporary file name ahead of time, and then
// read this file in the parent to obtain the results, in the case the child
// exits with code 3.
const results_tmp_file_nonce = Package.Manifest.hex64(std.crypto.random.int(u64));
const results_tmp_file_nonce = std.fmt.hex(std.crypto.random.int(u64));
try child_argv.append("-Z" ++ results_tmp_file_nonce);

var color: Color = .auto;
Expand Down Expand Up @@ -7196,8 +7196,7 @@ fn createDependenciesModule(
// Atomically create the file in a directory named after the hash of its contents.
const basename = "dependencies.zig";
const rand_int = std.crypto.random.int(u64);
const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++
Package.Manifest.hex64(rand_int);
const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(rand_int);
{
var tmp_dir = try local_cache_directory.handle.makeOpenPath(tmp_dir_sub_path, .{});
defer tmp_dir.close();
Expand Down
15 changes: 15 additions & 0 deletions test/incremental/hello
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#target=x86_64-linux
#update=initial version
#file=main.zig
const std = @import("std");
pub fn main() !void {
try std.io.getStdOut().writeAll("good morning\n");
}
#expect_stdout="good morning\n"
#update=change the string
#file=main.zig
const std = @import("std");
pub fn main() !void {
try std.io.getStdOut().writeAll("おはようございます\n");
}
#expect_stdout="おはようございます\n"
Loading