mirror of
https://github.com/ziglang/zig.git
synced 2026-01-16 12:25:21 +00:00
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 in6e84f46990Fixes regression from6e84f46990and 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>
This commit is contained in:
parent
87a397ab0c
commit
6bf554f9a7
@ -140,13 +140,13 @@ pub fn parse(text: []const u8) !Version {
|
||||
return ver;
|
||||
}
|
||||
|
||||
fn parseNum(text: []const u8) !usize {
|
||||
fn parseNum(text: []const u8) error{ InvalidVersion, Overflow }!usize {
|
||||
// Leading zeroes are not allowed.
|
||||
if (text.len > 1 and text[0] == '0') return error.InvalidVersion;
|
||||
|
||||
return std.fmt.parseUnsigned(usize, text, 10) catch |err| switch (err) {
|
||||
error.InvalidCharacter => return error.InvalidVersion,
|
||||
else => |e| return e,
|
||||
error.Overflow => return error.Overflow,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -354,31 +354,37 @@ 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,
|
||||
}
|
||||
/// Similar to `SemanticVersion.parse`, but with following changes:
|
||||
/// * Leading zeroes are allowed.
|
||||
/// * Supports only 2 or 3 version components (major, minor, [patch]). If 3-rd component is omitted, it will be 0.
|
||||
pub fn parseVersion(ver: []const u8) error{ InvalidVersion, Overflow }!SemanticVersion {
|
||||
const parseVersionComponentFn = (struct {
|
||||
fn parseVersionComponentInner(component: []const u8) error{ InvalidVersion, Overflow }!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, ".");
|
||||
}).parseVersionComponentInner;
|
||||
var version_components = mem.splitScalar(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),
|
||||
.major = try parseVersionComponentFn(major),
|
||||
.minor = try parseVersionComponentFn(minor),
|
||||
.patch = try parseVersionComponentFn(patch),
|
||||
};
|
||||
}
|
||||
|
||||
test parseVersion {
|
||||
try std.testing.expectError(error.InvalidVersion, parseVersion("1"));
|
||||
try std.testing.expectEqual(SemanticVersion{ .major = 1, .minor = 2, .patch = 0 }, try parseVersion("1.2"));
|
||||
try std.testing.expectEqual(SemanticVersion{ .major = 1, .minor = 2, .patch = 3 }, try parseVersion("1.2.3"));
|
||||
try std.testing.expectError(error.InvalidVersion, parseVersion("1.2.3.4"));
|
||||
}
|
||||
|
||||
/// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`.
|
||||
pub fn getCpu(self: CrossTarget) Target.Cpu {
|
||||
switch (self.cpu_model) {
|
||||
|
||||
@ -557,7 +557,7 @@ fn glibcVerFromSoFile(file: fs.File) !std.SemanticVersion {
|
||||
var buf: [80000]u8 = undefined;
|
||||
if (buf.len < dynstr.size) return error.InvalidGnuLibCVersion;
|
||||
|
||||
const dynstr_size = @as(usize, @intCast(dynstr.size));
|
||||
const dynstr_size: usize = @intCast(dynstr.size);
|
||||
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);
|
||||
@ -565,7 +565,7 @@ fn glibcVerFromSoFile(file: fs.File) !std.SemanticVersion {
|
||||
while (it.next()) |s| {
|
||||
if (mem.startsWith(u8, s, "GLIBC_2.")) {
|
||||
const chopped = s["GLIBC_".len..];
|
||||
const ver = std.SemanticVersion.parse(chopped) catch |err| switch (err) {
|
||||
const ver = CrossTarget.parseVersion(chopped) catch |err| switch (err) {
|
||||
error.Overflow => return error.InvalidGnuLibCVersion,
|
||||
error.InvalidVersion => return error.InvalidGnuLibCVersion,
|
||||
};
|
||||
@ -578,7 +578,7 @@ fn glibcVerFromSoFile(file: fs.File) !std.SemanticVersion {
|
||||
return max_ver;
|
||||
}
|
||||
|
||||
fn glibcVerFromLinkName(link_name: []const u8, prefix: []const u8) !std.SemanticVersion {
|
||||
fn glibcVerFromLinkName(link_name: []const u8, prefix: []const u8) error{ UnrecognizedGnuLibCFileName, InvalidGnuLibCVersion }!std.SemanticVersion {
|
||||
// example: "libc-2.3.4.so"
|
||||
// example: "libc-2.27.so"
|
||||
// example: "ld-2.33.so"
|
||||
@ -588,12 +588,23 @@ fn glibcVerFromLinkName(link_name: []const u8, prefix: []const u8) !std.Semantic
|
||||
}
|
||||
// chop off "libc-" and ".so"
|
||||
const link_name_chopped = link_name[prefix.len .. link_name.len - suffix.len];
|
||||
return std.SemanticVersion.parse(link_name_chopped) catch |err| switch (err) {
|
||||
return CrossTarget.parseVersion(link_name_chopped) catch |err| switch (err) {
|
||||
error.Overflow => return error.InvalidGnuLibCVersion,
|
||||
error.InvalidVersion => return error.InvalidGnuLibCVersion,
|
||||
};
|
||||
}
|
||||
|
||||
test glibcVerFromLinkName {
|
||||
try std.testing.expectError(error.UnrecognizedGnuLibCFileName, glibcVerFromLinkName("ld-2.37.so", "this-prefix-does-not-exist"));
|
||||
try std.testing.expectError(error.UnrecognizedGnuLibCFileName, glibcVerFromLinkName("libc-2.37.so-is-not-end", "libc-"));
|
||||
|
||||
try std.testing.expectError(error.InvalidGnuLibCVersion, glibcVerFromLinkName("ld-2.so", "ld-"));
|
||||
try std.testing.expectEqual(std.SemanticVersion{ .major = 2, .minor = 37, .patch = 0 }, try glibcVerFromLinkName("ld-2.37.so", "ld-"));
|
||||
try std.testing.expectEqual(std.SemanticVersion{ .major = 2, .minor = 37, .patch = 0 }, try glibcVerFromLinkName("ld-2.37.0.so", "ld-"));
|
||||
try std.testing.expectEqual(std.SemanticVersion{ .major = 2, .minor = 37, .patch = 1 }, try glibcVerFromLinkName("ld-2.37.1.so", "ld-"));
|
||||
try std.testing.expectError(error.InvalidGnuLibCVersion, glibcVerFromLinkName("ld-2.37.4.5.so", "ld-"));
|
||||
}
|
||||
|
||||
pub const AbiAndDynamicLinkerFromFileError = error{
|
||||
FileSystem,
|
||||
SystemResources,
|
||||
|
||||
@ -87,26 +87,7 @@ fn parseSystemVersion(buf: []const u8) !std.SemanticVersion {
|
||||
const ver = try svt.expectContent();
|
||||
try svt.skipUntilTag(.end, "string");
|
||||
|
||||
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),
|
||||
};
|
||||
return try std.zig.CrossTarget.parseVersion(ver);
|
||||
}
|
||||
|
||||
const SystemVersionTokenizer = struct {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user