authorgravatar for bratishkaerik@getgoogleoff.meEric Joldasov <bratishkaerik@getgoogleoff.me> 2023-10-22 20:18:20+06:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-10-23 06:00:53-04:00
log6bf554f9a75b412f3d1f2306dff8c0036555f08c
treedde036caf73e984c02000e668c7c1c60394d924a
parent87a397ab0c7d1d355ce512f97ddf13d066afb9e1

std.zig.system.NativeTargetInfo: fix glibc version parsing

In most cases "GLIBC_2.X" strings and `/lib/libc-2.x.so` files do not contain third (`patch`) field, which causes std.SemanticVersion.parse function to return error. To fix this, we reuse [now-public] std.zig.CrossTarget.parseVersion function, which accounts for this third field and makes it 0 in case it was not found. This new behaviour is similar to std.builtin.Version.parse, which was removed in https://github.com/ziglang/zig/commit/6e84f469904a24615a6721265a88ad8dcb4ed83a Fixes regression from https://github.com/ziglang/zig/commit/6e84f469904a24615a6721265a88ad8dcb4ed83a and https://github.com/ziglang/zig/pull/13998 . Related: https://github.com/ziglang/zig/issues/17626 . Results with `zig end`: Before: `"target": "x86_64-linux.6.5.7...6.5.7-gnu.2.19",` After: `"target": "x86_64-linux.6.5.7...6.5.7-gnu.2.36",` Also, while we are here, write explicit error sets and remove duplicate logic from std.zig.system.darwin.macos.parseSystemVersion . Signed-off-by: Eric Joldasov <bratishkaerik@getgoogleoff.me>

4 files changed, 39 insertions(+), 41 deletions(-)

