From fae6290387850bfddbe4e9c1255750a65568b763 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Wed, 10 May 2023 01:52:33 -0400 Subject: Cache: fix race condition When checking a cache entry with no input files for a hit, if `createFile` returned `error.WouldBlock` we would forget about the fact that the file has been created, and all future checks will assume that a cache hit has happened, even though one never has or does, leading to rare `FileNotFound` errors trying the access the protected files. This fix works by writing an extra byte to the manifest file to distinguish hits and misses when there no input files to write. --- lib/std/Build/Cache.zig | 124 +++++++++++++++++++----------------------------- 1 file changed, 48 insertions(+), 76 deletions(-) (limited to 'lib/std/Build/Cache.zig') diff --git a/lib/std/Build/Cache.zig b/lib/std/Build/Cache.zig index 9139311785..a686e2d9d9 100644 --- a/lib/std/Build/Cache.zig +++ b/lib/std/Build/Cache.zig @@ -145,6 +145,8 @@ pub const bin_digest_len = 16; pub const hex_digest_len = bin_digest_len * 2; pub const BinDigest = [bin_digest_len]u8; +/// This is currently just an arbitrary non-empty string that can't match another manifest line. +const manifest_header = "0"; const manifest_file_size_max = 50 * 1024 * 1024; /// The type used for hashing file contents. Currently, this is SipHash128(1, 3), because it @@ -152,8 +154,15 @@ const manifest_file_size_max = 50 * 1024 * 1024; /// fastest options right now. pub const Hasher = crypto.auth.siphash.SipHash128(1, 3); -/// Initial state, that can be copied. -pub const hasher_init: Hasher = Hasher.init(&[_]u8{0} ** Hasher.key_length); +/// Initial state with random bytes, that can be copied. +/// Refresh this with new random bytes when the manifest +/// format is modified in a non-backwards-compatible way. +pub const hasher_init: Hasher = Hasher.init(&[_]u8{ + 0x33, 0x52, 0xa2, 0x84, + 0xcf, 0x17, 0x56, 0x57, + 0x01, 0xbb, 0xcd, 0xe4, + 0x77, 0xd6, 0xf0, 0x60, +}); pub const File = struct { prefixed_path: ?PrefixedPath, @@ -391,72 +400,29 @@ pub const Manifest = struct { @memcpy(manifest_file_path[0..self.hex_digest.len], &self.hex_digest); manifest_file_path[hex_digest_len..][0..ext.len].* = ext.*; - if (self.files.items.len == 0) { - // If there are no file inputs, we check if the manifest file exists instead of - // comparing the hashes on the files used for the cached item - while (true) { - if (self.cache.manifest_dir.openFile(&manifest_file_path, .{ - .mode = .read_write, - .lock = .Exclusive, - .lock_nonblocking = self.want_shared_lock, - })) |manifest_file| { - self.manifest_file = manifest_file; - self.have_exclusive_lock = true; - break; - } else |open_err| switch (open_err) { - error.WouldBlock => { - self.manifest_file = try self.cache.manifest_dir.openFile(&manifest_file_path, .{ - .lock = .Shared, - }); - break; - }, - error.FileNotFound => { - if (self.cache.manifest_dir.createFile(&manifest_file_path, .{ - .read = true, - .truncate = false, - .lock = .Exclusive, - .lock_nonblocking = self.want_shared_lock, - })) |manifest_file| { - self.manifest_file = manifest_file; - self.manifest_dirty = true; - self.have_exclusive_lock = true; - return false; // cache miss; exclusive lock already held - } else |err| switch (err) { - // There are no dir components, so you would think - // that this was unreachable, however we have - // observed on macOS two processes racing to do - // openat() with O_CREAT manifest in ENOENT. - error.WouldBlock, error.FileNotFound => continue, - else => |e| return e, - } - }, - else => |e| return e, - } - } - } else { - while (true) { - if (self.cache.manifest_dir.createFile(&manifest_file_path, .{ - .read = true, - .truncate = false, - .lock = .Exclusive, - .lock_nonblocking = self.want_shared_lock, - })) |manifest_file| { - self.manifest_file = manifest_file; - self.have_exclusive_lock = true; + while (true) { + if (self.cache.manifest_dir.createFile(&manifest_file_path, .{ + .read = true, + .truncate = false, + .lock = .Exclusive, + .lock_nonblocking = self.want_shared_lock, + })) |manifest_file| { + self.manifest_file = manifest_file; + self.have_exclusive_lock = true; + break; + } else |err| switch (err) { + error.WouldBlock => { + self.manifest_file = try self.cache.manifest_dir.openFile(&manifest_file_path, .{ + .mode = .read_write, + .lock = .Shared, + }); break; - } else |err| switch (err) { - error.WouldBlock => { - self.manifest_file = try self.cache.manifest_dir.openFile(&manifest_file_path, .{ - .lock = .Shared, - }); - break; - }, - // There are no dir components, so you would think that this was - // unreachable, however we have observed on macOS two processes racing - // to do openat() with O_CREAT manifest in ENOENT. - error.FileNotFound => continue, - else => |e| return e, - } + }, + // There are no dir components, so you would think that this was + // unreachable, however we have observed on macOS two processes racing + // to do openat() with O_CREAT manifest in ENOENT. + error.FileNotFound => continue, + else => |e| return e, } } @@ -469,6 +435,18 @@ pub const Manifest = struct { var any_file_changed = false; var line_iter = mem.tokenize(u8, file_contents, "\n"); var idx: usize = 0; + if (if (line_iter.next()) |line| !std.mem.eql(u8, line, manifest_header) else true) { + self.manifest_dirty = true; + while (idx < input_file_count) : (idx += 1) { + const ch_file = &self.files.items[idx]; + self.populateFileHash(ch_file) catch |err| { + self.failed_file_index = idx; + return err; + }; + } + try self.upgradeToExclusiveLock(); + return false; + } while (line_iter.next()) |line| { defer idx += 1; @@ -854,19 +832,13 @@ pub const Manifest = struct { defer contents.deinit(); const writer = contents.writer(); - var encoded_digest: [hex_digest_len]u8 = undefined; - + try writer.writeAll(manifest_header ++ "\n"); for (self.files.items) |file| { - _ = fmt.bufPrint( - &encoded_digest, - "{s}", - .{fmt.fmtSliceHexLower(&file.bin_digest)}, - ) catch unreachable; - try writer.print("{d} {d} {d} {s} {d} {s}\n", .{ + try writer.print("{d} {d} {d} {} {d} {s}\n", .{ file.stat.size, file.stat.inode, file.stat.mtime, - &encoded_digest, + fmt.fmtSliceHexLower(&file.bin_digest), file.prefixed_path.?.prefix, file.prefixed_path.?.sub_path, }); -- cgit v1.2.3 From 6e292f66db8e7b85ea8b116872b3ca074db7885a Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Thu, 11 May 2023 00:51:41 -0400 Subject: Cache: fix unnecessary cache misses With the old logic, it was possible for a bunch of processes to queue up to update a cache entry, and then each to do so one at a time. Now, it rechecks whether there still a cache miss or another process has completed the work in the interim. --- lib/std/Build/Cache.zig | 249 ++++++++++++++++++++++++------------------------ 1 file changed, 126 insertions(+), 123 deletions(-) (limited to 'lib/std/Build/Cache.zig') diff --git a/lib/std/Build/Cache.zig b/lib/std/Build/Cache.zig index a686e2d9d9..17429c0370 100644 --- a/lib/std/Build/Cache.zig +++ b/lib/std/Build/Cache.zig @@ -428,149 +428,151 @@ pub const Manifest = struct { self.want_refresh_timestamp = true; - const file_contents = try self.manifest_file.?.reader().readAllAlloc(gpa, manifest_file_size_max); - defer gpa.free(file_contents); - - const input_file_count = self.files.items.len; - var any_file_changed = false; - var line_iter = mem.tokenize(u8, file_contents, "\n"); - var idx: usize = 0; - if (if (line_iter.next()) |line| !std.mem.eql(u8, line, manifest_header) else true) { - self.manifest_dirty = true; - while (idx < input_file_count) : (idx += 1) { - const ch_file = &self.files.items[idx]; - self.populateFileHash(ch_file) catch |err| { - self.failed_file_index = idx; - return err; - }; + while (true) { + const file_contents = try self.manifest_file.?.reader().readAllAlloc(gpa, manifest_file_size_max); + defer gpa.free(file_contents); + + const input_file_count = self.files.items.len; + var any_file_changed = false; + var line_iter = mem.tokenize(u8, file_contents, "\n"); + var idx: usize = 0; + if (if (line_iter.next()) |line| !std.mem.eql(u8, line, manifest_header) else true) { + if (try self.upgradeToExclusiveLock()) continue; + self.manifest_dirty = true; + while (idx < input_file_count) : (idx += 1) { + const ch_file = &self.files.items[idx]; + self.populateFileHash(ch_file) catch |err| { + self.failed_file_index = idx; + return err; + }; + } + return false; } - try self.upgradeToExclusiveLock(); - return false; - } - while (line_iter.next()) |line| { - defer idx += 1; - - const cache_hash_file = if (idx < input_file_count) &self.files.items[idx] else blk: { - const new = try self.files.addOne(gpa); - new.* = .{ - .prefixed_path = null, - .contents = null, - .max_file_size = null, - .stat = undefined, - .bin_digest = undefined, + while (line_iter.next()) |line| { + defer idx += 1; + + const cache_hash_file = if (idx < input_file_count) &self.files.items[idx] else blk: { + const new = try self.files.addOne(gpa); + new.* = .{ + .prefixed_path = null, + .contents = null, + .max_file_size = null, + .stat = undefined, + .bin_digest = undefined, + }; + break :blk new; }; - break :blk new; - }; - var iter = mem.tokenize(u8, line, " "); - const size = iter.next() orelse return error.InvalidFormat; - const inode = iter.next() orelse return error.InvalidFormat; - const mtime_nsec_str = iter.next() orelse return error.InvalidFormat; - const digest_str = iter.next() orelse return error.InvalidFormat; - const prefix_str = iter.next() orelse return error.InvalidFormat; - const file_path = iter.rest(); - - cache_hash_file.stat.size = fmt.parseInt(u64, size, 10) catch return error.InvalidFormat; - cache_hash_file.stat.inode = fmt.parseInt(fs.File.INode, inode, 10) catch return error.InvalidFormat; - cache_hash_file.stat.mtime = fmt.parseInt(i64, mtime_nsec_str, 10) catch return error.InvalidFormat; - _ = fmt.hexToBytes(&cache_hash_file.bin_digest, digest_str) catch return error.InvalidFormat; - const prefix = fmt.parseInt(u8, prefix_str, 10) catch return error.InvalidFormat; - if (prefix >= self.cache.prefixes_len) return error.InvalidFormat; - - if (file_path.len == 0) { - return error.InvalidFormat; - } - if (cache_hash_file.prefixed_path) |pp| { - if (pp.prefix != prefix or !mem.eql(u8, file_path, pp.sub_path)) { + var iter = mem.tokenize(u8, line, " "); + const size = iter.next() orelse return error.InvalidFormat; + const inode = iter.next() orelse return error.InvalidFormat; + const mtime_nsec_str = iter.next() orelse return error.InvalidFormat; + const digest_str = iter.next() orelse return error.InvalidFormat; + const prefix_str = iter.next() orelse return error.InvalidFormat; + const file_path = iter.rest(); + + cache_hash_file.stat.size = fmt.parseInt(u64, size, 10) catch return error.InvalidFormat; + cache_hash_file.stat.inode = fmt.parseInt(fs.File.INode, inode, 10) catch return error.InvalidFormat; + cache_hash_file.stat.mtime = fmt.parseInt(i64, mtime_nsec_str, 10) catch return error.InvalidFormat; + _ = fmt.hexToBytes(&cache_hash_file.bin_digest, digest_str) catch return error.InvalidFormat; + const prefix = fmt.parseInt(u8, prefix_str, 10) catch return error.InvalidFormat; + if (prefix >= self.cache.prefixes_len) return error.InvalidFormat; + + if (file_path.len == 0) { return error.InvalidFormat; } - } - - if (cache_hash_file.prefixed_path == null) { - cache_hash_file.prefixed_path = .{ - .prefix = prefix, - .sub_path = try gpa.dupe(u8, file_path), - }; - } - - const pp = cache_hash_file.prefixed_path.?; - const dir = self.cache.prefixes()[pp.prefix].handle; - const this_file = dir.openFile(pp.sub_path, .{ .mode = .read_only }) catch |err| switch (err) { - error.FileNotFound => { - try self.upgradeToExclusiveLock(); - return false; - }, - else => return error.CacheUnavailable, - }; - defer this_file.close(); - - const actual_stat = this_file.stat() catch |err| { - self.failed_file_index = idx; - return err; - }; - const size_match = actual_stat.size == cache_hash_file.stat.size; - const mtime_match = actual_stat.mtime == cache_hash_file.stat.mtime; - const inode_match = actual_stat.inode == cache_hash_file.stat.inode; + if (cache_hash_file.prefixed_path) |pp| { + if (pp.prefix != prefix or !mem.eql(u8, file_path, pp.sub_path)) { + return error.InvalidFormat; + } + } - if (!size_match or !mtime_match or !inode_match) { - self.manifest_dirty = true; + if (cache_hash_file.prefixed_path == null) { + cache_hash_file.prefixed_path = .{ + .prefix = prefix, + .sub_path = try gpa.dupe(u8, file_path), + }; + } - cache_hash_file.stat = .{ - .size = actual_stat.size, - .mtime = actual_stat.mtime, - .inode = actual_stat.inode, + const pp = cache_hash_file.prefixed_path.?; + const dir = self.cache.prefixes()[pp.prefix].handle; + const this_file = dir.openFile(pp.sub_path, .{ .mode = .read_only }) catch |err| switch (err) { + error.FileNotFound => { + if (try self.upgradeToExclusiveLock()) continue; + return false; + }, + else => return error.CacheUnavailable, }; + defer this_file.close(); - if (self.isProblematicTimestamp(cache_hash_file.stat.mtime)) { - // The actual file has an unreliable timestamp, force it to be hashed - cache_hash_file.stat.mtime = 0; - cache_hash_file.stat.inode = 0; - } - - var actual_digest: BinDigest = undefined; - hashFile(this_file, &actual_digest) catch |err| { + const actual_stat = this_file.stat() catch |err| { self.failed_file_index = idx; return err; }; + const size_match = actual_stat.size == cache_hash_file.stat.size; + const mtime_match = actual_stat.mtime == cache_hash_file.stat.mtime; + const inode_match = actual_stat.inode == cache_hash_file.stat.inode; + + if (!size_match or !mtime_match or !inode_match) { + self.manifest_dirty = true; + + cache_hash_file.stat = .{ + .size = actual_stat.size, + .mtime = actual_stat.mtime, + .inode = actual_stat.inode, + }; + + if (self.isProblematicTimestamp(cache_hash_file.stat.mtime)) { + // The actual file has an unreliable timestamp, force it to be hashed + cache_hash_file.stat.mtime = 0; + cache_hash_file.stat.inode = 0; + } + + var actual_digest: BinDigest = undefined; + hashFile(this_file, &actual_digest) catch |err| { + self.failed_file_index = idx; + return err; + }; + + if (!mem.eql(u8, &cache_hash_file.bin_digest, &actual_digest)) { + cache_hash_file.bin_digest = actual_digest; + // keep going until we have the input file digests + any_file_changed = true; + } + } - if (!mem.eql(u8, &cache_hash_file.bin_digest, &actual_digest)) { - cache_hash_file.bin_digest = actual_digest; - // keep going until we have the input file digests - any_file_changed = true; + if (!any_file_changed) { + self.hash.hasher.update(&cache_hash_file.bin_digest); } } - if (!any_file_changed) { - self.hash.hasher.update(&cache_hash_file.bin_digest); + if (any_file_changed) { + if (try self.upgradeToExclusiveLock()) continue; + // cache miss + // keep the manifest file open + self.unhit(bin_digest, input_file_count); + return false; } - } - if (any_file_changed) { - // cache miss - // keep the manifest file open - self.unhit(bin_digest, input_file_count); - try self.upgradeToExclusiveLock(); - return false; - } + if (idx < input_file_count) { + if (try self.upgradeToExclusiveLock()) continue; + self.manifest_dirty = true; + while (idx < input_file_count) : (idx += 1) { + const ch_file = &self.files.items[idx]; + self.populateFileHash(ch_file) catch |err| { + self.failed_file_index = idx; + return err; + }; + } + return false; + } - if (idx < input_file_count) { - self.manifest_dirty = true; - while (idx < input_file_count) : (idx += 1) { - const ch_file = &self.files.items[idx]; - self.populateFileHash(ch_file) catch |err| { - self.failed_file_index = idx; - return err; - }; + if (self.want_shared_lock) { + try self.downgradeToSharedLock(); } - try self.upgradeToExclusiveLock(); - return false; - } - if (self.want_shared_lock) { - try self.downgradeToSharedLock(); + return true; } - - return true; } pub fn unhit(self: *Manifest, bin_digest: BinDigest, input_file_count: usize) void { @@ -867,8 +869,8 @@ pub const Manifest = struct { self.have_exclusive_lock = false; } - fn upgradeToExclusiveLock(self: *Manifest) !void { - if (self.have_exclusive_lock) return; + fn upgradeToExclusiveLock(self: *Manifest) !bool { + if (self.have_exclusive_lock) return false; assert(self.manifest_file != null); // WASI does not currently support flock, so we bypass it here. @@ -882,6 +884,7 @@ pub const Manifest = struct { try manifest_file.lock(.Exclusive); } self.have_exclusive_lock = true; + return true; } /// Obtain only the data needed to maintain a lock on the manifest file. -- cgit v1.2.3 From 815e53b147a321d0bdb47dc008aa8181f57175ac Mon Sep 17 00:00:00 2001 From: Ryan Liptak Date: Thu, 4 May 2023 18:05:40 -0700 Subject: Update all std.mem.tokenize calls to their appropriate function Everywhere that can now use `tokenizeScalar` should get a nice little performance boost. --- build.zig | 8 ++++---- lib/std/Build.zig | 2 +- lib/std/Build/Cache.zig | 4 ++-- lib/std/Build/Step/CheckObject.zig | 8 ++++---- lib/std/Build/Step/Compile.zig | 6 +++--- lib/std/Build/Step/ConfigHeader.zig | 4 ++-- lib/std/child_process.zig | 4 ++-- lib/std/fs.zig | 2 +- lib/std/fs/path.zig | 26 ++++++++++++------------ lib/std/http/Client.zig | 4 ++-- lib/std/http/Server.zig | 4 ++-- lib/std/net.zig | 6 +++--- lib/std/os.zig | 2 +- lib/std/process.zig | 2 +- lib/std/zig/system/NativePaths.zig | 10 ++++----- lib/std/zig/system/NativeTargetInfo.zig | 4 ++-- src/arch/x86_64/CodeGen.zig | 6 +++--- src/glibc.zig | 2 +- src/libc_installation.zig | 8 ++++---- src/link/Plan9.zig | 2 +- src/print_zir.zig | 2 +- test/behavior/bugs/6456.zig | 2 +- test/src/Cases.zig | 4 ++-- tools/generate_linux_syscalls.zig | 36 ++++++++++++++++----------------- 24 files changed, 79 insertions(+), 79 deletions(-) (limited to 'lib/std/Build/Cache.zig') diff --git a/build.zig b/build.zig index 208d06fe1d..21b323df56 100644 --- a/build.zig +++ b/build.zig @@ -284,7 +284,7 @@ pub fn build(b: *std.Build) !void { // That means we also have to rely on stage1 compiled c++ files. We parse config.h to find // the information passed on to us from cmake. if (cfg.cmake_prefix_path.len > 0) { - var it = mem.tokenize(u8, cfg.cmake_prefix_path, ";"); + var it = mem.tokenizeScalar(u8, cfg.cmake_prefix_path, ';'); while (it.next()) |path| { b.addSearchPrefix(path); } @@ -687,7 +687,7 @@ fn addCxxKnownPath( if (!std.process.can_spawn) return error.RequiredLibraryNotFound; const path_padded = b.exec(&.{ ctx.cxx_compiler, b.fmt("-print-file-name={s}", .{objname}) }); - var tokenizer = mem.tokenize(u8, path_padded, "\r\n"); + var tokenizer = mem.tokenizeAny(u8, path_padded, "\r\n"); const path_unpadded = tokenizer.next().?; if (mem.eql(u8, path_unpadded, objname)) { if (errtxt) |msg| { @@ -710,7 +710,7 @@ fn addCxxKnownPath( } fn addCMakeLibraryList(exe: *std.Build.Step.Compile, list: []const u8) void { - var it = mem.tokenize(u8, list, ";"); + var it = mem.tokenizeScalar(u8, list, ';'); while (it.next()) |lib| { if (mem.startsWith(u8, lib, "-l")) { exe.linkSystemLibrary(lib["-l".len..]); @@ -855,7 +855,7 @@ fn parseConfigH(b: *std.Build, config_h_text: []const u8) ?CMakeConfig { // .prefix = ZIG_LLVM_LINK_MODE parsed manually below }; - var lines_it = mem.tokenize(u8, config_h_text, "\r\n"); + var lines_it = mem.tokenizeAny(u8, config_h_text, "\r\n"); while (lines_it.next()) |line| { inline for (mappings) |mapping| { if (mem.startsWith(u8, line, mapping.prefix)) { diff --git a/lib/std/Build.zig b/lib/std/Build.zig index ca55d23937..4ab5db5c70 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -1358,7 +1358,7 @@ pub fn findProgram(self: *Build, names: []const []const u8, paths: []const []con if (fs.path.isAbsolute(name)) { return name; } - var it = mem.tokenize(u8, PATH, &[_]u8{fs.path.delimiter}); + var it = mem.tokenizeScalar(u8, PATH, fs.path.delimiter); while (it.next()) |path| { const full_path = self.pathJoin(&.{ path, diff --git a/lib/std/Build/Cache.zig b/lib/std/Build/Cache.zig index 17429c0370..7709e5e26c 100644 --- a/lib/std/Build/Cache.zig +++ b/lib/std/Build/Cache.zig @@ -434,7 +434,7 @@ pub const Manifest = struct { const input_file_count = self.files.items.len; var any_file_changed = false; - var line_iter = mem.tokenize(u8, file_contents, "\n"); + var line_iter = mem.tokenizeScalar(u8, file_contents, '\n'); var idx: usize = 0; if (if (line_iter.next()) |line| !std.mem.eql(u8, line, manifest_header) else true) { if (try self.upgradeToExclusiveLock()) continue; @@ -463,7 +463,7 @@ pub const Manifest = struct { break :blk new; }; - var iter = mem.tokenize(u8, line, " "); + var iter = mem.tokenizeScalar(u8, line, ' '); const size = iter.next() orelse return error.InvalidFormat; const inode = iter.next() orelse return error.InvalidFormat; const mtime_nsec_str = iter.next() orelse return error.InvalidFormat; diff --git a/lib/std/Build/Step/CheckObject.zig b/lib/std/Build/Step/CheckObject.zig index c77dc3de36..24ebfef388 100644 --- a/lib/std/Build/Step/CheckObject.zig +++ b/lib/std/Build/Step/CheckObject.zig @@ -103,8 +103,8 @@ const Action = struct { assert(act.tag == .match or act.tag == .not_present); const phrase = act.phrase.resolve(b, step); var candidate_var: ?struct { name: []const u8, value: u64 } = null; - var hay_it = mem.tokenize(u8, mem.trim(u8, haystack, " "), " "); - var needle_it = mem.tokenize(u8, mem.trim(u8, phrase, " "), " "); + var hay_it = mem.tokenizeScalar(u8, mem.trim(u8, haystack, " "), ' '); + var needle_it = mem.tokenizeScalar(u8, mem.trim(u8, phrase, " "), ' '); while (needle_it.next()) |needle_tok| { const hay_tok = hay_it.next() orelse return false; @@ -155,7 +155,7 @@ const Action = struct { var op_stack = std.ArrayList(enum { add, sub, mod, mul }).init(gpa); var values = std.ArrayList(u64).init(gpa); - var it = mem.tokenize(u8, phrase, " "); + var it = mem.tokenizeScalar(u8, phrase, ' '); while (it.next()) |next| { if (mem.eql(u8, next, "+")) { try op_stack.append(.add); @@ -365,7 +365,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { var vars = std.StringHashMap(u64).init(gpa); for (self.checks.items) |chk| { - var it = mem.tokenize(u8, output, "\r\n"); + var it = mem.tokenizeAny(u8, output, "\r\n"); for (chk.actions.items) |act| { switch (act.tag) { .match => { diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig index 2371f49daf..6a05adc1a6 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -777,7 +777,7 @@ fn runPkgConfig(self: *Compile, lib_name: []const u8) ![]const []const u8 { var zig_args = ArrayList([]const u8).init(b.allocator); defer zig_args.deinit(); - var it = mem.tokenize(u8, stdout, " \r\n\t"); + var it = mem.tokenizeAny(u8, stdout, " \r\n\t"); while (it.next()) |tok| { if (mem.eql(u8, tok, "-I")) { const dir = it.next() orelse return error.PkgConfigInvalidOutput; @@ -2017,10 +2017,10 @@ fn execPkgConfigList(self: *std.Build, out_code: *u8) (PkgConfigError || ExecErr const stdout = try self.execAllowFail(&[_][]const u8{ "pkg-config", "--list-all" }, out_code, .Ignore); var list = ArrayList(PkgConfigPkg).init(self.allocator); errdefer list.deinit(); - var line_it = mem.tokenize(u8, stdout, "\r\n"); + var line_it = mem.tokenizeAny(u8, stdout, "\r\n"); while (line_it.next()) |line| { if (mem.trim(u8, line, " \t").len == 0) continue; - var tok_it = mem.tokenize(u8, line, " \t"); + var tok_it = mem.tokenizeAny(u8, line, " \t"); try list.append(PkgConfigPkg{ .name = tok_it.next() orelse return error.PkgConfigInvalidOutput, .desc = tok_it.rest(), diff --git a/lib/std/Build/Step/ConfigHeader.zig b/lib/std/Build/Step/ConfigHeader.zig index f6939e0e38..cd97367218 100644 --- a/lib/std/Build/Step/ConfigHeader.zig +++ b/lib/std/Build/Step/ConfigHeader.zig @@ -257,7 +257,7 @@ fn render_autoconf( try output.appendSlice("\n"); continue; } - var it = std.mem.tokenize(u8, line[1..], " \t\r"); + var it = std.mem.tokenizeAny(u8, line[1..], " \t\r"); const undef = it.next().?; if (!std.mem.eql(u8, undef, "undef")) { try output.appendSlice(line); @@ -304,7 +304,7 @@ fn render_cmake( try output.appendSlice("\n"); continue; } - var it = std.mem.tokenize(u8, line[1..], " \t\r"); + var it = std.mem.tokenizeAny(u8, line[1..], " \t\r"); const cmakedefine = it.next().?; if (!std.mem.eql(u8, cmakedefine, "cmakedefine") and !std.mem.eql(u8, cmakedefine, "cmakedefine01")) diff --git a/lib/std/child_process.zig b/lib/std/child_process.zig index daaa1689bc..d94f5ea000 100644 --- a/lib/std/child_process.zig +++ b/lib/std/child_process.zig @@ -850,7 +850,7 @@ pub const ChildProcess = struct { return original_err; } - var it = mem.tokenize(u16, PATH, &[_]u16{';'}); + var it = mem.tokenizeScalar(u16, PATH, ';'); while (it.next()) |search_path| { dir_buf.clearRetainingCapacity(); try dir_buf.appendSlice(self.allocator, search_path); @@ -1067,7 +1067,7 @@ fn windowsCreateProcessPathExt( // Now we know that at least *a* file matching the wildcard exists, we can loop // through PATHEXT in order and exec any that exist - var ext_it = mem.tokenize(u16, pathext, &[_]u16{';'}); + var ext_it = mem.tokenizeScalar(u16, pathext, ';'); while (ext_it.next()) |ext| { if (!windowsCreateProcessSupportsExtension(ext)) continue; diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 7327a3a913..5aeea8a4aa 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -3021,7 +3021,7 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 { } else if (argv0.len != 0) { // argv[0] is not empty (and not a path): search it inside PATH const PATH = std.os.getenvZ("PATH") orelse return error.FileNotFound; - var path_it = mem.tokenize(u8, PATH, &[_]u8{path.delimiter}); + var path_it = mem.tokenizeScalar(u8, PATH, path.delimiter); while (path_it.next()) |a_path| { var resolved_path_buf: [MAX_PATH_BYTES - 1:0]u8 = undefined; const resolved_path = std.fmt.bufPrintZ(&resolved_path_buf, "{s}/{s}", .{ diff --git a/lib/std/fs/path.zig b/lib/std/fs/path.zig index 4c320ae5cf..e7a28a7615 100644 --- a/lib/std/fs/path.zig +++ b/lib/std/fs/path.zig @@ -358,7 +358,7 @@ pub fn windowsParsePath(path: []const u8) WindowsPath { return relative_path; } - var it = mem.tokenize(u8, path, &[_]u8{this_sep}); + var it = mem.tokenizeScalar(u8, path, this_sep); _ = (it.next() orelse return relative_path); _ = (it.next() orelse return relative_path); return WindowsPath{ @@ -420,8 +420,8 @@ fn networkShareServersEql(ns1: []const u8, ns2: []const u8) bool { const sep1 = ns1[0]; const sep2 = ns2[0]; - var it1 = mem.tokenize(u8, ns1, &[_]u8{sep1}); - var it2 = mem.tokenize(u8, ns2, &[_]u8{sep2}); + var it1 = mem.tokenizeScalar(u8, ns1, sep1); + var it2 = mem.tokenizeScalar(u8, ns2, sep2); // TODO ASCII is wrong, we actually need full unicode support to compare paths. return ascii.eqlIgnoreCase(it1.next().?, it2.next().?); @@ -441,8 +441,8 @@ fn compareDiskDesignators(kind: WindowsPath.Kind, p1: []const u8, p2: []const u8 const sep1 = p1[0]; const sep2 = p2[0]; - var it1 = mem.tokenize(u8, p1, &[_]u8{sep1}); - var it2 = mem.tokenize(u8, p2, &[_]u8{sep2}); + var it1 = mem.tokenizeScalar(u8, p1, sep1); + var it2 = mem.tokenizeScalar(u8, p2, sep2); // TODO ASCII is wrong, we actually need full unicode support to compare paths. return ascii.eqlIgnoreCase(it1.next().?, it2.next().?) and ascii.eqlIgnoreCase(it1.next().?, it2.next().?); @@ -535,7 +535,7 @@ pub fn resolveWindows(allocator: Allocator, paths: []const []const u8) ![]u8 { break :l disk_designator.len; }, .NetworkShare => { - var it = mem.tokenize(u8, paths[first_index], "/\\"); + var it = mem.tokenizeAny(u8, paths[first_index], "/\\"); const server_name = it.next().?; const other_name = it.next().?; @@ -570,7 +570,7 @@ pub fn resolveWindows(allocator: Allocator, paths: []const []const u8) ![]u8 { if (!correct_disk_designator) { continue; } - var it = mem.tokenize(u8, p[parsed.disk_designator.len..], "/\\"); + var it = mem.tokenizeAny(u8, p[parsed.disk_designator.len..], "/\\"); while (it.next()) |component| { if (mem.eql(u8, component, ".")) { continue; @@ -657,7 +657,7 @@ pub fn resolvePosix(allocator: Allocator, paths: []const []const u8) Allocator.E negative_count = 0; result.clearRetainingCapacity(); } - var it = mem.tokenize(u8, p, "/"); + var it = mem.tokenizeScalar(u8, p, '/'); while (it.next()) |component| { if (mem.eql(u8, component, ".")) { continue; @@ -1078,8 +1078,8 @@ pub fn relativeWindows(allocator: Allocator, from: []const u8, to: []const u8) ! return resolved_to; } - var from_it = mem.tokenize(u8, resolved_from, "/\\"); - var to_it = mem.tokenize(u8, resolved_to, "/\\"); + var from_it = mem.tokenizeAny(u8, resolved_from, "/\\"); + var to_it = mem.tokenizeAny(u8, resolved_to, "/\\"); while (true) { const from_component = from_it.next() orelse return allocator.dupe(u8, to_it.rest()); const to_rest = to_it.rest(); @@ -1102,7 +1102,7 @@ pub fn relativeWindows(allocator: Allocator, from: []const u8, to: []const u8) ! result_index += 3; } - var rest_it = mem.tokenize(u8, to_rest, "/\\"); + var rest_it = mem.tokenizeAny(u8, to_rest, "/\\"); while (rest_it.next()) |to_component| { result[result_index] = '\\'; result_index += 1; @@ -1124,8 +1124,8 @@ pub fn relativePosix(allocator: Allocator, from: []const u8, to: []const u8) ![] const resolved_to = try resolvePosix(allocator, &[_][]const u8{ cwd, to }); defer allocator.free(resolved_to); - var from_it = mem.tokenize(u8, resolved_from, "/"); - var to_it = mem.tokenize(u8, resolved_to, "/"); + var from_it = mem.tokenizeScalar(u8, resolved_from, '/'); + var to_it = mem.tokenizeScalar(u8, resolved_to, '/'); while (true) { const from_component = from_it.next() orelse return allocator.dupe(u8, to_it.rest()); const to_rest = to_it.rest(); diff --git a/lib/std/http/Client.zig b/lib/std/http/Client.zig index 023bdd28bc..5626864ceb 100644 --- a/lib/std/http/Client.zig +++ b/lib/std/http/Client.zig @@ -386,7 +386,7 @@ pub const Response = struct { }; pub fn parse(res: *Response, bytes: []const u8, trailing: bool) ParseError!void { - var it = mem.tokenize(u8, bytes[0 .. bytes.len - 4], "\r\n"); + var it = mem.tokenizeAny(u8, bytes[0 .. bytes.len - 4], "\r\n"); const first_line = it.next() orelse return error.HttpHeadersInvalid; if (first_line.len < 12) @@ -412,7 +412,7 @@ pub const Response = struct { else => {}, } - var line_it = mem.tokenize(u8, line, ": "); + var line_it = mem.tokenizeAny(u8, line, ": "); const header_name = line_it.next() orelse return error.HttpHeadersInvalid; const header_value = line_it.rest(); diff --git a/lib/std/http/Server.zig b/lib/std/http/Server.zig index 6b5db6725f..51ab6c086b 100644 --- a/lib/std/http/Server.zig +++ b/lib/std/http/Server.zig @@ -231,7 +231,7 @@ pub const Request = struct { }; pub fn parse(req: *Request, bytes: []const u8) ParseError!void { - var it = mem.tokenize(u8, bytes[0 .. bytes.len - 4], "\r\n"); + var it = mem.tokenizeAny(u8, bytes[0 .. bytes.len - 4], "\r\n"); const first_line = it.next() orelse return error.HttpHeadersInvalid; if (first_line.len < 10) @@ -265,7 +265,7 @@ pub const Request = struct { else => {}, } - var line_it = mem.tokenize(u8, line, ": "); + var line_it = mem.tokenizeAny(u8, line, ": "); const header_name = line_it.next() orelse return error.HttpHeadersInvalid; const header_value = line_it.rest(); diff --git a/lib/std/net.zig b/lib/std/net.zig index 57e50a7349..4360cc29f4 100644 --- a/lib/std/net.zig +++ b/lib/std/net.zig @@ -1266,7 +1266,7 @@ fn linuxLookupNameFromHosts( var split_it = mem.split(u8, line, "#"); const no_comment_line = split_it.first(); - var line_it = mem.tokenize(u8, no_comment_line, " \t"); + var line_it = mem.tokenizeAny(u8, no_comment_line, " \t"); const ip_text = line_it.next() orelse continue; var first_name_text: ?[]const u8 = null; while (line_it.next()) |name_text| { @@ -1346,7 +1346,7 @@ fn linuxLookupNameFromDnsSearch( @memcpy(canon.items, canon_name); try canon.append('.'); - var tok_it = mem.tokenize(u8, search, " \t"); + var tok_it = mem.tokenizeAny(u8, search, " \t"); while (tok_it.next()) |tok| { canon.shrinkRetainingCapacity(canon_name.len + 1); try canon.appendSlice(tok); @@ -1468,7 +1468,7 @@ fn getResolvConf(allocator: mem.Allocator, rc: *ResolvConf) !void { var split = mem.split(u8, line, "#"); break :no_comment_line split.first(); }; - var line_it = mem.tokenize(u8, no_comment_line, " \t"); + var line_it = mem.tokenizeAny(u8, no_comment_line, " \t"); const token = line_it.next() orelse continue; if (mem.eql(u8, token, "options")) { diff --git a/lib/std/os.zig b/lib/std/os.zig index 779e913230..eac79690b5 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -1878,7 +1878,7 @@ pub fn execvpeZ_expandArg0( // Use of MAX_PATH_BYTES here is valid as the path_buf will be passed // directly to the operating system in execveZ. var path_buf: [MAX_PATH_BYTES]u8 = undefined; - var it = mem.tokenize(u8, PATH, ":"); + var it = mem.tokenizeScalar(u8, PATH, ':'); var seen_eacces = false; var err: ExecveError = error.FileNotFound; diff --git a/lib/std/process.zig b/lib/std/process.zig index 504f9075eb..c33fd92db6 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -1200,7 +1200,7 @@ fn totalSystemMemoryLinux() !usize { var buf: [50]u8 = undefined; const amt = try file.read(&buf); if (amt != 50) return error.Unexpected; - var it = std.mem.tokenize(u8, buf[0..amt], " \n"); + var it = std.mem.tokenizeAny(u8, buf[0..amt], " \n"); const label = it.next().?; if (!std.mem.eql(u8, label, "MemTotal:")) return error.Unexpected; const int_text = it.next() orelse return error.Unexpected; diff --git a/lib/std/zig/system/NativePaths.zig b/lib/std/zig/system/NativePaths.zig index 70c795b0cf..368e3e062d 100644 --- a/lib/std/zig/system/NativePaths.zig +++ b/lib/std/zig/system/NativePaths.zig @@ -31,7 +31,7 @@ pub fn detect(allocator: Allocator, native_info: NativeTargetInfo) !NativePaths defer allocator.free(nix_cflags_compile); is_nix = true; - var it = mem.tokenize(u8, nix_cflags_compile, " "); + var it = mem.tokenizeScalar(u8, nix_cflags_compile, ' '); while (true) { const word = it.next() orelse break; if (mem.eql(u8, word, "-isystem")) { @@ -62,7 +62,7 @@ pub fn detect(allocator: Allocator, native_info: NativeTargetInfo) !NativePaths defer allocator.free(nix_ldflags); is_nix = true; - var it = mem.tokenize(u8, nix_ldflags, " "); + var it = mem.tokenizeScalar(u8, nix_ldflags, ' '); while (true) { const word = it.next() orelse break; if (mem.eql(u8, word, "-rpath")) { @@ -147,21 +147,21 @@ pub fn detect(allocator: Allocator, native_info: NativeTargetInfo) !NativePaths // We use os.getenv here since this part won't be executed on // windows, to get rid of unnecessary error handling. if (std.os.getenv("C_INCLUDE_PATH")) |c_include_path| { - var it = mem.tokenize(u8, c_include_path, ":"); + var it = mem.tokenizeScalar(u8, c_include_path, ':'); while (it.next()) |dir| { try self.addIncludeDir(dir); } } if (std.os.getenv("CPLUS_INCLUDE_PATH")) |cplus_include_path| { - var it = mem.tokenize(u8, cplus_include_path, ":"); + var it = mem.tokenizeScalar(u8, cplus_include_path, ':'); while (it.next()) |dir| { try self.addIncludeDir(dir); } } if (std.os.getenv("LIBRARY_PATH")) |library_path| { - var it = mem.tokenize(u8, library_path, ":"); + var it = mem.tokenizeScalar(u8, library_path, ':'); while (it.next()) |dir| { try self.addLibDir(dir); } diff --git a/lib/std/zig/system/NativeTargetInfo.zig b/lib/std/zig/system/NativeTargetInfo.zig index 539ad96365..808a1bda8d 100644 --- a/lib/std/zig/system/NativeTargetInfo.zig +++ b/lib/std/zig/system/NativeTargetInfo.zig @@ -354,7 +354,7 @@ fn detectAbiAndDynamicLinker( const newline = mem.indexOfScalar(u8, buffer[0..len], '\n') orelse break :blk file; const line = buffer[0..newline]; if (!mem.startsWith(u8, line, "#!")) break :blk file; - var it = mem.tokenize(u8, line[2..], " "); + var it = mem.tokenizeScalar(u8, line[2..], ' '); file_name = it.next() orelse return defaultAbiAndDynamicLinker(cpu, os, cross_target); file.close(); } @@ -811,7 +811,7 @@ pub fn abiAndDynamicLinkerFromFile( const strtab = strtab_buf[0..strtab_read_len]; const rpath_list = mem.sliceTo(strtab, 0); - var it = mem.tokenize(u8, rpath_list, ":"); + var it = mem.tokenizeScalar(u8, rpath_list, ':'); while (it.next()) |rpath| { if (glibcVerFromRPath(rpath)) |ver| { result.target.os.version_range.linux.glibc = ver; diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 2dc1cc8ee4..be09a33bde 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -8409,9 +8409,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { } const asm_source = mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len]; - var line_it = mem.tokenize(u8, asm_source, "\n\r;"); + var line_it = mem.tokenizeAny(u8, asm_source, "\n\r;"); while (line_it.next()) |line| { - var mnem_it = mem.tokenize(u8, line, " \t"); + var mnem_it = mem.tokenizeAny(u8, line, " \t"); const mnem_str = mnem_it.next() orelse continue; if (mem.startsWith(u8, mnem_str, "#")) continue; @@ -8435,7 +8435,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { return self.fail("Invalid mnemonic: '{s}'", .{mnem_str}); } }; - var op_it = mem.tokenize(u8, mnem_it.rest(), ","); + var op_it = mem.tokenizeScalar(u8, mnem_it.rest(), ','); var ops = [1]encoder.Instruction.Operand{.none} ** 4; for (&ops) |*op| { const op_str = mem.trim(u8, op_it.next() orelse break, " \t"); diff --git a/src/glibc.zig b/src/glibc.zig index 327e4f4bb9..00787381f4 100644 --- a/src/glibc.zig +++ b/src/glibc.zig @@ -109,7 +109,7 @@ pub fn loadMetaData(gpa: Allocator, contents: []const u8) LoadMetaDataError!*ABI const target_name = mem.sliceTo(contents[index..], 0); index += target_name.len + 1; - var component_it = mem.tokenize(u8, target_name, "-"); + var component_it = mem.tokenizeScalar(u8, target_name, '-'); const arch_name = component_it.next() orelse { log.err("abilists: expected arch name", .{}); return error.ZigInstallationCorrupt; diff --git a/src/libc_installation.zig b/src/libc_installation.zig index da877e1291..a62da6b9c7 100644 --- a/src/libc_installation.zig +++ b/src/libc_installation.zig @@ -60,7 +60,7 @@ pub const LibCInstallation = struct { const contents = try std.fs.cwd().readFileAlloc(allocator, libc_file, std.math.maxInt(usize)); defer allocator.free(contents); - var it = std.mem.tokenize(u8, contents, "\n"); + var it = std.mem.tokenizeScalar(u8, contents, '\n'); while (it.next()) |line| { if (line.len == 0 or line[0] == '#') continue; var line_it = std.mem.split(u8, line, "="); @@ -293,7 +293,7 @@ pub const LibCInstallation = struct { }, } - var it = std.mem.tokenize(u8, exec_res.stderr, "\n\r"); + var it = std.mem.tokenizeAny(u8, exec_res.stderr, "\n\r"); var search_paths = std.ArrayList([]const u8).init(allocator); defer search_paths.deinit(); while (it.next()) |line| { @@ -613,7 +613,7 @@ fn ccPrintFileName(args: CCPrintFileNameOptions) ![:0]u8 { }, } - var it = std.mem.tokenize(u8, exec_res.stdout, "\n\r"); + var it = std.mem.tokenizeAny(u8, exec_res.stdout, "\n\r"); const line = it.next() orelse return error.LibCRuntimeNotFound; // When this command fails, it returns exit code 0 and duplicates the input file name. // So we detect failure by checking if the output matches exactly the input. @@ -692,7 +692,7 @@ fn appendCcExe(args: *std.ArrayList([]const u8), skip_cc_env_var: bool) !void { return; }; // Respect space-separated flags to the C compiler. - var it = std.mem.tokenize(u8, cc_env_var, " "); + var it = std.mem.tokenizeScalar(u8, cc_env_var, ' '); while (it.next()) |arg| { try args.append(arg); } diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index bef06d1c87..f8ac4e09c1 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -264,7 +264,7 @@ fn putFn(self: *Plan9, decl_index: Module.Decl.Index, out: FnDeclOutput) !void { fn addPathComponents(self: *Plan9, path: []const u8, a: *std.ArrayList(u8)) !void { const sep = std.fs.path.sep; - var it = std.mem.tokenize(u8, path, &.{sep}); + var it = std.mem.tokenizeScalar(u8, path, sep); while (it.next()) |component| { if (self.file_segments.get(component)) |num| { try a.writer().writeIntBig(u16, num); diff --git a/src/print_zir.zig b/src/print_zir.zig index f5e84fcf5b..6ded52ae9f 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -2581,7 +2581,7 @@ const Writer = struct { fn writeDocComment(self: *Writer, stream: anytype, doc_comment_index: u32) !void { if (doc_comment_index != 0) { const doc_comment = self.code.nullTerminatedString(doc_comment_index); - var it = std.mem.tokenize(u8, doc_comment, "\n"); + var it = std.mem.tokenizeScalar(u8, doc_comment, '\n'); while (it.next()) |doc_line| { try stream.writeByteNTimes(' ', self.indent); try stream.print("///{s}\n", .{doc_line}); diff --git a/test/behavior/bugs/6456.zig b/test/behavior/bugs/6456.zig index 1eef9c7f75..297c9c7423 100644 --- a/test/behavior/bugs/6456.zig +++ b/test/behavior/bugs/6456.zig @@ -18,7 +18,7 @@ test "issue 6456" { comptime { var fields: []const StructField = &[0]StructField{}; - var it = std.mem.tokenize(u8, text, "\n"); + var it = std.mem.tokenizeScalar(u8, text, '\n'); while (it.next()) |name| { fields = fields ++ &[_]StructField{StructField{ .alignment = 0, diff --git a/test/src/Cases.zig b/test/src/Cases.zig index 68ecebc7bd..aa5369af93 100644 --- a/test/src/Cases.zig +++ b/test/src/Cases.zig @@ -846,7 +846,7 @@ const TestManifest = struct { const actual_start = start orelse return error.MissingTestManifest; const manifest_bytes = bytes[actual_start..end]; - var it = std.mem.tokenize(u8, manifest_bytes, "\r\n"); + var it = std.mem.tokenizeAny(u8, manifest_bytes, "\r\n"); // First line is the test type const tt: Type = blk: { @@ -923,7 +923,7 @@ const TestManifest = struct { fn trailing(self: TestManifest) TrailingIterator { return .{ - .inner = std.mem.tokenize(u8, self.trailing_bytes, "\r\n"), + .inner = std.mem.tokenizeAny(u8, self.trailing_bytes, "\r\n"), }; } diff --git a/tools/generate_linux_syscalls.zig b/tools/generate_linux_syscalls.zig index 11b18ae3bf..32e287b434 100644 --- a/tools/generate_linux_syscalls.zig +++ b/tools/generate_linux_syscalls.zig @@ -51,11 +51,11 @@ pub fn main() !void { try writer.writeAll("pub const X86 = enum(usize) {\n"); const table = try linux_dir.readFile("arch/x86/entry/syscalls/syscall_32.tbl", buf); - var lines = mem.tokenize(u8, table, "\n"); + var lines = mem.tokenizeScalar(u8, table, '\n'); while (lines.next()) |line| { if (line[0] == '#') continue; - var fields = mem.tokenize(u8, line, " \t"); + var fields = mem.tokenizeAny(u8, line, " \t"); const number = fields.next() orelse return error.Incomplete; // abi is always i386 _ = fields.next() orelse return error.Incomplete; @@ -70,11 +70,11 @@ pub fn main() !void { try writer.writeAll("pub const X64 = enum(usize) {\n"); const table = try linux_dir.readFile("arch/x86/entry/syscalls/syscall_64.tbl", buf); - var lines = mem.tokenize(u8, table, "\n"); + var lines = mem.tokenizeScalar(u8, table, '\n'); while (lines.next()) |line| { if (line[0] == '#') continue; - var fields = mem.tokenize(u8, line, " \t"); + var fields = mem.tokenizeAny(u8, line, " \t"); const number = fields.next() orelse return error.Incomplete; const abi = fields.next() orelse return error.Incomplete; // The x32 abi syscalls are always at the end. @@ -96,11 +96,11 @@ pub fn main() !void { ); const table = try linux_dir.readFile("arch/arm/tools/syscall.tbl", buf); - var lines = mem.tokenize(u8, table, "\n"); + var lines = mem.tokenizeScalar(u8, table, '\n'); while (lines.next()) |line| { if (line[0] == '#') continue; - var fields = mem.tokenize(u8, line, " \t"); + var fields = mem.tokenizeAny(u8, line, " \t"); const number = fields.next() orelse return error.Incomplete; const abi = fields.next() orelse return error.Incomplete; if (mem.eql(u8, abi, "oabi")) continue; @@ -127,11 +127,11 @@ pub fn main() !void { { try writer.writeAll("pub const Sparc64 = enum(usize) {\n"); const table = try linux_dir.readFile("arch/sparc/kernel/syscalls/syscall.tbl", buf); - var lines = mem.tokenize(u8, table, "\n"); + var lines = mem.tokenizeScalar(u8, table, '\n'); while (lines.next()) |line| { if (line[0] == '#') continue; - var fields = mem.tokenize(u8, line, " \t"); + var fields = mem.tokenizeAny(u8, line, " \t"); const number = fields.next() orelse return error.Incomplete; const abi = fields.next() orelse return error.Incomplete; if (mem.eql(u8, abi, "32")) continue; @@ -151,11 +151,11 @@ pub fn main() !void { ); const table = try linux_dir.readFile("arch/mips/kernel/syscalls/syscall_o32.tbl", buf); - var lines = mem.tokenize(u8, table, "\n"); + var lines = mem.tokenizeScalar(u8, table, '\n'); while (lines.next()) |line| { if (line[0] == '#') continue; - var fields = mem.tokenize(u8, line, " \t"); + var fields = mem.tokenizeAny(u8, line, " \t"); const number = fields.next() orelse return error.Incomplete; // abi is always o32 _ = fields.next() orelse return error.Incomplete; @@ -176,11 +176,11 @@ pub fn main() !void { ); const table = try linux_dir.readFile("arch/mips/kernel/syscalls/syscall_n64.tbl", buf); - var lines = mem.tokenize(u8, table, "\n"); + var lines = mem.tokenizeScalar(u8, table, '\n'); while (lines.next()) |line| { if (line[0] == '#') continue; - var fields = mem.tokenize(u8, line, " \t"); + var fields = mem.tokenizeAny(u8, line, " \t"); const number = fields.next() orelse return error.Incomplete; // abi is always n64 _ = fields.next() orelse return error.Incomplete; @@ -197,11 +197,11 @@ pub fn main() !void { const table = try linux_dir.readFile("arch/powerpc/kernel/syscalls/syscall.tbl", buf); var list_64 = std.ArrayList(u8).init(allocator); - var lines = mem.tokenize(u8, table, "\n"); + var lines = mem.tokenizeScalar(u8, table, '\n'); while (lines.next()) |line| { if (line[0] == '#') continue; - var fields = mem.tokenize(u8, line, " \t"); + var fields = mem.tokenizeAny(u8, line, " \t"); const number = fields.next() orelse return error.Incomplete; const abi = fields.next() orelse return error.Incomplete; const name = fields.next() orelse return error.Incomplete; @@ -277,9 +277,9 @@ pub fn main() !void { }, }; - var lines = mem.tokenize(u8, defines, "\n"); + var lines = mem.tokenizeScalar(u8, defines, '\n'); loop: while (lines.next()) |line| { - var fields = mem.tokenize(u8, line, " \t"); + var fields = mem.tokenizeAny(u8, line, " \t"); const cmd = fields.next() orelse return error.Incomplete; if (!mem.eql(u8, cmd, "#define")) continue; const define = fields.next() orelse return error.Incomplete; @@ -339,9 +339,9 @@ pub fn main() !void { }, }; - var lines = mem.tokenize(u8, defines, "\n"); + var lines = mem.tokenizeScalar(u8, defines, '\n'); loop: while (lines.next()) |line| { - var fields = mem.tokenize(u8, line, " \t"); + var fields = mem.tokenizeAny(u8, line, " \t"); const cmd = fields.next() orelse return error.Incomplete; if (!mem.eql(u8, cmd, "#define")) continue; const define = fields.next() orelse return error.Incomplete; -- cgit v1.2.3 From 728ce2d7c18e23ca6c36d86f4ee1ea4ce3ac81e2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 16 May 2023 20:00:47 -0700 Subject: tweaks to --build-id * build.zig: the result of b.option() can be assigned directly in many cases thanks to the return type being an optional * std.Build: make the build system aware of the std.Build.Step.Compile.BuildId type when used as an option. - remove extraneous newlines in error logs * simplify caching logic * simplify hexstring parsing tests and use a doc test * simplify hashing logic. don't use an optional when the `none` tag already provides this meaning. * CLI: fix incorrect linker arg parsing --- build.zig | 7 +- lib/std/Build.zig | 62 ++++++++++++------ lib/std/Build/Cache.zig | 4 ++ lib/std/Build/Step/Compile.zig | 141 ++++++++++++++++------------------------- src/Compilation.zig | 9 ++- src/link.zig | 2 +- src/link/Elf.zig | 21 +++--- src/link/Wasm.zig | 50 +++++++-------- src/main.zig | 37 ++++++----- 9 files changed, 169 insertions(+), 164 deletions(-) (limited to 'lib/std/Build/Cache.zig') diff --git a/build.zig b/build.zig index 62f1d86441..a75269083f 100644 --- a/build.zig +++ b/build.zig @@ -167,8 +167,11 @@ pub fn build(b: *std.Build) !void { exe.sanitize_thread = sanitize_thread; exe.entitlements = entitlements; - if (b.option([]const u8, "build-id", "Include a build id note")) |build_id| - exe.build_id = try std.Build.CompileStep.BuildId.parse(b.allocator, build_id); + exe.build_id = b.option( + std.Build.Step.Compile.BuildId, + "build-id", + "Request creation of '.note.gnu.build-id' section", + ); b.installArtifact(exe); diff --git a/lib/std/Build.zig b/lib/std/Build.zig index ca55d23937..7ef504851e 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -181,6 +181,7 @@ const TypeId = enum { @"enum", string, list, + build_id, }; const TopLevelStep = struct { @@ -832,13 +833,13 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ } else if (mem.eql(u8, s, "false")) { return false; } else { - log.err("Expected -D{s} to be a boolean, but received '{s}'\n", .{ name, s }); + log.err("Expected -D{s} to be a boolean, but received '{s}'", .{ name, s }); self.markInvalidUserInput(); return null; } }, .list, .map => { - log.err("Expected -D{s} to be a boolean, but received a {s}.\n", .{ + log.err("Expected -D{s} to be a boolean, but received a {s}.", .{ name, @tagName(option_ptr.value), }); self.markInvalidUserInput(); @@ -847,7 +848,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ }, .int => switch (option_ptr.value) { .flag, .list, .map => { - log.err("Expected -D{s} to be an integer, but received a {s}.\n", .{ + log.err("Expected -D{s} to be an integer, but received a {s}.", .{ name, @tagName(option_ptr.value), }); self.markInvalidUserInput(); @@ -856,12 +857,12 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ .scalar => |s| { const n = std.fmt.parseInt(T, s, 10) catch |err| switch (err) { error.Overflow => { - log.err("-D{s} value {s} cannot fit into type {s}.\n", .{ name, s, @typeName(T) }); + log.err("-D{s} value {s} cannot fit into type {s}.", .{ name, s, @typeName(T) }); self.markInvalidUserInput(); return null; }, else => { - log.err("Expected -D{s} to be an integer of type {s}.\n", .{ name, @typeName(T) }); + log.err("Expected -D{s} to be an integer of type {s}.", .{ name, @typeName(T) }); self.markInvalidUserInput(); return null; }, @@ -871,7 +872,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ }, .float => switch (option_ptr.value) { .flag, .map, .list => { - log.err("Expected -D{s} to be a float, but received a {s}.\n", .{ + log.err("Expected -D{s} to be a float, but received a {s}.", .{ name, @tagName(option_ptr.value), }); self.markInvalidUserInput(); @@ -879,7 +880,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ }, .scalar => |s| { const n = std.fmt.parseFloat(T, s) catch { - log.err("Expected -D{s} to be a float of type {s}.\n", .{ name, @typeName(T) }); + log.err("Expected -D{s} to be a float of type {s}.", .{ name, @typeName(T) }); self.markInvalidUserInput(); return null; }; @@ -888,7 +889,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ }, .@"enum" => switch (option_ptr.value) { .flag, .map, .list => { - log.err("Expected -D{s} to be an enum, but received a {s}.\n", .{ + log.err("Expected -D{s} to be an enum, but received a {s}.", .{ name, @tagName(option_ptr.value), }); self.markInvalidUserInput(); @@ -898,7 +899,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ if (std.meta.stringToEnum(T, s)) |enum_lit| { return enum_lit; } else { - log.err("Expected -D{s} to be of type {s}.\n", .{ name, @typeName(T) }); + log.err("Expected -D{s} to be of type {s}.", .{ name, @typeName(T) }); self.markInvalidUserInput(); return null; } @@ -906,7 +907,7 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ }, .string => switch (option_ptr.value) { .flag, .list, .map => { - log.err("Expected -D{s} to be a string, but received a {s}.\n", .{ + log.err("Expected -D{s} to be a string, but received a {s}.", .{ name, @tagName(option_ptr.value), }); self.markInvalidUserInput(); @@ -914,9 +915,27 @@ pub fn option(self: *Build, comptime T: type, name_raw: []const u8, description_ }, .scalar => |s| return s, }, + .build_id => switch (option_ptr.value) { + .flag, .map, .list => { + log.err("Expected -D{s} to be an enum, but received a {s}.", .{ + name, @tagName(option_ptr.value), + }); + self.markInvalidUserInput(); + return null; + }, + .scalar => |s| { + if (Step.Compile.BuildId.parse(s)) |build_id| { + return build_id; + } else |err| { + log.err("unable to parse option '-D{s}': {s}", .{ name, @errorName(err) }); + self.markInvalidUserInput(); + return null; + } + }, + }, .list => switch (option_ptr.value) { .flag, .map => { - log.err("Expected -D{s} to be a list, but received a {s}.\n", .{ + log.err("Expected -D{s} to be a list, but received a {s}.", .{ name, @tagName(option_ptr.value), }); self.markInvalidUserInput(); @@ -1183,15 +1202,18 @@ pub fn addUserInputFlag(self: *Build, name_raw: []const u8) !bool { } fn typeToEnum(comptime T: type) TypeId { - return switch (@typeInfo(T)) { - .Int => .int, - .Float => .float, - .Bool => .bool, - .Enum => .@"enum", - else => switch (T) { - []const u8 => .string, - []const []const u8 => .list, - else => @compileError("Unsupported type: " ++ @typeName(T)), + return switch (T) { + Step.Compile.BuildId => .build_id, + else => return switch (@typeInfo(T)) { + .Int => .int, + .Float => .float, + .Bool => .bool, + .Enum => .@"enum", + else => switch (T) { + []const u8 => .string, + []const []const u8 => .list, + else => @compileError("Unsupported type: " ++ @typeName(T)), + }, }, }; } diff --git a/lib/std/Build/Cache.zig b/lib/std/Build/Cache.zig index 17429c0370..e991aff5b5 100644 --- a/lib/std/Build/Cache.zig +++ b/lib/std/Build/Cache.zig @@ -235,6 +235,10 @@ pub const HashHelper = struct { .none => {}, } }, + std.Build.Step.Compile.BuildId => switch (x) { + .none, .fast, .uuid, .sha1, .md5 => hh.add(std.meta.activeTag(x)), + .hexstring => |hex_string| hh.addBytes(hex_string.toSlice()), + }, else => switch (@typeInfo(@TypeOf(x))) { .Bool, .Int, .Enum, .Array => hh.addBytes(mem.asBytes(&x)), else => @compileError("unable to hash type " ++ @typeName(@TypeOf(x))), diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig index 25492eb73d..d0a2d69bfe 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -294,27 +294,41 @@ pub const BuildId = union(enum) { uuid, sha1, md5, - hexstring: []const u8, + hexstring: HexString, + + pub fn eql(a: BuildId, b: BuildId) bool { + const a_tag = std.meta.activeTag(a); + const b_tag = std.meta.activeTag(b); + if (a_tag != b_tag) return false; + return switch (a) { + .none, .fast, .uuid, .sha1, .md5 => true, + .hexstring => |a_hexstring| mem.eql(u8, a_hexstring.toSlice(), b.hexstring.toSlice()), + }; + } - pub fn hash(self: BuildId, hasher: anytype) void { - switch (self) { - .none, .fast, .uuid, .sha1, .md5 => { - hasher.update(@tagName(self)); - }, - .hexstring => |str| { - hasher.update("0x"); - hasher.update(str); - }, + pub const HexString = struct { + bytes: [32]u8, + len: u8, + + /// Result is byte values, *not* hex-encoded. + pub fn toSlice(hs: *const HexString) []const u8 { + return hs.bytes[0..hs.len]; } + }; + + /// Input is byte values, *not* hex-encoded. + /// Asserts `bytes` fits inside `HexString` + pub fn initHexString(bytes: []const u8) BuildId { + var result: BuildId = .{ .hexstring = .{ + .bytes = undefined, + .len = @intCast(u8, bytes.len), + } }; + @memcpy(result.hexstring.bytes[0..bytes.len], bytes); + return result; } - // parses the incoming BuildId. If returns a hexstring, it is allocated - // by the provided allocator. - pub fn parse(allocator: std.mem.Allocator, text: []const u8) error{ - InvalidHexInt, - InvalidBuildId, - OutOfMemory, - }!BuildId { + /// Converts UTF-8 text to a `BuildId`. + pub fn parse(text: []const u8) !BuildId { if (mem.eql(u8, text, "none")) { return .none; } else if (mem.eql(u8, text, "fast")) { @@ -326,27 +340,27 @@ pub const BuildId = union(enum) { } else if (mem.eql(u8, text, "md5")) { return .md5; } else if (mem.startsWith(u8, text, "0x")) { - var clean_hex_string = try allocator.alloc(u8, text.len); - errdefer allocator.free(clean_hex_string); - - var i: usize = 0; - for (text["0x".len..]) |c| { - if (std.ascii.isHex(c)) { - clean_hex_string[i] = c; - i += 1; - } else if (c == '-' or c == ':') { - continue; - } else { - return error.InvalidHexInt; - } - } - if (i < text.len) - _ = allocator.resize(clean_hex_string, i); - - return BuildId{ .hexstring = clean_hex_string[0..i] }; + var result: BuildId = .{ .hexstring = undefined }; + const slice = try std.fmt.hexToBytes(&result.hexstring.bytes, text[2..]); + result.hexstring.len = @intCast(u8, slice.len); + return result; } + return error.InvalidBuildIdStyle; + } + + test parse { + try std.testing.expectEqual(BuildId.md5, try parse("md5")); + try std.testing.expectEqual(BuildId.none, try parse("none")); + try std.testing.expectEqual(BuildId.fast, try parse("fast")); + try std.testing.expectEqual(BuildId.uuid, try parse("uuid")); + try std.testing.expectEqual(BuildId.sha1, try parse("sha1")); + try std.testing.expectEqual(BuildId.sha1, try parse("tree")); - return error.InvalidBuildId; + try std.testing.expect(BuildId.initHexString("").eql(try parse("0x"))); + try std.testing.expect(BuildId.initHexString("\x12\x34\x56").eql(try parse("0x123456"))); + try std.testing.expectError(error.InvalidLength, parse("0x12-34")); + try std.testing.expectError(error.InvalidCharacter, parse("0xfoobbb")); + try std.testing.expectError(error.InvalidBuildIdStyle, parse("yaddaxxx")); } }; @@ -1872,11 +1886,13 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { try addFlag(&zig_args, "valgrind", self.valgrind_support); try addFlag(&zig_args, "each-lib-rpath", self.each_lib_rpath); + if (self.build_id) |build_id| { - const fmt_str = "--build-id={s}{s}"; try zig_args.append(switch (build_id) { - .hexstring => |str| try std.fmt.allocPrint(b.allocator, fmt_str, .{ "0x", str }), - .none, .fast, .uuid, .sha1, .md5 => try std.fmt.allocPrint(b.allocator, fmt_str, .{ "", @tagName(build_id) }), + .hexstring => |hs| b.fmt("--build-id=0x{s}", .{ + std.fmt.fmtSliceHexLower(hs.toSlice()), + }), + .none, .fast, .uuid, .sha1, .md5 => b.fmt("--build-id={s}", .{@tagName(build_id)}), }); } @@ -2243,50 +2259,3 @@ fn checkCompileErrors(self: *Compile) !void { \\========================================= , .{ expected_generated.items, actual_stderr }); } - -const testing = std.testing; - -test "BuildId.parse" { - const tests = &[_]struct { - []const u8, - ?BuildId, - ?anyerror, - }{ - .{ "0x", BuildId{ .hexstring = "" }, null }, - .{ "0x12-34:", BuildId{ .hexstring = "1234" }, null }, - .{ "0x123456", BuildId{ .hexstring = "123456" }, null }, - .{ "md5", .md5, null }, - .{ "none", .none, null }, - .{ "fast", .fast, null }, - .{ "uuid", .uuid, null }, - .{ "sha1", .sha1, null }, - .{ "tree", .sha1, null }, - .{ "0xfoobbb", null, error.InvalidHexInt }, - .{ "yaddaxxx", null, error.InvalidBuildId }, - }; - - for (tests) |tt| { - const input = tt[0]; - const expected = tt[1]; - const expected_err = tt[2]; - - _ = (if (expected_err) |err| { - try testing.expectError(err, BuildId.parse(testing.allocator, input)); - } else blk: { - const actual = BuildId.parse(testing.allocator, input) catch |e| break :blk e; - switch (expected.?) { - .hexstring => |expected_str| { - try testing.expectEqualStrings(expected_str, actual.hexstring); - testing.allocator.free(actual.hexstring); - }, - else => try testing.expectEqual(expected.?, actual), - } - }) catch |e| { - std.log.err( - "BuildId.parse failed on {s}: expected {} got {!}", - .{ input, expected.?, e }, - ); - return e; - }; - } -} diff --git a/src/Compilation.zig b/src/Compilation.zig index 5a547346a5..de09a78c77 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -798,6 +798,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { const unwind_tables = options.want_unwind_tables orelse (link_libunwind or target_util.needUnwindTables(options.target)); const link_eh_frame_hdr = options.link_eh_frame_hdr or unwind_tables; + const build_id = options.build_id orelse .none; // Make a decision on whether to use LLD or our own linker. const use_lld = options.use_lld orelse blk: { @@ -828,7 +829,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { options.output_mode == .Lib or options.linker_script != null or options.version_script != null or options.emit_implib != null or - options.build_id != null or + build_id != .none or options.symbol_wrap_set.count() > 0) { break :blk true; @@ -1514,7 +1515,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .skip_linker_dependencies = options.skip_linker_dependencies, .parent_compilation_link_libc = options.parent_compilation_link_libc, .each_lib_rpath = options.each_lib_rpath orelse options.is_native_os, - .build_id = options.build_id, + .build_id = build_id, .cache_mode = cache_mode, .disable_lld_caching = options.disable_lld_caching or cache_mode == .whole, .subsystem = options.subsystem, @@ -2269,9 +2270,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes man.hash.addListOfBytes(comp.bin_file.options.rpath_list); man.hash.addListOfBytes(comp.bin_file.options.symbol_wrap_set.keys()); man.hash.add(comp.bin_file.options.each_lib_rpath); - if (comp.bin_file.options.build_id) |build_id| { - build_id.hash(&man.hash.hasher); - } + man.hash.add(comp.bin_file.options.build_id); man.hash.add(comp.bin_file.options.skip_linker_dependencies); man.hash.add(comp.bin_file.options.z_nodelete); man.hash.add(comp.bin_file.options.z_notext); diff --git a/src/link.zig b/src/link.zig index eccf389d05..79ac33b892 100644 --- a/src/link.zig +++ b/src/link.zig @@ -158,7 +158,7 @@ pub const Options = struct { skip_linker_dependencies: bool, parent_compilation_link_libc: bool, each_lib_rpath: bool, - build_id: ?BuildId, + build_id: BuildId, disable_lld_caching: bool, is_test: bool, hash_style: HashStyle, diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 289c687270..f90f4ebd46 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1399,8 +1399,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v man.hash.add(self.base.options.each_lib_rpath); if (self.base.options.output_mode == .Exe) { man.hash.add(stack_size); - if (self.base.options.build_id) |build_id| - build_id.hash(&man.hash.hasher); + man.hash.add(self.base.options.build_id); } man.hash.addListOfBytes(self.base.options.symbol_wrap_set.keys()); man.hash.add(self.base.options.skip_linker_dependencies); @@ -1543,12 +1542,18 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v try argv.append("-z"); try argv.append(try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size})); - if (self.base.options.build_id) |build_id| { - const fmt_str = "--build-id={s}{s}"; - try argv.append(switch (build_id) { - .hexstring => |str| try std.fmt.allocPrint(arena, fmt_str, .{ "0x", str }), - .none, .fast, .uuid, .sha1, .md5 => try std.fmt.allocPrint(arena, fmt_str, .{ "", @tagName(build_id) }), - }); + switch (self.base.options.build_id) { + .none => {}, + .fast, .uuid, .sha1, .md5 => { + try argv.append(try std.fmt.allocPrint(arena, "--build-id={s}", .{ + @tagName(self.base.options.build_id), + })); + }, + .hexstring => |hs| { + try argv.append(try std.fmt.allocPrint(arena, "--build-id=0x{s}", .{ + std.fmt.fmtSliceHexLower(hs.toSlice()), + })); + }, } } diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 9396377c73..cd9c44d656 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -3163,8 +3163,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l try man.addOptionalFile(compiler_rt_path); man.hash.addOptionalBytes(options.entry); man.hash.addOptional(options.stack_size_override); - if (wasm.base.options.build_id) |build_id| - build_id.hash(&man.hash.hasher); + man.hash.add(wasm.base.options.build_id); man.hash.add(options.import_memory); man.hash.add(options.import_table); man.hash.add(options.export_table); @@ -3798,27 +3797,29 @@ fn writeToFile( if (!wasm.base.options.strip) { // The build id must be computed on the main sections only, // so we have to do it now, before the debug sections. - if (wasm.base.options.build_id) |build_id| { - switch (build_id) { - .none => {}, - .fast => { - var id: [16]u8 = undefined; - std.crypto.hash.sha3.TurboShake128(null).hash(binary_bytes.items, &id, .{}); - var uuid: [36]u8 = undefined; - _ = try std.fmt.bufPrint(&uuid, "{s}-{s}-{s}-{s}-{s}", .{ - std.fmt.fmtSliceHexLower(id[0..4]), - std.fmt.fmtSliceHexLower(id[4..6]), - std.fmt.fmtSliceHexLower(id[6..8]), - std.fmt.fmtSliceHexLower(id[8..10]), - std.fmt.fmtSliceHexLower(id[10..]), - }); - try emitBuildIdSection(&binary_bytes, &uuid); - }, - .hexstring => |str| { - try emitBuildIdSection(&binary_bytes, str); - }, - else => |mode| log.err("build-id '{s}' is not supported for WASM", .{@tagName(mode)}), - } + switch (wasm.base.options.build_id) { + .none => {}, + .fast => { + var id: [16]u8 = undefined; + std.crypto.hash.sha3.TurboShake128(null).hash(binary_bytes.items, &id, .{}); + var uuid: [36]u8 = undefined; + _ = try std.fmt.bufPrint(&uuid, "{s}-{s}-{s}-{s}-{s}", .{ + std.fmt.fmtSliceHexLower(id[0..4]), + std.fmt.fmtSliceHexLower(id[4..6]), + std.fmt.fmtSliceHexLower(id[6..8]), + std.fmt.fmtSliceHexLower(id[8..10]), + std.fmt.fmtSliceHexLower(id[10..]), + }); + try emitBuildIdSection(&binary_bytes, &uuid); + }, + .hexstring => |hs| { + var buffer: [32 * 2]u8 = undefined; + const str = std.fmt.bufPrint(&buffer, "{s}", .{ + std.fmt.fmtSliceHexLower(hs.toSlice()), + }) catch unreachable; + try emitBuildIdSection(&binary_bytes, str); + }, + else => |mode| log.err("build-id '{s}' is not supported for WASM", .{@tagName(mode)}), } // if (wasm.dwarf) |*dwarf| { @@ -4211,8 +4212,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! try man.addOptionalFile(compiler_rt_path); man.hash.addOptionalBytes(wasm.base.options.entry); man.hash.addOptional(wasm.base.options.stack_size_override); - if (wasm.base.options.build_id) |build_id| - build_id.hash(&man.hash.hasher); + man.hash.add(wasm.base.options.build_id); man.hash.add(wasm.base.options.import_memory); man.hash.add(wasm.base.options.import_table); man.hash.add(wasm.base.options.export_table); diff --git a/src/main.zig b/src/main.zig index 93199f9566..aa7d587983 100644 --- a/src/main.zig +++ b/src/main.zig @@ -494,7 +494,10 @@ const usage_build_generic = \\ -fno-each-lib-rpath Prevent adding rpath for each used dynamic library \\ -fallow-shlib-undefined Allows undefined symbols in shared libraries \\ -fno-allow-shlib-undefined Disallows undefined symbols in shared libraries - \\ --build-id[=style] Generate a build ID note + \\ --build-id[=style] At a minor link-time expense, coordinates stripped binaries + \\ fast, uuid, sha1, md5 with debug symbols via a '.note.gnu.build-id' section + \\ 0x[hexstring] Maximum 32 bytes + \\ none (default) Disable build-id \\ --eh-frame-hdr Enable C++ exception handling by passing --eh-frame-hdr to linker \\ --emit-relocs Enable output of relocation sections for post build tools \\ -z [arg] Set linker extension flags @@ -1445,11 +1448,11 @@ fn buildOutputType( } else if (mem.eql(u8, arg, "--build-id")) { build_id = .fast; } else if (mem.startsWith(u8, arg, "--build-id=")) { - const value = arg["--build-id=".len..]; - build_id = BuildId.parse(arena, value) catch |err| switch (err) { - error.InvalidHexInt => fatal("failed to parse hex value {s}", .{value}), - error.InvalidBuildId => fatal("invalid --build-id={s}", .{value}), - error.OutOfMemory => fatal("OOM", .{}), + const style = arg["--build-id=".len..]; + build_id = BuildId.parse(style) catch |err| { + fatal("unable to parse --build-id style '{s}': {s}", .{ + style, @errorName(err), + }); }; } else if (mem.eql(u8, arg, "--debug-compile-errors")) { if (!crash_report.is_enabled) { @@ -1689,7 +1692,14 @@ fn buildOutputType( if (mem.indexOfScalar(u8, linker_arg, '=')) |equals_pos| { const key = linker_arg[0..equals_pos]; const value = linker_arg[equals_pos + 1 ..]; - if (mem.eql(u8, key, "--sort-common")) { + if (mem.eql(u8, key, "--build-id")) { + build_id = BuildId.parse(value) catch |err| { + fatal("unable to parse --build-id style '{s}': {s}", .{ + value, @errorName(err), + }); + }; + continue; + } else if (mem.eql(u8, key, "--sort-common")) { // this ignores --sort=common=; ignoring plain --sort-common // is done below. continue; @@ -1699,7 +1709,9 @@ fn buildOutputType( continue; } } - if (mem.eql(u8, linker_arg, "--as-needed")) { + if (mem.eql(u8, linker_arg, "--build-id")) { + build_id = .fast; + } else if (mem.eql(u8, linker_arg, "--as-needed")) { needed = false; } else if (mem.eql(u8, linker_arg, "--no-as-needed")) { needed = true; @@ -1731,15 +1743,6 @@ fn buildOutputType( search_strategy = .paths_first; } else if (mem.eql(u8, linker_arg, "-search_dylibs_first")) { search_strategy = .dylibs_first; - } else if (mem.eql(u8, linker_arg, "--build-id")) { - build_id = .fast; - } else if (mem.startsWith(u8, linker_arg, "--build-id=")) { - const value = linker_arg["--build-id=".len..]; - build_id = BuildId.parse(arena, value) catch |err| switch (err) { - error.InvalidHexInt => fatal("failed to parse hex value {s}", .{value}), - error.InvalidBuildId => fatal("invalid --build-id={s}", .{value}), - error.OutOfMemory => fatal("OOM", .{}), - }; } else { try linker_args.append(linker_arg); } -- cgit v1.2.3 From ba35eeb417e4d54ce4c559871b9330bc95afc053 Mon Sep 17 00:00:00 2001 From: Linus Groh Date: Sat, 20 May 2023 23:11:53 +0100 Subject: std.fs.file: Rename File.Lock enum values to snake case --- lib/std/Build/Cache.zig | 6 +++--- lib/std/fs.zig | 40 ++++++++++++++++++++-------------------- lib/std/fs/file.zig | 34 +++++++++++++++++++--------------- lib/std/fs/test.zig | 22 +++++++++++----------- src/Module.zig | 8 ++++---- 5 files changed, 57 insertions(+), 53 deletions(-) (limited to 'lib/std/Build/Cache.zig') diff --git a/lib/std/Build/Cache.zig b/lib/std/Build/Cache.zig index e991aff5b5..4db8f18a31 100644 --- a/lib/std/Build/Cache.zig +++ b/lib/std/Build/Cache.zig @@ -408,7 +408,7 @@ pub const Manifest = struct { if (self.cache.manifest_dir.createFile(&manifest_file_path, .{ .read = true, .truncate = false, - .lock = .Exclusive, + .lock = .exclusive, .lock_nonblocking = self.want_shared_lock, })) |manifest_file| { self.manifest_file = manifest_file; @@ -418,7 +418,7 @@ pub const Manifest = struct { error.WouldBlock => { self.manifest_file = try self.cache.manifest_dir.openFile(&manifest_file_path, .{ .mode = .read_write, - .lock = .Shared, + .lock = .shared, }); break; }, @@ -885,7 +885,7 @@ pub const Manifest = struct { // Here we intentionally have a period where the lock is released, in case there are // other processes holding a shared lock. manifest_file.unlock(); - try manifest_file.lock(.Exclusive); + try manifest_file.lock(.exclusive); } self.have_exclusive_lock = true; return true; diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 496dbf5f0a..6ab2dbaa7f 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -1157,9 +1157,9 @@ pub const Dir = struct { else 0; os_flags |= switch (flags.lock) { - .None => @as(u32, 0), - .Shared => os.O.SHLOCK | nonblocking_lock_flag, - .Exclusive => os.O.EXLOCK | nonblocking_lock_flag, + .none => @as(u32, 0), + .shared => os.O.SHLOCK | nonblocking_lock_flag, + .exclusive => os.O.EXLOCK | nonblocking_lock_flag, }; } if (@hasDecl(os.O, "LARGEFILE")) { @@ -1182,13 +1182,13 @@ pub const Dir = struct { // WASI doesn't have os.flock so we intetinally check OS prior to the inner if block // since it is not compiltime-known and we need to avoid undefined symbol in Wasm. if (builtin.target.os.tag != .wasi) { - if (!has_flock_open_flags and flags.lock != .None) { + if (!has_flock_open_flags and flags.lock != .none) { // TODO: integrate async I/O const lock_nonblocking = if (flags.lock_nonblocking) os.LOCK.NB else @as(i32, 0); try os.flock(fd, switch (flags.lock) { - .None => unreachable, - .Shared => os.LOCK.SH | lock_nonblocking, - .Exclusive => os.LOCK.EX | lock_nonblocking, + .none => unreachable, + .shared => os.LOCK.SH | lock_nonblocking, + .exclusive => os.LOCK.EX | lock_nonblocking, }); } } @@ -1241,9 +1241,9 @@ pub const Dir = struct { const range_off: w.LARGE_INTEGER = 0; const range_len: w.LARGE_INTEGER = 1; const exclusive = switch (flags.lock) { - .None => return file, - .Shared => false, - .Exclusive => true, + .none => return file, + .shared => false, + .exclusive => true, }; try w.LockFile( file.handle, @@ -1320,9 +1320,9 @@ pub const Dir = struct { else 0; const lock_flag: u32 = if (has_flock_open_flags) switch (flags.lock) { - .None => @as(u32, 0), - .Shared => os.O.SHLOCK | nonblocking_lock_flag, - .Exclusive => os.O.EXLOCK | nonblocking_lock_flag, + .none => @as(u32, 0), + .shared => os.O.SHLOCK | nonblocking_lock_flag, + .exclusive => os.O.EXLOCK | nonblocking_lock_flag, } else 0; const O_LARGEFILE = if (@hasDecl(os.O, "LARGEFILE")) os.O.LARGEFILE else 0; @@ -1339,13 +1339,13 @@ pub const Dir = struct { // WASI doesn't have os.flock so we intetinally check OS prior to the inner if block // since it is not compiltime-known and we need to avoid undefined symbol in Wasm. if (builtin.target.os.tag != .wasi) { - if (!has_flock_open_flags and flags.lock != .None) { + if (!has_flock_open_flags and flags.lock != .none) { // TODO: integrate async I/O const lock_nonblocking = if (flags.lock_nonblocking) os.LOCK.NB else @as(i32, 0); try os.flock(fd, switch (flags.lock) { - .None => unreachable, - .Shared => os.LOCK.SH | lock_nonblocking, - .Exclusive => os.LOCK.EX | lock_nonblocking, + .none => unreachable, + .shared => os.LOCK.SH | lock_nonblocking, + .exclusive => os.LOCK.EX | lock_nonblocking, }); } } @@ -1402,9 +1402,9 @@ pub const Dir = struct { const range_off: w.LARGE_INTEGER = 0; const range_len: w.LARGE_INTEGER = 1; const exclusive = switch (flags.lock) { - .None => return file, - .Shared => false, - .Exclusive => true, + .none => return file, + .shared => false, + .exclusive => true, }; try w.LockFile( file.handle, diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig index 83db10ef32..3ed4b07a3d 100644 --- a/lib/std/fs/file.zig +++ b/lib/std/fs/file.zig @@ -81,7 +81,11 @@ pub const File = struct { read_write, }; - pub const Lock = enum { None, Shared, Exclusive }; + pub const Lock = enum { + none, + shared, + exclusive, + }; pub const OpenFlags = struct { mode: OpenMode = .read_only, @@ -110,7 +114,7 @@ pub const File = struct { /// * Windows /// /// [1]: https://www.kernel.org/doc/Documentation/filesystems/mandatory-locking.txt - lock: Lock = .None, + lock: Lock = .none, /// Sets whether or not to wait until the file is locked to return. If set to true, /// `error.WouldBlock` will be returned. Otherwise, the file will wait until the file @@ -174,7 +178,7 @@ pub const File = struct { /// * Windows /// /// [1]: https://www.kernel.org/doc/Documentation/filesystems/mandatory-locking.txt - lock: Lock = .None, + lock: Lock = .none, /// Sets whether or not to wait until the file is locked to return. If set to true, /// `error.WouldBlock` will be returned. Otherwise, the file will wait until the file @@ -1465,9 +1469,9 @@ pub const File = struct { if (is_windows) { var io_status_block: windows.IO_STATUS_BLOCK = undefined; const exclusive = switch (l) { - .None => return, - .Shared => false, - .Exclusive => true, + .none => return, + .shared => false, + .exclusive => true, }; return windows.LockFile( file.handle, @@ -1486,9 +1490,9 @@ pub const File = struct { }; } else { return os.flock(file.handle, switch (l) { - .None => os.LOCK.UN, - .Shared => os.LOCK.SH, - .Exclusive => os.LOCK.EX, + .none => os.LOCK.UN, + .shared => os.LOCK.SH, + .exclusive => os.LOCK.EX, }) catch |err| switch (err) { error.WouldBlock => unreachable, // non-blocking=false else => |e| return e, @@ -1532,9 +1536,9 @@ pub const File = struct { if (is_windows) { var io_status_block: windows.IO_STATUS_BLOCK = undefined; const exclusive = switch (l) { - .None => return, - .Shared => false, - .Exclusive => true, + .none => return, + .shared => false, + .exclusive => true, }; windows.LockFile( file.handle, @@ -1553,9 +1557,9 @@ pub const File = struct { }; } else { os.flock(file.handle, switch (l) { - .None => os.LOCK.UN, - .Shared => os.LOCK.SH | os.LOCK.NB, - .Exclusive => os.LOCK.EX | os.LOCK.NB, + .none => os.LOCK.UN, + .shared => os.LOCK.SH | os.LOCK.NB, + .exclusive => os.LOCK.EX | os.LOCK.NB, }) catch |err| switch (err) { error.WouldBlock => return false, else => |e| return e, diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig index 16677007f9..88796e8e4c 100644 --- a/lib/std/fs/test.zig +++ b/lib/std/fs/test.zig @@ -336,7 +336,7 @@ test "Dir.realpath smoke test" { var tmp_dir = tmpDir(.{}); defer tmp_dir.cleanup(); - var file = try tmp_dir.dir.createFile("test_file", .{ .lock = File.Lock.Shared }); + var file = try tmp_dir.dir.createFile("test_file", .{ .lock = .shared }); // We need to close the file immediately as otherwise on Windows we'll end up // with a sharing violation. file.close(); @@ -1035,10 +1035,10 @@ test "open file with exclusive nonblocking lock twice" { var tmp = tmpDir(.{}); defer tmp.cleanup(); - const file1 = try tmp.dir.createFile(filename, .{ .lock = .Exclusive, .lock_nonblocking = true }); + const file1 = try tmp.dir.createFile(filename, .{ .lock = .exclusive, .lock_nonblocking = true }); defer file1.close(); - const file2 = tmp.dir.createFile(filename, .{ .lock = .Exclusive, .lock_nonblocking = true }); + const file2 = tmp.dir.createFile(filename, .{ .lock = .exclusive, .lock_nonblocking = true }); try testing.expectError(error.WouldBlock, file2); } @@ -1050,10 +1050,10 @@ test "open file with shared and exclusive nonblocking lock" { var tmp = tmpDir(.{}); defer tmp.cleanup(); - const file1 = try tmp.dir.createFile(filename, .{ .lock = .Shared, .lock_nonblocking = true }); + const file1 = try tmp.dir.createFile(filename, .{ .lock = .shared, .lock_nonblocking = true }); defer file1.close(); - const file2 = tmp.dir.createFile(filename, .{ .lock = .Exclusive, .lock_nonblocking = true }); + const file2 = tmp.dir.createFile(filename, .{ .lock = .exclusive, .lock_nonblocking = true }); try testing.expectError(error.WouldBlock, file2); } @@ -1065,10 +1065,10 @@ test "open file with exclusive and shared nonblocking lock" { var tmp = tmpDir(.{}); defer tmp.cleanup(); - const file1 = try tmp.dir.createFile(filename, .{ .lock = .Exclusive, .lock_nonblocking = true }); + const file1 = try tmp.dir.createFile(filename, .{ .lock = .exclusive, .lock_nonblocking = true }); defer file1.close(); - const file2 = tmp.dir.createFile(filename, .{ .lock = .Shared, .lock_nonblocking = true }); + const file2 = tmp.dir.createFile(filename, .{ .lock = .shared, .lock_nonblocking = true }); try testing.expectError(error.WouldBlock, file2); } @@ -1085,13 +1085,13 @@ test "open file with exclusive lock twice, make sure second lock waits" { var tmp = tmpDir(.{}); defer tmp.cleanup(); - const file = try tmp.dir.createFile(filename, .{ .lock = .Exclusive }); + const file = try tmp.dir.createFile(filename, .{ .lock = .exclusive }); errdefer file.close(); const S = struct { fn checkFn(dir: *fs.Dir, started: *std.Thread.ResetEvent, locked: *std.Thread.ResetEvent) !void { started.set(); - const file1 = try dir.createFile(filename, .{ .lock = .Exclusive }); + const file1 = try dir.createFile(filename, .{ .lock = .exclusive }); locked.set(); file1.close(); @@ -1138,12 +1138,12 @@ test "open file with exclusive nonblocking lock twice (absolute paths)" { defer gpa.free(filename); const file1 = try fs.createFileAbsolute(filename, .{ - .lock = .Exclusive, + .lock = .exclusive, .lock_nonblocking = true, }); const file2 = fs.createFileAbsolute(filename, .{ - .lock = .Exclusive, + .lock = .exclusive, .lock_nonblocking = true, }); file1.close(); diff --git a/src/Module.zig b/src/Module.zig index c191fd6c7b..61843f5a8f 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -3618,7 +3618,7 @@ pub fn astGenFile(mod: *Module, file: *File) !void { file.sub_file_path, want_local_cache, &digest, }); - break :lock .Shared; + break :lock .shared; }, .parse_failure, .astgen_failure, .success_zir => lock: { const unchanged_metadata = @@ -3633,7 +3633,7 @@ pub fn astGenFile(mod: *Module, file: *File) !void { log.debug("metadata changed: {s}", .{file.sub_file_path}); - break :lock .Exclusive; + break :lock .exclusive; }, }; @@ -3715,11 +3715,11 @@ pub fn astGenFile(mod: *Module, file: *File) !void { } // If we already have the exclusive lock then it is our job to update. - if (builtin.os.tag == .wasi or lock == .Exclusive) break; + if (builtin.os.tag == .wasi or lock == .exclusive) break; // Otherwise, unlock to give someone a chance to get the exclusive lock // and then upgrade to an exclusive lock. cache_file.unlock(); - lock = .Exclusive; + lock = .exclusive; try cache_file.lock(lock); } -- cgit v1.2.3 From 9244e4fe2d675c6cda569afc7509349e35199ed5 Mon Sep 17 00:00:00 2001 From: kcbanner Date: Sat, 27 May 2023 15:07:44 -0400 Subject: cache: handle 0-length prefix paths in findPrefixResolved --- lib/std/Build/Cache.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/std/Build/Cache.zig') diff --git a/lib/std/Build/Cache.zig b/lib/std/Build/Cache.zig index 4db8f18a31..de68ef6644 100644 --- a/lib/std/Build/Cache.zig +++ b/lib/std/Build/Cache.zig @@ -123,7 +123,7 @@ fn findPrefixResolved(cache: *const Cache, resolved_path: []u8) !PrefixedPath { var i: u8 = 1; // Start at 1 to skip over checking the null prefix. while (i < prefixes_slice.len) : (i += 1) { const p = prefixes_slice[i].path.?; - if (mem.startsWith(u8, resolved_path, p)) { + if (p.len > 0 and mem.startsWith(u8, resolved_path, p)) { // +1 to skip over the path separator here const sub_path = try gpa.dupe(u8, resolved_path[p.len + 1 ..]); gpa.free(resolved_path); -- cgit v1.2.3 From 6e84f469904a24615a6721265a88ad8dcb4ed83a Mon Sep 17 00:00:00 2001 From: r00ster91 Date: Tue, 21 Feb 2023 18:39:22 +0100 Subject: std: replace builtin.Version with SemanticVersion --- build.zig | 4 +- lib/std/Build.zig | 8 +- lib/std/Build/Cache.zig | 2 +- lib/std/Build/Step/Compile.zig | 4 +- lib/std/Build/Step/Options.zig | 23 ----- lib/std/Build/Step/TranslateC.zig | 2 +- lib/std/SemanticVersion.zig | 24 ++++- lib/std/builtin.zig | 133 ------------------------- lib/std/c.zig | 2 +- lib/std/crypto/tlcsprng.zig | 1 + lib/std/os.zig | 18 ++-- lib/std/os/test.zig | 2 +- lib/std/target.zig | 36 +++---- lib/std/zig.zig | 2 +- lib/std/zig/CrossTarget.zig | 65 +++++++++--- lib/std/zig/system/NativeTargetInfo.zig | 22 ++-- lib/std/zig/system/darwin.zig | 3 +- lib/std/zig/system/darwin/macos.zig | 47 +++++---- src/Compilation.zig | 4 +- src/codegen/spirv/spec.zig | 2 +- src/glibc.zig | 4 +- src/link.zig | 4 +- src/link/Elf.zig | 2 +- src/link/MachO/load_commands.zig | 12 +-- src/main.zig | 13 ++- src/target.zig | 14 +-- test/link/macho/dylib/build.zig | 2 +- test/link/macho/needed_library/build.zig | 2 +- test/link/macho/search_strategy/build.zig | 2 +- test/link/macho/tls/build.zig | 2 +- test/link/macho/uuid/build.zig | 2 +- test/standalone/load_dynamic_library/build.zig | 2 +- test/standalone/shared_library/build.zig | 2 +- tools/gen_spirv_spec.zig | 2 +- 34 files changed, 189 insertions(+), 280 deletions(-) (limited to 'lib/std/Build/Cache.zig') diff --git a/build.zig b/build.zig index 9cfebebc56..28bc528772 100644 --- a/build.zig +++ b/build.zig @@ -9,7 +9,7 @@ const fs = std.fs; const InstallDirectoryOptions = std.Build.InstallDirectoryOptions; const assert = std.debug.assert; -const zig_version = std.builtin.Version{ .major = 0, .minor = 11, .patch = 0 }; +const zig_version = std.SemanticVersion{ .major = 0, .minor = 11, .patch = 0 }; const stack_size = 32 * 1024 * 1024; pub fn build(b: *std.Build) !void { @@ -242,7 +242,7 @@ pub fn build(b: *std.Build) !void { const commit_height = it.next().?; const commit_id = it.next().?; - const ancestor_ver = try std.builtin.Version.parse(tagged_ancestor); + const ancestor_ver = try std.SemanticVersion.parse(tagged_ancestor); if (zig_version.order(ancestor_ver) != .gt) { std.debug.print("Zig version '{}' must be greater than tagged ancestor '{}'\n", .{ zig_version, ancestor_ver }); std.process.exit(1); diff --git a/lib/std/Build.zig b/lib/std/Build.zig index 6ea7153c0d..c569e0074a 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -472,7 +472,7 @@ pub fn addOptions(self: *Build) *Step.Options { pub const ExecutableOptions = struct { name: []const u8, root_source_file: ?FileSource = null, - version: ?std.builtin.Version = null, + version: ?std.SemanticVersion = null, target: CrossTarget = .{}, optimize: std.builtin.Mode = .Debug, linkage: ?Step.Compile.Linkage = null, @@ -530,7 +530,7 @@ pub fn addObject(b: *Build, options: ObjectOptions) *Step.Compile { pub const SharedLibraryOptions = struct { name: []const u8, root_source_file: ?FileSource = null, - version: ?std.builtin.Version = null, + version: ?std.SemanticVersion = null, target: CrossTarget, optimize: std.builtin.Mode, max_rss: usize = 0, @@ -562,7 +562,7 @@ pub const StaticLibraryOptions = struct { root_source_file: ?FileSource = null, target: CrossTarget, optimize: std.builtin.Mode, - version: ?std.builtin.Version = null, + version: ?std.SemanticVersion = null, max_rss: usize = 0, link_libc: ?bool = null, single_threaded: ?bool = null, @@ -592,7 +592,7 @@ pub const TestOptions = struct { root_source_file: FileSource, target: CrossTarget = .{}, optimize: std.builtin.Mode = .Debug, - version: ?std.builtin.Version = null, + version: ?std.SemanticVersion = null, max_rss: usize = 0, filter: ?[]const u8 = null, test_runner: ?[]const u8 = null, diff --git a/lib/std/Build/Cache.zig b/lib/std/Build/Cache.zig index a1518f7c6a..3b7f180ae8 100644 --- a/lib/std/Build/Cache.zig +++ b/lib/std/Build/Cache.zig @@ -212,7 +212,7 @@ pub const HashHelper = struct { /// Convert the input value into bytes and record it as a dependency of the process being cached. pub fn add(hh: *HashHelper, x: anytype) void { switch (@TypeOf(x)) { - std.builtin.Version => { + std.SemanticVersion => { hh.add(x.major); hh.add(x.minor); hh.add(x.patch); diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig index 092fdf7e63..89576c15fa 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -32,7 +32,7 @@ linker_script: ?FileSource = null, version_script: ?[]const u8 = null, out_filename: []const u8, linkage: ?Linkage = null, -version: ?std.builtin.Version, +version: ?std.SemanticVersion, kind: Kind, major_only_filename: ?[]const u8, name_only_filename: ?[]const u8, @@ -278,7 +278,7 @@ pub const Options = struct { optimize: std.builtin.Mode, kind: Kind, linkage: ?Linkage = null, - version: ?std.builtin.Version = null, + version: ?std.SemanticVersion = null, max_rss: usize = 0, filter: ?[]const u8 = null, test_runner: ?[]const u8 = null, diff --git a/lib/std/Build/Step/Options.zig b/lib/std/Build/Step/Options.zig index cc7152a81e..52821a5951 100644 --- a/lib/std/Build/Step/Options.zig +++ b/lib/std/Build/Step/Options.zig @@ -76,23 +76,6 @@ fn addOptionFallible(self: *Options, comptime T: type, name: []const u8, value: } return; }, - std.builtin.Version => { - try out.print( - \\pub const {}: @import("std").builtin.Version = .{{ - \\ .major = {d}, - \\ .minor = {d}, - \\ .patch = {d}, - \\}}; - \\ - , .{ - std.zig.fmtId(name), - - value.major, - value.minor, - value.patch, - }); - return; - }, std.SemanticVersion => { try out.print( \\pub const {}: @import("std").SemanticVersion = .{{ @@ -367,7 +350,6 @@ test Options { options.addOption([2][2]u16, "nested_array", nested_array); options.addOption([]const []const u16, "nested_slice", nested_slice); //options.addOption(KeywordEnum, "keyword_enum", .@"0.8.1"); - options.addOption(std.builtin.Version, "version", try std.builtin.Version.parse("0.1.2")); options.addOption(std.SemanticVersion, "semantic_version", try std.SemanticVersion.parse("0.1.2-foo+bar")); try std.testing.expectEqualStrings( @@ -401,11 +383,6 @@ test Options { //\\ @"0.8.1", //\\}; //\\pub const keyword_enum: KeywordEnum = KeywordEnum.@"0.8.1"; - \\pub const version: @import("std").builtin.Version = .{ - \\ .major = 0, - \\ .minor = 1, - \\ .patch = 2, - \\}; \\pub const semantic_version: @import("std").SemanticVersion = .{ \\ .major = 0, \\ .minor = 1, diff --git a/lib/std/Build/Step/TranslateC.zig b/lib/std/Build/Step/TranslateC.zig index 0c7ddc4720..ced249b3f2 100644 --- a/lib/std/Build/Step/TranslateC.zig +++ b/lib/std/Build/Step/TranslateC.zig @@ -47,7 +47,7 @@ pub fn create(owner: *std.Build, options: Options) *TranslateC { pub const AddExecutableOptions = struct { name: ?[]const u8 = null, - version: ?std.builtin.Version = null, + version: ?std.SemanticVersion = null, target: ?CrossTarget = null, optimize: ?std.builtin.Mode = null, linkage: ?Step.Compile.Linkage = null, diff --git a/lib/std/SemanticVersion.zig b/lib/std/SemanticVersion.zig index 4d505b4e30..4fa1d47c40 100644 --- a/lib/std/SemanticVersion.zig +++ b/lib/std/SemanticVersion.zig @@ -1,4 +1,4 @@ -//! A software version formatted according to the Semantic Version 2 specification. +//! A software version formatted according to the Semantic Versioning 2.0.0 specification. //! //! See: https://semver.org @@ -167,7 +167,7 @@ const expect = std.testing.expect; const expectError = std.testing.expectError; test "SemanticVersion format" { - // Test vectors are from https://github.com/semver/semver.org/issues/59#issuecomment-390854010. + // Many of these test strings are from https://github.com/semver/semver.org/issues/59#issuecomment-390854010. // Valid version strings should be accepted. for ([_][]const u8{ @@ -200,6 +200,8 @@ test "SemanticVersion format" { "1.2.3----R-S.12.9.1--.12+meta", "1.2.3----RC-SNAPSHOT.12.9.1--.12", "1.0.0+0.build.1-rc.10000aaa-kk-0.1", + "5.4.0-1018-raspi", + "5.7.123", }) |valid| try std.testing.expectFmt(valid, "{}", .{try parse(valid)}); // Invalid version strings should be rejected. @@ -244,6 +246,24 @@ test "SemanticVersion format" { "+justmeta", "9.8.7+meta+meta", "9.8.7-whatever+meta+meta", + "2.6.32.11-svn21605", + "2.11.2(0.329/5/3)", + "2.13-DEVELOPMENT", + "2.3-35", + "1a.4", + "3.b1.0", + "1.4beta", + "2.7.pre", + "0..3", + "8.008.", + "01...", + "55", + "foobar", + "", + "-1", + "+4", + ".", + "....3", }) |invalid| try expectError(error.InvalidVersion, parse(invalid)); // Valid version string that may overflow. diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index b449080e86..54781e4465 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -483,139 +483,6 @@ pub const WasiExecModel = enum { reactor, }; -/// This data structure is used by the Zig language code generation and -/// therefore must be kept in sync with the compiler implementation. -pub const Version = struct { - major: u32, - minor: u32, - patch: u32 = 0, - - pub const Range = struct { - min: Version, - max: Version, - - pub fn includesVersion(self: Range, ver: Version) bool { - if (self.min.order(ver) == .gt) return false; - if (self.max.order(ver) == .lt) return false; - return true; - } - - /// Checks if system is guaranteed to be at least `version` or older than `version`. - /// Returns `null` if a runtime check is required. - pub fn isAtLeast(self: Range, ver: Version) ?bool { - if (self.min.order(ver) != .lt) return true; - if (self.max.order(ver) == .lt) return false; - return null; - } - }; - - pub fn order(lhs: Version, rhs: Version) std.math.Order { - if (lhs.major < rhs.major) return .lt; - if (lhs.major > rhs.major) return .gt; - if (lhs.minor < rhs.minor) return .lt; - if (lhs.minor > rhs.minor) return .gt; - if (lhs.patch < rhs.patch) return .lt; - if (lhs.patch > rhs.patch) return .gt; - return .eq; - } - - pub fn parse(text: []const u8) !Version { - var end: usize = 0; - while (end < text.len) : (end += 1) { - const c = text[end]; - if (!std.ascii.isDigit(c) and c != '.') break; - } - // found no digits or '.' before unexpected character - if (end == 0) return error.InvalidVersion; - - var it = std.mem.splitScalar(u8, text[0..end], '.'); - // substring is not empty, first call will succeed - const major = it.first(); - if (major.len == 0) return error.InvalidVersion; - const minor = it.next() orelse "0"; - // ignore 'patch' if 'minor' is invalid - const patch = if (minor.len == 0) "0" else (it.next() orelse "0"); - - return Version{ - .major = try std.fmt.parseUnsigned(u32, major, 10), - .minor = try std.fmt.parseUnsigned(u32, if (minor.len == 0) "0" else minor, 10), - .patch = try std.fmt.parseUnsigned(u32, if (patch.len == 0) "0" else patch, 10), - }; - } - - pub fn format( - self: Version, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - out_stream: anytype, - ) !void { - _ = options; - if (fmt.len == 0) { - if (self.patch == 0) { - if (self.minor == 0) { - return std.fmt.format(out_stream, "{d}", .{self.major}); - } else { - return std.fmt.format(out_stream, "{d}.{d}", .{ self.major, self.minor }); - } - } else { - return std.fmt.format(out_stream, "{d}.{d}.{d}", .{ self.major, self.minor, self.patch }); - } - } else { - std.fmt.invalidFmtError(fmt, self); - } - } -}; - -test "Version.parse" { - @setEvalBranchQuota(3000); - try testVersionParse(); - comptime (try testVersionParse()); -} - -fn testVersionParse() !void { - const f = struct { - fn eql(text: []const u8, v1: u32, v2: u32, v3: u32) !void { - const v = try Version.parse(text); - try std.testing.expect(v.major == v1 and v.minor == v2 and v.patch == v3); - } - - fn err(text: []const u8, expected_err: anyerror) !void { - _ = Version.parse(text) catch |actual_err| { - if (actual_err == expected_err) return; - return actual_err; - }; - return error.Unreachable; - } - }; - - try f.eql("2.6.32.11-svn21605", 2, 6, 32); // Debian PPC - try f.eql("2.11.2(0.329/5/3)", 2, 11, 2); // MinGW - try f.eql("5.4.0-1018-raspi", 5, 4, 0); // Ubuntu - try f.eql("5.7.12_3", 5, 7, 12); // Void - try f.eql("2.13-DEVELOPMENT", 2, 13, 0); // DragonFly - try f.eql("2.3-35", 2, 3, 0); - try f.eql("1a.4", 1, 0, 0); - try f.eql("3.b1.0", 3, 0, 0); - try f.eql("1.4beta", 1, 4, 0); - try f.eql("2.7.pre", 2, 7, 0); - try f.eql("0..3", 0, 0, 0); - try f.eql("8.008.", 8, 8, 0); - try f.eql("01...", 1, 0, 0); - try f.eql("55", 55, 0, 0); - try f.eql("4294967295.0.1", 4294967295, 0, 1); - try f.eql("429496729_6", 429496729, 0, 0); - - try f.err("foobar", error.InvalidVersion); - try f.err("", error.InvalidVersion); - try f.err("-1", error.InvalidVersion); - try f.err("+4", error.InvalidVersion); - try f.err(".", error.InvalidVersion); - try f.err("....3", error.InvalidVersion); - try f.err("4294967296", error.Overflow); - try f.err("5000877755", error.Overflow); - // error.InvalidCharacter is not possible anymore -} - /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const CallModifier = enum { diff --git a/lib/std/c.zig b/lib/std/c.zig index 7cc4adf815..c0ee29445a 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -20,7 +20,7 @@ pub const Tokenizer = tokenizer.Tokenizer; /// If linking gnu libc (glibc), the `ok` value will be true if the target /// version is greater than or equal to `glibc_version`. /// If linking a libc other than these, returns `false`. -pub fn versionCheck(comptime glibc_version: std.builtin.Version) type { +pub fn versionCheck(comptime glibc_version: std.SemanticVersion) type { return struct { pub const ok = blk: { if (!builtin.link_libc) break :blk false; diff --git a/lib/std/crypto/tlcsprng.zig b/lib/std/crypto/tlcsprng.zig index ac706e5f6a..54a30cfaba 100644 --- a/lib/std/crypto/tlcsprng.zig +++ b/lib/std/crypto/tlcsprng.zig @@ -38,6 +38,7 @@ const want_fork_safety = os_has_fork and !os_has_arc4random and const maybe_have_wipe_on_fork = builtin.os.isAtLeast(.linux, .{ .major = 4, .minor = 14, + .patch = 0, }) orelse true; const is_haiku = builtin.os.tag == .haiku; diff --git a/lib/std/os.zig b/lib/std/os.zig index 4699d0186c..802bb1d8df 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -488,7 +488,7 @@ pub fn getrandom(buffer: []u8) GetRandomError!void { if (builtin.os.tag == .linux or builtin.os.tag == .freebsd) { var buf = buffer; const use_c = builtin.os.tag != .linux or - std.c.versionCheck(std.builtin.Version{ .major = 2, .minor = 25, .patch = 0 }).ok; + std.c.versionCheck(std.SemanticVersion{ .major = 2, .minor = 25, .patch = 0 }).ok; while (buf.len != 0) { const res = if (use_c) blk: { @@ -5272,7 +5272,7 @@ pub fn getFdPath(fd: fd_t, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { return target; }, .freebsd => { - if (comptime builtin.os.version_range.semver.max.order(.{ .major = 13, .minor = 0 }) == .gt) { + if (comptime builtin.os.version_range.semver.max.order(.{ .major = 13, .minor = 0, .patch = 0 }) == .gt) { var kfile: system.kinfo_file = undefined; kfile.structsize = system.KINFO_FILE_SIZE; switch (errno(system.fcntl(fd, system.F.KINFO, @ptrToInt(&kfile)))) { @@ -5325,7 +5325,7 @@ pub fn getFdPath(fd: fd_t, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { } }, .dragonfly => { - if (comptime builtin.os.version_range.semver.max.order(.{ .major = 6, .minor = 0 }) == .lt) { + if (comptime builtin.os.version_range.semver.max.order(.{ .major = 6, .minor = 0, .patch = 0 }) == .lt) { @compileError("querying for canonical path of a handle is unsupported on this host"); } @memset(out_buffer[0..MAX_PATH_BYTES], 0); @@ -5339,7 +5339,7 @@ pub fn getFdPath(fd: fd_t, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { return out_buffer[0..len]; }, .netbsd => { - if (comptime builtin.os.version_range.semver.max.order(.{ .major = 10, .minor = 0 }) == .lt) { + if (comptime builtin.os.version_range.semver.max.order(.{ .major = 10, .minor = 0, .patch = 0 }) == .lt) { @compileError("querying for canonical path of a handle is unsupported on this host"); } @memset(out_buffer[0..MAX_PATH_BYTES], 0); @@ -6152,9 +6152,9 @@ pub fn sendfile( .linux => sf: { // sendfile() first appeared in Linux 2.2, glibc 2.1. const call_sf = comptime if (builtin.link_libc) - std.c.versionCheck(.{ .major = 2, .minor = 1 }).ok + std.c.versionCheck(.{ .major = 2, .minor = 1, .patch = 0 }).ok else - builtin.os.version_range.linux.range.max.order(.{ .major = 2, .minor = 2 }) != .lt; + builtin.os.version_range.linux.range.max.order(.{ .major = 2, .minor = 2, .patch = 0 }) != .lt; if (!call_sf) break :sf; if (headers.len != 0) { @@ -6453,8 +6453,8 @@ var has_copy_file_range_syscall = std.atomic.Atomic(bool).init(true); /// /// Maximum offsets on Linux and FreeBSD are `math.maxInt(i64)`. pub fn copy_file_range(fd_in: fd_t, off_in: u64, fd_out: fd_t, off_out: u64, len: usize, flags: u32) CopyFileRangeError!usize { - if ((comptime builtin.os.isAtLeast(.freebsd, .{ .major = 13, .minor = 0 }) orelse false) or - ((comptime builtin.os.isAtLeast(.linux, .{ .major = 4, .minor = 5 }) orelse false and + if ((comptime builtin.os.isAtLeast(.freebsd, .{ .major = 13, .minor = 0, .patch = 0 }) orelse false) or + ((comptime builtin.os.isAtLeast(.linux, .{ .major = 4, .minor = 5, .patch = 0 }) orelse false and std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 }).ok) and has_copy_file_range_syscall.load(.Monotonic))) { @@ -6787,7 +6787,7 @@ pub fn memfd_createZ(name: [*:0]const u8, flags: u32) MemFdCreateError!fd_t { } }, .freebsd => { - if (comptime builtin.os.version_range.semver.max.order(.{ .major = 13, .minor = 0 }) == .lt) + if (comptime builtin.os.version_range.semver.max.order(.{ .major = 13, .minor = 0, .patch = 0 }) == .lt) @compileError("memfd_create is unavailable on FreeBSD < 13.0"); const rc = system.memfd_create(name, flags); switch (errno(rc)) { diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig index e7b66c0d55..59575e0109 100644 --- a/lib/std/os/test.zig +++ b/lib/std/os/test.zig @@ -541,7 +541,7 @@ test "memfd_create" { switch (native_os) { .linux => {}, .freebsd => { - if (comptime builtin.os.version_range.semver.max.order(.{ .major = 13, .minor = 0 }) == .lt) + if (comptime builtin.os.version_range.semver.max.order(.{ .major = 13, .minor = 0, .patch = 0 }) == .lt) return error.SkipZigTest; }, else => return error.SkipZigTest, diff --git a/lib/std/target.zig b/lib/std/target.zig index 4c7bcfc37a..995edd02f7 100644 --- a/lib/std/target.zig +++ b/lib/std/target.zig @@ -1,7 +1,7 @@ const std = @import("std.zig"); const builtin = @import("builtin"); const mem = std.mem; -const Version = std.builtin.Version; +const Version = std.SemanticVersion; /// TODO Nearly all the functions in this namespace would be /// better off if https://github.com/ziglang/zig/issues/425 @@ -272,75 +272,75 @@ pub const Target = struct { .freebsd => return .{ .semver = Version.Range{ - .min = .{ .major = 12, .minor = 0 }, - .max = .{ .major = 13, .minor = 1 }, + .min = .{ .major = 12, .minor = 0, .patch = 0 }, + .max = .{ .major = 13, .minor = 1, .patch = 0 }, }, }, .macos => return switch (arch) { .aarch64 => VersionRange{ .semver = .{ .min = .{ .major = 11, .minor = 7, .patch = 1 }, - .max = .{ .major = 13, .minor = 3 }, + .max = .{ .major = 13, .minor = 3, .patch = 0 }, }, }, .x86_64 => VersionRange{ .semver = .{ .min = .{ .major = 11, .minor = 7, .patch = 1 }, - .max = .{ .major = 13, .minor = 3 }, + .max = .{ .major = 13, .minor = 3, .patch = 0 }, }, }, else => unreachable, }, .ios => return .{ .semver = .{ - .min = .{ .major = 12, .minor = 0 }, + .min = .{ .major = 12, .minor = 0, .patch = 0 }, .max = .{ .major = 13, .minor = 4, .patch = 0 }, }, }, .watchos => return .{ .semver = .{ - .min = .{ .major = 6, .minor = 0 }, + .min = .{ .major = 6, .minor = 0, .patch = 0 }, .max = .{ .major = 6, .minor = 2, .patch = 0 }, }, }, .tvos => return .{ .semver = .{ - .min = .{ .major = 13, .minor = 0 }, + .min = .{ .major = 13, .minor = 0, .patch = 0 }, .max = .{ .major = 13, .minor = 4, .patch = 0 }, }, }, .netbsd => return .{ .semver = .{ - .min = .{ .major = 8, .minor = 0 }, - .max = .{ .major = 10, .minor = 0 }, + .min = .{ .major = 8, .minor = 0, .patch = 0 }, + .max = .{ .major = 10, .minor = 0, .patch = 0 }, }, }, .openbsd => return .{ .semver = .{ - .min = .{ .major = 6, .minor = 8 }, - .max = .{ .major = 7, .minor = 2 }, + .min = .{ .major = 6, .minor = 8, .patch = 0 }, + .max = .{ .major = 7, .minor = 2, .patch = 0 }, }, }, .dragonfly => return .{ .semver = .{ - .min = .{ .major = 5, .minor = 8 }, - .max = .{ .major = 6, .minor = 4 }, + .min = .{ .major = 5, .minor = 8, .patch = 0 }, + .max = .{ .major = 6, .minor = 4, .patch = 0 }, }, }, .solaris => return .{ .semver = .{ - .min = .{ .major = 5, .minor = 11 }, - .max = .{ .major = 5, .minor = 11 }, + .min = .{ .major = 5, .minor = 11, .patch = 0 }, + .max = .{ .major = 5, .minor = 11, .patch = 0 }, }, }, .linux => return .{ .linux = .{ .range = .{ - .min = .{ .major = 3, .minor = 16 }, + .min = .{ .major = 3, .minor = 16, .patch = 0 }, .max = .{ .major = 5, .minor = 10, .patch = 81 }, }, - .glibc = .{ .major = 2, .minor = 19 }, + .glibc = .{ .major = 2, .minor = 19, .patch = 0 }, }, }, diff --git a/lib/std/zig.zig b/lib/std/zig.zig index 98edeabd10..fe6d2ec120 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -108,7 +108,7 @@ pub const BinNameOptions = struct { target: std.Target, output_mode: std.builtin.OutputMode, link_mode: ?std.builtin.LinkMode = null, - version: ?std.builtin.Version = null, + version: ?std.SemanticVersion = null, }; /// Returns the standard file system basename of a binary generated by the Zig compiler. diff --git a/lib/std/zig/CrossTarget.zig b/lib/std/zig/CrossTarget.zig index 6432c733c6..13219888b2 100644 --- a/lib/std/zig/CrossTarget.zig +++ b/lib/std/zig/CrossTarget.zig @@ -33,7 +33,7 @@ os_version_max: ?OsVersion = null, /// `null` means default when cross compiling, or native when os_tag is native. /// If `isGnuLibC()` is `false`, this must be `null` and is ignored. -glibc_version: ?SemVer = null, +glibc_version: ?SemanticVersion = null, /// `null` means the native C ABI, if `os_tag` is native, otherwise it means the default C ABI. abi: ?Target.Abi = null, @@ -61,11 +61,11 @@ pub const CpuModel = union(enum) { pub const OsVersion = union(enum) { none: void, - semver: SemVer, + semver: SemanticVersion, windows: Target.Os.WindowsVersion, }; -pub const SemVer = std.builtin.Version; +pub const SemanticVersion = std.SemanticVersion; pub const DynamicLinker = Target.DynamicLinker; @@ -266,9 +266,8 @@ pub fn parse(args: ParseOptions) !CrossTarget { const abi_ver_text = abi_it.rest(); if (abi_it.next() != null) { if (result.isGnuLibC()) { - result.glibc_version = SemVer.parse(abi_ver_text) catch |err| switch (err) { + result.glibc_version = parseVersion(abi_ver_text) catch |err| switch (err) { error.Overflow => return error.InvalidAbiVersion, - error.InvalidCharacter => return error.InvalidAbiVersion, error.InvalidVersion => return error.InvalidAbiVersion, }; } else { @@ -353,6 +352,31 @@ pub fn parseCpuArch(args: ParseOptions) ?Target.Cpu.Arch { } } +/// Parses a version with an omitted patch component, such as "1.0", +/// which SemanticVersion.parse is not capable of. +fn parseVersion(ver: []const u8) !SemanticVersion { + const parseVersionComponent = struct { + fn parseVersionComponent(component: []const u8) !usize { + return std.fmt.parseUnsigned(usize, component, 10) catch |err| { + switch (err) { + error.InvalidCharacter => return error.InvalidVersion, + error.Overflow => return error.Overflow, + } + }; + } + }.parseVersionComponent; + var version_components = mem.split(u8, ver, "."); + const major = version_components.first(); + const minor = version_components.next() orelse return error.InvalidVersion; + const patch = version_components.next() orelse "0"; + if (version_components.next() != null) return error.InvalidVersion; + return .{ + .major = try parseVersionComponent(major), + .minor = try parseVersionComponent(minor), + .patch = try parseVersionComponent(patch), + }; +} + /// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`. pub fn getCpu(self: CrossTarget) Target.Cpu { switch (self.cpu_model) { @@ -534,6 +558,16 @@ pub fn isNative(self: CrossTarget) bool { return self.isNativeCpu() and self.isNativeOs() and self.isNativeAbi(); } +/// Formats a version with the patch component omitted if it is zero, +/// unlike SemanticVersion.format which formats all its version components regardless. +fn formatVersion(version: SemanticVersion, writer: anytype) !void { + if (version.patch == 0) { + try writer.print("{d}.{d}", .{ version.major, version.minor }); + } else { + try writer.print("{d}.{d}.{d}", .{ version.major, version.minor, version.patch }); + } +} + pub fn zigTriple(self: CrossTarget, allocator: mem.Allocator) error{OutOfMemory}![]u8 { if (self.isNative()) { return allocator.dupe(u8, "native"); @@ -552,20 +586,27 @@ pub fn zigTriple(self: CrossTarget, allocator: mem.Allocator) error{OutOfMemory} if (self.os_version_min != null or self.os_version_max != null) { switch (self.getOsVersionMin()) { .none => {}, - .semver => |v| try result.writer().print(".{}", .{v}), + .semver => |v| { + try result.writer().writeAll("."); + try formatVersion(v, result.writer()); + }, .windows => |v| try result.writer().print("{s}", .{v}), } } if (self.os_version_max) |max| { switch (max) { .none => {}, - .semver => |v| try result.writer().print("...{}", .{v}), + .semver => |v| { + try result.writer().writeAll("..."); + try formatVersion(v, result.writer()); + }, .windows => |v| try result.writer().print("..{s}", .{v}), } } if (self.glibc_version) |v| { - try result.writer().print("-{s}.{}", .{ @tagName(self.getAbi()), v }); + try result.writer().print("-{s}.", .{@tagName(self.getAbi())}); + try formatVersion(v, result.writer()); } else if (self.abi) |abi| { try result.writer().print("-{s}", .{@tagName(abi)}); } @@ -630,7 +671,7 @@ pub fn isGnuLibC(self: CrossTarget) bool { pub fn setGnuLibCVersion(self: *CrossTarget, major: u32, minor: u32, patch: u32) void { assert(self.isGnuLibC()); - self.glibc_version = SemVer{ .major = major, .minor = minor, .patch = patch }; + self.glibc_version = SemanticVersion{ .major = major, .minor = minor, .patch = patch }; } pub fn getObjectFormat(self: CrossTarget) Target.ObjectFormat { @@ -709,17 +750,15 @@ fn parseOs(result: *CrossTarget, diags: *ParseOptions.Diagnostics, text: []const var range_it = mem.splitSequence(u8, version_text, "..."); const min_text = range_it.next().?; - const min_ver = SemVer.parse(min_text) catch |err| switch (err) { + const min_ver = parseVersion(min_text) catch |err| switch (err) { error.Overflow => return error.InvalidOperatingSystemVersion, - error.InvalidCharacter => return error.InvalidOperatingSystemVersion, error.InvalidVersion => return error.InvalidOperatingSystemVersion, }; result.os_version_min = .{ .semver = min_ver }; const max_text = range_it.next() orelse return; - const max_ver = SemVer.parse(max_text) catch |err| switch (err) { + const max_ver = parseVersion(max_text) catch |err| switch (err) { error.Overflow => return error.InvalidOperatingSystemVersion, - error.InvalidCharacter => return error.InvalidOperatingSystemVersion, error.InvalidVersion => return error.InvalidOperatingSystemVersion, }; result.os_version_max = .{ .semver = max_ver }; diff --git a/lib/std/zig/system/NativeTargetInfo.zig b/lib/std/zig/system/NativeTargetInfo.zig index cddaea2295..2daac4881d 100644 --- a/lib/std/zig/system/NativeTargetInfo.zig +++ b/lib/std/zig/system/NativeTargetInfo.zig @@ -43,24 +43,22 @@ pub fn detect(cross_target: CrossTarget) DetectError!NativeTargetInfo { const release = mem.sliceTo(&uts.release, 0); // The release field sometimes has a weird format, // `Version.parse` will attempt to find some meaningful interpretation. - if (std.builtin.Version.parse(release)) |ver| { + if (std.SemanticVersion.parse(release)) |ver| { os.version_range.linux.range.min = ver; os.version_range.linux.range.max = ver; } else |err| switch (err) { error.Overflow => {}, - error.InvalidCharacter => {}, error.InvalidVersion => {}, } }, .solaris => { const uts = std.os.uname(); const release = mem.sliceTo(&uts.release, 0); - if (std.builtin.Version.parse(release)) |ver| { + if (std.SemanticVersion.parse(release)) |ver| { os.version_range.semver.min = ver; os.version_range.semver.max = ver; } else |err| switch (err) { error.Overflow => {}, - error.InvalidCharacter => {}, error.InvalidVersion => {}, } }, @@ -144,7 +142,7 @@ pub fn detect(cross_target: CrossTarget) DetectError!NativeTargetInfo { error.Unexpected => return error.OSVersionDetectionFail, }; - if (std.builtin.Version.parse(buf[0 .. len - 1])) |ver| { + if (std.SemanticVersion.parse(buf[0 .. len - 1])) |ver| { os.version_range.semver.min = ver; os.version_range.semver.max = ver; } else |_| { @@ -390,7 +388,7 @@ fn detectAbiAndDynamicLinker( }; } -fn glibcVerFromRPath(rpath: []const u8) !std.builtin.Version { +fn glibcVerFromRPath(rpath: []const u8) !std.SemanticVersion { var dir = fs.cwd().openDir(rpath, .{}) catch |err| switch (err) { error.NameTooLong => unreachable, error.InvalidUtf8 => unreachable, @@ -471,7 +469,7 @@ fn glibcVerFromRPath(rpath: []const u8) !std.builtin.Version { }; } -fn glibcVerFromSoFile(file: fs.File) !std.builtin.Version { +fn glibcVerFromSoFile(file: fs.File) !std.SemanticVersion { var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 align(@alignOf(elf.Elf64_Ehdr)) = undefined; _ = try preadMin(file, &hdr_buf, 0, hdr_buf.len); const hdr32 = @ptrCast(*elf.Elf32_Ehdr, &hdr_buf); @@ -557,13 +555,12 @@ fn glibcVerFromSoFile(file: fs.File) !std.builtin.Version { const dynstr_bytes = buf[0..dynstr_size]; _ = try preadMin(file, dynstr_bytes, dynstr.offset, dynstr_bytes.len); var it = mem.splitScalar(u8, dynstr_bytes, 0); - var max_ver: std.builtin.Version = .{ .major = 2, .minor = 2, .patch = 5 }; + var max_ver: std.SemanticVersion = .{ .major = 2, .minor = 2, .patch = 5 }; while (it.next()) |s| { if (mem.startsWith(u8, s, "GLIBC_2.")) { const chopped = s["GLIBC_".len..]; - const ver = std.builtin.Version.parse(chopped) catch |err| switch (err) { + const ver = std.SemanticVersion.parse(chopped) catch |err| switch (err) { error.Overflow => return error.InvalidGnuLibCVersion, - error.InvalidCharacter => return error.InvalidGnuLibCVersion, error.InvalidVersion => return error.InvalidGnuLibCVersion, }; switch (ver.order(max_ver)) { @@ -575,7 +572,7 @@ fn glibcVerFromSoFile(file: fs.File) !std.builtin.Version { return max_ver; } -fn glibcVerFromLinkName(link_name: []const u8, prefix: []const u8) !std.builtin.Version { +fn glibcVerFromLinkName(link_name: []const u8, prefix: []const u8) !std.SemanticVersion { // example: "libc-2.3.4.so" // example: "libc-2.27.so" // example: "ld-2.33.so" @@ -585,9 +582,8 @@ fn glibcVerFromLinkName(link_name: []const u8, prefix: []const u8) !std.builtin. } // chop off "libc-" and ".so" const link_name_chopped = link_name[prefix.len .. link_name.len - suffix.len]; - return std.builtin.Version.parse(link_name_chopped) catch |err| switch (err) { + return std.SemanticVersion.parse(link_name_chopped) catch |err| switch (err) { error.Overflow => return error.InvalidGnuLibCVersion, - error.InvalidCharacter => return error.InvalidGnuLibCVersion, error.InvalidVersion => return error.InvalidGnuLibCVersion, }; } diff --git a/lib/std/zig/system/darwin.zig b/lib/std/zig/system/darwin.zig index fbddaa799a..05762ffc54 100644 --- a/lib/std/zig/system/darwin.zig +++ b/lib/std/zig/system/darwin.zig @@ -2,7 +2,7 @@ const std = @import("std"); const mem = std.mem; const Allocator = mem.Allocator; const Target = std.Target; -const Version = std.builtin.Version; +const Version = std.SemanticVersion; pub const macos = @import("darwin/macos.zig"); @@ -69,6 +69,7 @@ pub fn getDarwinSDK(allocator: Allocator, target: Target) ?DarwinSDK { const version = Version.parse(raw_version) catch Version{ .major = 0, .minor = 0, + .patch = 0, }; break :version version; }; diff --git a/lib/std/zig/system/darwin/macos.zig b/lib/std/zig/system/darwin/macos.zig index eef2f77a62..6717b1319f 100644 --- a/lib/std/zig/system/darwin/macos.zig +++ b/lib/std/zig/system/darwin/macos.zig @@ -74,20 +74,39 @@ pub fn detect(target_os: *Target.Os) !void { return error.OSVersionDetectionFail; } -fn parseSystemVersion(buf: []const u8) !std.builtin.Version { +fn parseSystemVersion(buf: []const u8) !std.SemanticVersion { var svt = SystemVersionTokenizer{ .bytes = buf }; try svt.skipUntilTag(.start, "dict"); while (true) { try svt.skipUntilTag(.start, "key"); const content = try svt.expectContent(); try svt.skipUntilTag(.end, "key"); - if (std.mem.eql(u8, content, "ProductVersion")) break; + if (mem.eql(u8, content, "ProductVersion")) break; } try svt.skipUntilTag(.start, "string"); const ver = try svt.expectContent(); try svt.skipUntilTag(.end, "string"); - return std.builtin.Version.parse(ver); + const parseVersionComponent = struct { + fn parseVersionComponent(component: []const u8) !usize { + return std.fmt.parseUnsigned(usize, component, 10) catch |err| { + switch (err) { + error.InvalidCharacter => return error.InvalidVersion, + error.Overflow => return error.Overflow, + } + }; + } + }.parseVersionComponent; + var version_components = mem.split(u8, ver, "."); + const major = version_components.first(); + const minor = version_components.next() orelse return error.InvalidVersion; + const patch = version_components.next() orelse "0"; + if (version_components.next() != null) return error.InvalidVersion; + return .{ + .major = try parseVersionComponent(major), + .minor = try parseVersionComponent(minor), + .patch = try parseVersionComponent(patch), + }; } const SystemVersionTokenizer = struct { @@ -246,7 +265,7 @@ const SystemVersionTokenizer = struct { while (try self.next()) |tok| { switch (tok) { .tag => |tag| { - if (tag.kind == kind and std.mem.eql(u8, tag.name, name)) return; + if (tag.kind == kind and mem.eql(u8, tag.name, name)) return; }, else => {}, } @@ -297,7 +316,7 @@ test "detect" { \\ \\ , - .{ .major = 10, .minor = 3 }, + .{ .major = 10, .minor = 3, .patch = 0 }, }, .{ \\ @@ -361,7 +380,7 @@ test "detect" { \\ \\ , - .{ .major = 11, .minor = 0 }, + .{ .major = 11, .minor = 0, .patch = 0 }, }, .{ \\ @@ -383,27 +402,17 @@ test "detect" { \\ \\ , - .{ .major = 11, .minor = 1 }, + .{ .major = 11, .minor = 1, .patch = 0 }, }, }; inline for (cases) |case| { const ver0 = try parseSystemVersion(case[0]); - const ver1: std.builtin.Version = case[1]; - try testVersionEquality(ver1, ver0); + const ver1: std.SemanticVersion = case[1]; + try testing.expectEqual(@as(std.math.Order, .eq), ver0.order(ver1)); } } -fn testVersionEquality(expected: std.builtin.Version, got: std.builtin.Version) !void { - var b_expected: [64]u8 = undefined; - const s_expected: []const u8 = try std.fmt.bufPrint(b_expected[0..], "{}", .{expected}); - - var b_got: [64]u8 = undefined; - const s_got: []const u8 = try std.fmt.bufPrint(b_got[0..], "{}", .{got}); - - try testing.expectEqualStrings(s_expected, s_got); -} - pub fn detectNativeCpuAndFeatures() ?Target.Cpu { var cpu_family: std.c.CPUFAMILY = undefined; var len: usize = @sizeOf(std.c.CPUFAMILY); diff --git a/src/Compilation.zig b/src/Compilation.zig index 662dcdc408..739b747e32 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -615,8 +615,8 @@ pub const InitOptions = struct { stack_size_override: ?u64 = null, image_base_override: ?u64 = null, self_exe_path: ?[]const u8 = null, - version: ?std.builtin.Version = null, - compatibility_version: ?std.builtin.Version = null, + version: ?std.SemanticVersion = null, + compatibility_version: ?std.SemanticVersion = null, libc_installation: ?*const LibCInstallation = null, machine_code_model: std.builtin.CodeModel = .default, clang_preprocessor_mode: ClangPreprocessorMode = .no, diff --git a/src/codegen/spirv/spec.zig b/src/codegen/spirv/spec.zig index 60d16461cb..f73487f41f 100644 --- a/src/codegen/spirv/spec.zig +++ b/src/codegen/spirv/spec.zig @@ -1,6 +1,6 @@ //! This file is auto-generated by tools/gen_spirv_spec.zig. -const Version = @import("std").builtin.Version; +const Version = @import("std").SemanticVersion; pub const Word = u32; pub const IdResult = struct { diff --git a/src/glibc.zig b/src/glibc.zig index 4ab00eeed9..bb38c2c987 100644 --- a/src/glibc.zig +++ b/src/glibc.zig @@ -5,7 +5,7 @@ const log = std.log; const fs = std.fs; const path = fs.path; const assert = std.debug.assert; -const Version = std.builtin.Version; +const Version = std.SemanticVersion; const target_util = @import("target.zig"); const Compilation = @import("Compilation.zig"); @@ -172,7 +172,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr const target = comp.getTarget(); const target_ver = target.os.version_range.linux.glibc; - const start_old_init_fini = target_ver.order(.{ .major = 2, .minor = 33 }) != .gt; + const start_old_init_fini = target_ver.order(.{ .major = 2, .minor = 33, .patch = 0 }) != .gt; // In all cases in this function, we add the C compiler flags to // cache_exempt_flags rather than extra_flags, because these arguments diff --git a/src/link.zig b/src/link.zig index c184f7ed7c..9458bd6c0a 100644 --- a/src/link.zig +++ b/src/link.zig @@ -197,8 +197,8 @@ pub const Options = struct { /// __real_symbol. symbol_wrap_set: std.StringArrayHashMapUnmanaged(void), - version: ?std.builtin.Version, - compatibility_version: ?std.builtin.Version, + version: ?std.SemanticVersion, + compatibility_version: ?std.SemanticVersion, libc_installation: ?*const LibCInstallation, dwarf_format: ?std.dwarf.Format, diff --git a/src/link/Elf.zig b/src/link/Elf.zig index e0d0dfc75f..b2e7f57211 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -3414,7 +3414,7 @@ const CsuObjects = struct { if (result.crtn) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, obj.* }); var gccv: []const u8 = undefined; - if (link_options.target.os.version_range.semver.isAtLeast(.{ .major = 5, .minor = 4 }) orelse true) { + if (link_options.target.os.version_range.semver.isAtLeast(.{ .major = 5, .minor = 4, .patch = 0 }) orelse true) { gccv = "gcc80"; } else { gccv = "gcc54"; diff --git a/src/link/MachO/load_commands.zig b/src/link/MachO/load_commands.zig index 5111f53f2a..eb582e2222 100644 --- a/src/link/MachO/load_commands.zig +++ b/src/link/MachO/load_commands.zig @@ -204,12 +204,12 @@ pub fn writeDylibIdLC(gpa: Allocator, options: *const link.Options, lc_writer: a const emit = options.emit.?; const install_name = options.install_name orelse try emit.directory.join(gpa, &.{emit.sub_path}); defer if (options.install_name == null) gpa.free(install_name); - const curr = options.version orelse std.builtin.Version{ + const curr = options.version orelse std.SemanticVersion{ .major = 1, .minor = 0, .patch = 0, }; - const compat = options.compatibility_version orelse std.builtin.Version{ + const compat = options.compatibility_version orelse std.SemanticVersion{ .major = 1, .minor = 0, .patch = 0, @@ -217,8 +217,8 @@ pub fn writeDylibIdLC(gpa: Allocator, options: *const link.Options, lc_writer: a try writeDylibLC(.{ .cmd = .ID_DYLIB, .name = install_name, - .current_version = curr.major << 16 | curr.minor << 8 | curr.patch, - .compatibility_version = compat.major << 16 | compat.minor << 8 | compat.patch, + .current_version = @intCast(u32, curr.major << 16 | curr.minor << 8 | curr.patch), + .compatibility_version = @intCast(u32, compat.major << 16 | compat.minor << 8 | compat.patch), }, lc_writer); } @@ -275,12 +275,12 @@ pub fn writeBuildVersionLC(options: *const link.Options, lc_writer: anytype) !vo const cmdsize = @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version); const platform_version = blk: { const ver = options.target.os.version_range.semver.min; - const platform_version = ver.major << 16 | ver.minor << 8; + const platform_version = @intCast(u32, ver.major << 16 | ver.minor << 8); break :blk platform_version; }; const sdk_version = if (options.native_darwin_sdk) |sdk| blk: { const ver = sdk.version; - const sdk_version = ver.major << 16 | ver.minor << 8; + const sdk_version = @intCast(u32, ver.major << 16 | ver.minor << 8); break :blk sdk_version; } else platform_version; const is_simulator_abi = options.target.abi == .simulator; diff --git a/src/main.zig b/src/main.zig index b245b357ca..2f56cad133 100644 --- a/src/main.zig +++ b/src/main.zig @@ -724,9 +724,9 @@ fn buildOutputType( var dll_export_fns: ?bool = null; var single_threaded: ?bool = null; var root_src_file: ?[]const u8 = null; - var version: std.builtin.Version = .{ .major = 0, .minor = 0, .patch = 0 }; + var version: std.SemanticVersion = .{ .major = 0, .minor = 0, .patch = 0 }; var have_version = false; - var compatibility_version: ?std.builtin.Version = null; + var compatibility_version: ?std.SemanticVersion = null; var strip: ?bool = null; var formatted_panics: ?bool = null; var function_sections = false; @@ -1121,7 +1121,7 @@ fn buildOutputType( try cssan.addIncludePath(.iframework, arg, args_iter.nextOrFatal(), false); } else if (mem.eql(u8, arg, "--version")) { const next_arg = args_iter.nextOrFatal(); - version = std.builtin.Version.parse(next_arg) catch |err| { + version = std.SemanticVersion.parse(next_arg) catch |err| { fatal("unable to parse --version '{s}': {s}", .{ next_arg, @errorName(err) }); }; have_version = true; @@ -2152,12 +2152,12 @@ fn buildOutputType( try system_libs.put(linker_args_it.nextOrFatal(), .{ .weak = true }); } else if (mem.eql(u8, arg, "-compatibility_version")) { const compat_version = linker_args_it.nextOrFatal(); - compatibility_version = std.builtin.Version.parse(compat_version) catch |err| { + compatibility_version = std.SemanticVersion.parse(compat_version) catch |err| { fatal("unable to parse -compatibility_version '{s}': {s}", .{ compat_version, @errorName(err) }); }; } else if (mem.eql(u8, arg, "-current_version")) { const curr_version = linker_args_it.nextOrFatal(); - version = std.builtin.Version.parse(curr_version) catch |err| { + version = std.SemanticVersion.parse(curr_version) catch |err| { fatal("unable to parse -current_version '{s}': {s}", .{ curr_version, @errorName(err) }); }; have_version = true; @@ -2207,10 +2207,9 @@ fn buildOutputType( } else if (mem.startsWith(u8, arg, "/version:")) { var split_it = mem.splitBackwardsScalar(u8, arg, ':'); const version_arg = split_it.first(); - version = std.builtin.Version.parse(version_arg) catch |err| { + version = std.SemanticVersion.parse(version_arg) catch |err| { fatal("unable to parse /version '{s}': {s}", .{ arg, @errorName(err) }); }; - have_version = true; } else { fatal("unsupported linker arg: {s}", .{arg}); diff --git a/src/target.zig b/src/target.zig index ac78d27c1a..2d27869cf6 100644 --- a/src/target.zig +++ b/src/target.zig @@ -6,7 +6,7 @@ pub const ArchOsAbi = struct { arch: std.Target.Cpu.Arch, os: std.Target.Os.Tag, abi: std.Target.Abi, - os_ver: ?std.builtin.Version = null, + os_ver: ?std.SemanticVersion = null, }; pub const available_libcs = [_]ArchOsAbi{ @@ -16,9 +16,9 @@ pub const available_libcs = [_]ArchOsAbi{ .{ .arch = .aarch64, .os = .linux, .abi = .gnu }, .{ .arch = .aarch64, .os = .linux, .abi = .musl }, .{ .arch = .aarch64, .os = .windows, .abi = .gnu }, - .{ .arch = .aarch64, .os = .macos, .abi = .none, .os_ver = .{ .major = 11, .minor = 0 } }, - .{ .arch = .aarch64, .os = .macos, .abi = .none, .os_ver = .{ .major = 12, .minor = 0 } }, - .{ .arch = .aarch64, .os = .macos, .abi = .none, .os_ver = .{ .major = 13, .minor = 0 } }, + .{ .arch = .aarch64, .os = .macos, .abi = .none, .os_ver = .{ .major = 11, .minor = 0, .patch = 0 } }, + .{ .arch = .aarch64, .os = .macos, .abi = .none, .os_ver = .{ .major = 12, .minor = 0, .patch = 0 } }, + .{ .arch = .aarch64, .os = .macos, .abi = .none, .os_ver = .{ .major = 13, .minor = 0, .patch = 0 } }, .{ .arch = .armeb, .os = .linux, .abi = .gnueabi }, .{ .arch = .armeb, .os = .linux, .abi = .gnueabihf }, .{ .arch = .armeb, .os = .linux, .abi = .musleabi }, @@ -71,9 +71,9 @@ pub const available_libcs = [_]ArchOsAbi{ .{ .arch = .x86_64, .os = .linux, .abi = .gnux32 }, .{ .arch = .x86_64, .os = .linux, .abi = .musl }, .{ .arch = .x86_64, .os = .windows, .abi = .gnu }, - .{ .arch = .x86_64, .os = .macos, .abi = .none, .os_ver = .{ .major = 11, .minor = 0 } }, - .{ .arch = .x86_64, .os = .macos, .abi = .none, .os_ver = .{ .major = 12, .minor = 0 } }, - .{ .arch = .x86_64, .os = .macos, .abi = .none, .os_ver = .{ .major = 13, .minor = 0 } }, + .{ .arch = .x86_64, .os = .macos, .abi = .none, .os_ver = .{ .major = 11, .minor = 0, .patch = 0 } }, + .{ .arch = .x86_64, .os = .macos, .abi = .none, .os_ver = .{ .major = 12, .minor = 0, .patch = 0 } }, + .{ .arch = .x86_64, .os = .macos, .abi = .none, .os_ver = .{ .major = 13, .minor = 0, .patch = 0 } }, }; pub fn libCGenericName(target: std.Target) [:0]const u8 { diff --git a/test/link/macho/dylib/build.zig b/test/link/macho/dylib/build.zig index fe294f3333..5fbf73dd1b 100644 --- a/test/link/macho/dylib/build.zig +++ b/test/link/macho/dylib/build.zig @@ -17,7 +17,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize const dylib = b.addSharedLibrary(.{ .name = "a", - .version = .{ .major = 1, .minor = 0 }, + .version = .{ .major = 1, .minor = 0, .patch = 0 }, .optimize = optimize, .target = target, }); diff --git a/test/link/macho/needed_library/build.zig b/test/link/macho/needed_library/build.zig index 7b56572cc3..d39166c18b 100644 --- a/test/link/macho/needed_library/build.zig +++ b/test/link/macho/needed_library/build.zig @@ -17,7 +17,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize const dylib = b.addSharedLibrary(.{ .name = "a", - .version = .{ .major = 1, .minor = 0 }, + .version = .{ .major = 1, .minor = 0, .patch = 0 }, .optimize = optimize, .target = target, }); diff --git a/test/link/macho/search_strategy/build.zig b/test/link/macho/search_strategy/build.zig index 4b52d9aa0a..336ca593b1 100644 --- a/test/link/macho/search_strategy/build.zig +++ b/test/link/macho/search_strategy/build.zig @@ -61,7 +61,7 @@ fn createScenario( const dylib = b.addSharedLibrary(.{ .name = name, - .version = .{ .major = 1, .minor = 0 }, + .version = .{ .major = 1, .minor = 0, .patch = 0 }, .optimize = optimize, .target = target, }); diff --git a/test/link/macho/tls/build.zig b/test/link/macho/tls/build.zig index f155f514f8..555fe207c5 100644 --- a/test/link/macho/tls/build.zig +++ b/test/link/macho/tls/build.zig @@ -17,7 +17,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize const lib = b.addSharedLibrary(.{ .name = "a", - .version = .{ .major = 1, .minor = 0 }, + .version = .{ .major = 1, .minor = 0, .patch = 0 }, .optimize = optimize, .target = target, }); diff --git a/test/link/macho/uuid/build.zig b/test/link/macho/uuid/build.zig index 0072825f46..f2ef6b33ec 100644 --- a/test/link/macho/uuid/build.zig +++ b/test/link/macho/uuid/build.zig @@ -62,7 +62,7 @@ fn simpleDylib( ) *std.Build.Step.Compile { const dylib = b.addSharedLibrary(.{ .name = "test", - .version = .{ .major = 1, .minor = 0 }, + .version = .{ .major = 1, .minor = 0, .patch = 0 }, .optimize = optimize, .target = target, }); diff --git a/test/standalone/load_dynamic_library/build.zig b/test/standalone/load_dynamic_library/build.zig index 6dec8de7ae..a711704e46 100644 --- a/test/standalone/load_dynamic_library/build.zig +++ b/test/standalone/load_dynamic_library/build.zig @@ -13,7 +13,7 @@ pub fn build(b: *std.Build) void { const lib = b.addSharedLibrary(.{ .name = "add", .root_source_file = .{ .path = "add.zig" }, - .version = .{ .major = 1, .minor = 0 }, + .version = .{ .major = 1, .minor = 0, .patch = 0 }, .optimize = optimize, .target = target, }); diff --git a/test/standalone/shared_library/build.zig b/test/standalone/shared_library/build.zig index 377bf81862..3034d89017 100644 --- a/test/standalone/shared_library/build.zig +++ b/test/standalone/shared_library/build.zig @@ -9,7 +9,7 @@ pub fn build(b: *std.Build) void { const lib = b.addSharedLibrary(.{ .name = "mathtest", .root_source_file = .{ .path = "mathtest.zig" }, - .version = .{ .major = 1, .minor = 0 }, + .version = .{ .major = 1, .minor = 0, .patch = 0 }, .target = target, .optimize = optimize, }); diff --git a/tools/gen_spirv_spec.zig b/tools/gen_spirv_spec.zig index 28a5ed7ded..b48e3834a2 100644 --- a/tools/gen_spirv_spec.zig +++ b/tools/gen_spirv_spec.zig @@ -76,7 +76,7 @@ fn render(writer: anytype, allocator: Allocator, registry: g.CoreRegistry) !void try writer.writeAll( \\//! This file is auto-generated by tools/gen_spirv_spec.zig. \\ - \\const Version = @import("std").builtin.Version; + \\const Version = @import("std").SemanticVersion; \\ \\pub const Word = u32; \\pub const IdResult = struct{ -- cgit v1.2.3