lib/std/SemanticVersion.zig+2-2
......@@ -140,13 +140,13 @@ pub fn parse(text: []const u8) !Version {
140140 return ver;
141141}
142142
143fn parseNum(text: []const u8) !usize {
143fn parseNum(text: []const u8) error{ InvalidVersion, Overflow }!usize {
144144 // Leading zeroes are not allowed.
145145 if (text.len > 1 and text[0] == '0') return error.InvalidVersion;
146146
147147 return std.fmt.parseUnsigned(usize, text, 10) catch |err| switch (err) {
148148 error.InvalidCharacter => return error.InvalidVersion,
149 else => |e| return e,
149 error.Overflow => return error.Overflow,
150150 };
151151}
152152
lib/std/zig/CrossTarget.zig+21-15
......@@ -354,31 +354,37 @@ pub fn parseCpuArch(args: ParseOptions) ?Target.Cpu.Arch {
354354 }
355355}
356356
357/// Parses a version with an omitted patch component, such as "1.0",
358/// which SemanticVersion.parse is not capable of.
359fn parseVersion(ver: []const u8) !SemanticVersion {
360 const parseVersionComponent = struct {
361 fn parseVersionComponent(component: []const u8) !usize {
362 return std.fmt.parseUnsigned(usize, component, 10) catch |err| {
363 switch (err) {
364 error.InvalidCharacter => return error.InvalidVersion,
365 error.Overflow => return error.Overflow,
366 }
357/// Similar to `SemanticVersion.parse`, but with following changes:
358/// * Leading zeroes are allowed.
359/// * Supports only 2 or 3 version components (major, minor, [patch]). If 3-rd component is omitted, it will be 0.
360pub fn parseVersion(ver: []const u8) error{ InvalidVersion, Overflow }!SemanticVersion {
361 const parseVersionComponentFn = (struct {
362 fn parseVersionComponentInner(component: []const u8) error{ InvalidVersion, Overflow }!usize {
363 return std.fmt.parseUnsigned(usize, component, 10) catch |err| switch (err) {
364 error.InvalidCharacter => return error.InvalidVersion,
365 error.Overflow => return error.Overflow,
367366 };
368367 }
369 }.parseVersionComponent;
370 var version_components = mem.split(u8, ver, ".");
368 }).parseVersionComponentInner;
369 var version_components = mem.splitScalar(u8, ver, '.');
371370 const major = version_components.first();
372371 const minor = version_components.next() orelse return error.InvalidVersion;
373372 const patch = version_components.next() orelse "0";
374373 if (version_components.next() != null) return error.InvalidVersion;
375374 return .{
376 .major = try parseVersionComponent(major),
377 .minor = try parseVersionComponent(minor),
378 .patch = try parseVersionComponent(patch),
375 .major = try parseVersionComponentFn(major),
376 .minor = try parseVersionComponentFn(minor),
377 .patch = try parseVersionComponentFn(patch),
379378 };
380379}
381380
381test parseVersion {
382 try std.testing.expectError(error.InvalidVersion, parseVersion("1"));
383 try std.testing.expectEqual(SemanticVersion{ .major = 1, .minor = 2, .patch = 0 }, try parseVersion("1.2"));
384 try std.testing.expectEqual(SemanticVersion{ .major = 1, .minor = 2, .patch = 3 }, try parseVersion("1.2.3"));
385 try std.testing.expectError(error.InvalidVersion, parseVersion("1.2.3.4"));
386}
387
382388/// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`.
383389pub fn getCpu(self: CrossTarget) Target.Cpu {
384390 switch (self.cpu_model) {
lib/std/zig/system/NativeTargetInfo.zig+15-4
......@@ -557,7 +557,7 @@ fn glibcVerFromSoFile(file: fs.File) !std.SemanticVersion {
557557 var buf: [80000]u8 = undefined;
558558 if (buf.len < dynstr.size) return error.InvalidGnuLibCVersion;
559559
560 const dynstr_size = @as(usize, @intCast(dynstr.size));
560 const dynstr_size: usize = @intCast(dynstr.size);
561561 const dynstr_bytes = buf[0..dynstr_size];
562562 _ = try preadMin(file, dynstr_bytes, dynstr.offset, dynstr_bytes.len);
563563 var it = mem.splitScalar(u8, dynstr_bytes, 0);
......@@ -565,7 +565,7 @@ fn glibcVerFromSoFile(file: fs.File) !std.SemanticVersion {
565565 while (it.next()) |s| {
566566 if (mem.startsWith(u8, s, "GLIBC_2.")) {
567567 const chopped = s["GLIBC_".len..];
568 const ver = std.SemanticVersion.parse(chopped) catch |err| switch (err) {
568 const ver = CrossTarget.parseVersion(chopped) catch |err| switch (err) {
569569 error.Overflow => return error.InvalidGnuLibCVersion,
570570 error.InvalidVersion => return error.InvalidGnuLibCVersion,
571571 };
......@@ -578,7 +578,7 @@ fn glibcVerFromSoFile(file: fs.File) !std.SemanticVersion {
578578 return max_ver;
579579}
580580
581fn glibcVerFromLinkName(link_name: []const u8, prefix: []const u8) !std.SemanticVersion {
581fn glibcVerFromLinkName(link_name: []const u8, prefix: []const u8) error{ UnrecognizedGnuLibCFileName, InvalidGnuLibCVersion }!std.SemanticVersion {
582582 // example: "libc-2.3.4.so"
583583 // example: "libc-2.27.so"
584584 // example: "ld-2.33.so"
......@@ -588,12 +588,23 @@ fn glibcVerFromLinkName(link_name: []const u8, prefix: []const u8) !std.Semantic
588588 }
589589 // chop off "libc-" and ".so"
590590 const link_name_chopped = link_name[prefix.len .. link_name.len - suffix.len];
591 return std.SemanticVersion.parse(link_name_chopped) catch |err| switch (err) {
591 return CrossTarget.parseVersion(link_name_chopped) catch |err| switch (err) {
592592 error.Overflow => return error.InvalidGnuLibCVersion,
593593 error.InvalidVersion => return error.InvalidGnuLibCVersion,
594594 };
595595}
596596
597test glibcVerFromLinkName {
598 try std.testing.expectError(error.UnrecognizedGnuLibCFileName, glibcVerFromLinkName("ld-2.37.so", "this-prefix-does-not-exist"));
599 try std.testing.expectError(error.UnrecognizedGnuLibCFileName, glibcVerFromLinkName("libc-2.37.so-is-not-end", "libc-"));
600
601 try std.testing.expectError(error.InvalidGnuLibCVersion, glibcVerFromLinkName("ld-2.so", "ld-"));
602 try std.testing.expectEqual(std.SemanticVersion{ .major = 2, .minor = 37, .patch = 0 }, try glibcVerFromLinkName("ld-2.37.so", "ld-"));
603 try std.testing.expectEqual(std.SemanticVersion{ .major = 2, .minor = 37, .patch = 0 }, try glibcVerFromLinkName("ld-2.37.0.so", "ld-"));
604 try std.testing.expectEqual(std.SemanticVersion{ .major = 2, .minor = 37, .patch = 1 }, try glibcVerFromLinkName("ld-2.37.1.so", "ld-"));
605 try std.testing.expectError(error.InvalidGnuLibCVersion, glibcVerFromLinkName("ld-2.37.4.5.so", "ld-"));
606}
607
597608pub const AbiAndDynamicLinkerFromFileError = error{
598609 FileSystem,
599610 SystemResources,
lib/std/zig/system/darwin/macos.zig+1-20
......@@ -87,26 +87,7 @@ fn parseSystemVersion(buf: []const u8) !std.SemanticVersion {
8787 const ver = try svt.expectContent();
8888 try svt.skipUntilTag(.end, "string");
8989
90 const parseVersionComponent = struct {
91 fn parseVersionComponent(component: []const u8) !usize {
92 return std.fmt.parseUnsigned(usize, component, 10) catch |err| {
93 switch (err) {
94 error.InvalidCharacter => return error.InvalidVersion,
95 error.Overflow => return error.Overflow,
96 }
97 };
98 }
99 }.parseVersionComponent;
100 var version_components = mem.split(u8, ver, ".");
101 const major = version_components.first();
102 const minor = version_components.next() orelse return error.InvalidVersion;
103 const patch = version_components.next() orelse "0";
104 if (version_components.next() != null) return error.InvalidVersion;
105 return .{
106 .major = try parseVersionComponent(major),
107 .minor = try parseVersionComponent(minor),
108 .patch = try parseVersionComponent(patch),
109 };
90 return try std.zig.CrossTarget.parseVersion(ver);
11091}
11192
11293const SystemVersionTokenizer = struct {