srctree

Andrew Kelley parent b78b2689 60d5001a a2b834e8
Merge pull request #19654 from jacobly0/wasi-ver

Target: add wasi os version

inlinesplit
lib/std/Target.zig added: 533, removed: 606, total 0
@@ -81,14 +81,48 @@ pub const Os = struct {
return tag == .solaris or tag == .illumos;
}
 
pub fn exeFileExt(tag: Tag, arch: Cpu.Arch) [:0]const u8 {
return switch (tag) {
.windows => ".exe",
.uefi => ".efi",
.plan9 => arch.plan9Ext(),
else => switch (arch) {
.wasm32, .wasm64 => ".wasm",
else => "",
},
};
}
 
pub fn staticLibSuffix(tag: Tag, abi: Abi) [:0]const u8 {
return switch (abi) {
.msvc => ".lib",
else => switch (tag) {
.windows, .uefi => ".lib",
else => ".a",
},
};
}
 
pub fn dynamicLibSuffix(tag: Tag) [:0]const u8 {
if (tag.isDarwin()) {
return ".dylib";
}
switch (tag) {
.windows => return ".dll",
else => return ".so",
}
return switch (tag) {
.windows, .uefi => ".dll",
.ios, .macos, .watchos, .tvos => ".dylib",
else => ".so",
};
}
 
pub fn libPrefix(tag: Os.Tag, abi: Abi) [:0]const u8 {
return switch (abi) {
.msvc => "",
else => switch (tag) {
.windows, .uefi => "",
else => "lib",
},
};
}
 
pub inline fn isGnuLibC(tag: Os.Tag, abi: Abi) bool {
return tag == .linux and abi.isGnu();
}
 
pub fn defaultVersionRange(tag: Tag, arch: Cpu.Arch) Os {
@@ -97,6 +131,78 @@ pub const Os = struct {
.version_range = VersionRange.default(tag, arch),
};
}
 
pub inline fn getVersionRangeTag(tag: Tag) @typeInfo(TaggedVersionRange).Union.tag_type.? {
return switch (tag) {
.freestanding,
.ananas,
.cloudabi,
.fuchsia,
.kfreebsd,
.lv2,
.zos,
.haiku,
.minix,
.rtems,
.nacl,
.aix,
.cuda,
.nvcl,
.amdhsa,
.ps4,
.ps5,
.elfiamcu,
.mesa3d,
.contiki,
.amdpal,
.hermit,
.hurd,
.emscripten,
.driverkit,
.shadermodel,
.liteos,
.uefi,
.opencl, // TODO: OpenCL versions
.glsl450, // TODO: GLSL versions
.vulkan,
.plan9,
.illumos,
.other,
=> .none,
 
.freebsd,
.macos,
.ios,
.tvos,
.watchos,
.netbsd,
.openbsd,
.dragonfly,
.solaris,
.wasi,
=> .semver,
 
.linux => .linux,
 
.windows => .windows,
};
}
 
pub fn archName(tag: Tag, arch: Cpu.Arch) [:0]const u8 {
return switch (tag) {
.linux => switch (arch) {
.arm, .armeb, .thumb, .thumbeb => "arm",
.aarch64, .aarch64_be, .aarch64_32 => "aarch64",
.mips, .mipsel, .mips64, .mips64el => "mips",
.powerpc, .powerpcle, .powerpc64, .powerpc64le => "powerpc",
.riscv32, .riscv64 => "riscv",
.sparc, .sparcel, .sparc64 => "sparc",
.x86, .x86_64 => "x86",
else => @tagName(arch),
},
else => @tagName(arch),
};
}
};
 
/// Based on NTDDI version constants from
@@ -142,52 +248,60 @@ pub const Os = struct {
19042, //win10_fe aka win10_20h2
};
 
/// Returns whether the first version `self` is newer (greater) than or equal to the second version `ver`.
pub inline fn isAtLeast(self: WindowsVersion, ver: WindowsVersion) bool {
return @intFromEnum(self) >= @intFromEnum(ver);
/// Returns whether the first version `ver` is newer (greater) than or equal to the second version `ver`.
pub inline fn isAtLeast(ver: WindowsVersion, min_ver: WindowsVersion) bool {
return @intFromEnum(ver) >= @intFromEnum(min_ver);
}
 
pub const Range = struct {
min: WindowsVersion,
max: WindowsVersion,
 
pub inline fn includesVersion(self: Range, ver: WindowsVersion) bool {
return @intFromEnum(ver) >= @intFromEnum(self.min) and @intFromEnum(ver) <= @intFromEnum(self.max);
pub inline fn includesVersion(range: Range, ver: WindowsVersion) bool {
return @intFromEnum(ver) >= @intFromEnum(range.min) and
@intFromEnum(ver) <= @intFromEnum(range.max);
}
 
/// Checks if system is guaranteed to be at least `version` or older than `version`.
/// Returns `null` if a runtime check is required.
pub inline fn isAtLeast(self: Range, ver: WindowsVersion) ?bool {
if (@intFromEnum(self.min) >= @intFromEnum(ver)) return true;
if (@intFromEnum(self.max) < @intFromEnum(ver)) return false;
pub inline fn isAtLeast(range: Range, min_ver: WindowsVersion) ?bool {
if (@intFromEnum(range.min) >= @intFromEnum(min_ver)) return true;
if (@intFromEnum(range.max) < @intFromEnum(min_ver)) return false;
return null;
}
};
 
pub fn parse(str: []const u8) !WindowsVersion {
return std.meta.stringToEnum(WindowsVersion, str) orelse
@enumFromInt(std.fmt.parseInt(u32, str, 0) catch
return error.InvalidOperatingSystemVersion);
}
 
/// This function is defined to serialize a Zig source code representation of this
/// type, that, when parsed, will deserialize into the same data.
pub fn format(
self: WindowsVersion,
comptime fmt: []const u8,
ver: WindowsVersion,
comptime fmt_str: []const u8,
_: std.fmt.FormatOptions,
out_stream: anytype,
) !void {
if (comptime std.mem.eql(u8, fmt, "s")) {
if (@intFromEnum(self) >= @intFromEnum(WindowsVersion.nt4) and @intFromEnum(self) <= @intFromEnum(WindowsVersion.latest)) {
try std.fmt.format(out_stream, ".{s}", .{@tagName(self)});
} else {
// TODO this code path breaks zig triples, but it is used in `builtin`
try std.fmt.format(out_stream, "@enumFromInt(Target.Os.WindowsVersion, 0x{X:0>8})", .{@intFromEnum(self)});
}
} else if (fmt.len == 0) {
if (@intFromEnum(self) >= @intFromEnum(WindowsVersion.nt4) and @intFromEnum(self) <= @intFromEnum(WindowsVersion.latest)) {
try std.fmt.format(out_stream, "WindowsVersion.{s}", .{@tagName(self)});
} else {
try std.fmt.format(out_stream, "WindowsVersion(0x{X:0>8})", .{@intFromEnum(self)});
}
} else {
std.fmt.invalidFmtError(fmt, self);
}
writer: anytype,
) @TypeOf(writer).Error!void {
const maybe_name = std.enums.tagName(WindowsVersion, ver);
if (comptime std.mem.eql(u8, fmt_str, "s")) {
if (maybe_name) |name|
try writer.print(".{s}", .{name})
else
try writer.print(".{d}", .{@intFromEnum(ver)});
} else if (comptime std.mem.eql(u8, fmt_str, "c")) {
if (maybe_name) |name|
try writer.print(".{s}", .{name})
else
try writer.print("@enumFromInt(0x{X:0>8})", .{@intFromEnum(ver)});
} else if (fmt_str.len == 0) {
if (maybe_name) |name|
try writer.print("WindowsVersion.{s}", .{name})
else
try writer.print("WindowsVersion(0x{X:0>8})", .{@intFromEnum(ver)});
} else std.fmt.invalidFmtError(fmt_str, ver);
}
};
 
@@ -195,14 +309,14 @@ pub const Os = struct {
range: std.SemanticVersion.Range,
glibc: std.SemanticVersion,
 
pub inline fn includesVersion(self: LinuxVersionRange, ver: std.SemanticVersion) bool {
return self.range.includesVersion(ver);
pub inline fn includesVersion(range: LinuxVersionRange, ver: std.SemanticVersion) bool {
return range.range.includesVersion(ver);
}
 
/// Checks if system is guaranteed to be at least `version` or older than `version`.
/// Returns `null` if a runtime check is required.
pub inline fn isAtLeast(self: LinuxVersionRange, ver: std.SemanticVersion) ?bool {
return self.range.isAtLeast(ver);
pub inline fn isAtLeast(range: LinuxVersionRange, ver: std.SemanticVersion) ?bool {
return range.range.isAtLeast(ver);
}
};
 
@@ -239,7 +353,7 @@ pub const Os = struct {
/// The default `VersionRange` represents the range that the Zig Standard Library
/// bases its abstractions on.
pub fn default(tag: Tag, arch: Cpu.Arch) VersionRange {
switch (tag) {
return switch (tag) {
.freestanding,
.ananas,
.cloudabi,
@@ -263,7 +377,6 @@ pub const Os = struct {
.amdpal,
.hermit,
.hurd,
.wasi,
.emscripten,
.driverkit,
.shadermodel,
@@ -275,15 +388,15 @@ pub const Os = struct {
.plan9,
.illumos,
.other,
=> return .{ .none = {} },
=> .{ .none = {} },
 
.freebsd => return .{
.freebsd => .{
.semver = std.SemanticVersion.Range{
.min = .{ .major = 12, .minor = 0, .patch = 0 },
.max = .{ .major = 14, .minor = 0, .patch = 0 },
},
},
.macos => return switch (arch) {
.macos => switch (arch) {
.aarch64 => VersionRange{
.semver = .{
.min = .{ .major = 11, .minor = 7, .patch = 1 },
@@ -298,50 +411,56 @@ pub const Os = struct {
},
else => unreachable,
},
.ios => return .{
.ios => .{
.semver = .{
.min = .{ .major = 12, .minor = 0, .patch = 0 },
.max = .{ .major = 17, .minor = 1, .patch = 0 },
},
},
.watchos => return .{
.watchos => .{
.semver = .{
.min = .{ .major = 6, .minor = 0, .patch = 0 },
.max = .{ .major = 10, .minor = 1, .patch = 0 },
},
},
.tvos => return .{
.tvos => .{
.semver = .{
.min = .{ .major = 13, .minor = 0, .patch = 0 },
.max = .{ .major = 17, .minor = 1, .patch = 0 },
},
},
.netbsd => return .{
.netbsd => .{
.semver = .{
.min = .{ .major = 8, .minor = 0, .patch = 0 },
.max = .{ .major = 10, .minor = 0, .patch = 0 },
},
},
.openbsd => return .{
.openbsd => .{
.semver = .{
.min = .{ .major = 6, .minor = 8, .patch = 0 },
.max = .{ .major = 7, .minor = 4, .patch = 0 },
},
},
.dragonfly => return .{
.dragonfly => .{
.semver = .{
.min = .{ .major = 5, .minor = 8, .patch = 0 },
.max = .{ .major = 6, .minor = 4, .patch = 0 },
},
},
.solaris => return .{
.solaris => .{
.semver = .{
.min = .{ .major = 5, .minor = 11, .patch = 0 },
.max = .{ .major = 5, .minor = 11, .patch = 0 },
},
},
.wasi => .{
.semver = .{
.min = .{ .major = 0, .minor = 1, .patch = 0 },
.max = .{ .major = 0, .minor = 1, .patch = 0 },
},
},
 
.linux => return .{
.linux => .{
.linux = .{
.range = .{
.min = .{ .major = 4, .minor = 19, .patch = 0 },
@@ -351,13 +470,13 @@ pub const Os = struct {
},
},
 
.windows => return .{
.windows => .{
.windows = .{
.min = .win8_1,
.max = WindowsVersion.latest,
},
},
}
};
}
};
 
@@ -370,38 +489,28 @@ pub const Os = struct {
 
/// Provides a tagged union. `Target` does not store the tag because it is
/// redundant with the OS tag; this function abstracts that part away.
pub inline fn getVersionRange(self: Os) TaggedVersionRange {
switch (self.tag) {
.linux => return TaggedVersionRange{ .linux = self.version_range.linux },
.windows => return TaggedVersionRange{ .windows = self.version_range.windows },
 
.freebsd,
.macos,
.ios,
.tvos,
.watchos,
.netbsd,
.openbsd,
.dragonfly,
.solaris,
=> return TaggedVersionRange{ .semver = self.version_range.semver },
 
else => return .none,
}
pub inline fn getVersionRange(os: Os) TaggedVersionRange {
return switch (os.tag.getVersionRangeTag()) {
.none => .{ .none = {} },
.semver => .{ .semver = os.version_range.semver },
.linux => .{ .linux = os.version_range.linux },
.windows => .{ .windows = os.version_range.windows },
};
}
 
/// Checks if system is guaranteed to be at least `version` or older than `version`.
/// Returns `null` if a runtime check is required.
pub inline fn isAtLeast(self: Os, comptime tag: Tag, version: switch (tag) {
else => std.SemanticVersion,
pub inline fn isAtLeast(os: Os, comptime tag: Tag, ver: switch (tag.getVersionRangeTag()) {
.none => void,
.semver, .linux => std.SemanticVersion,
.windows => WindowsVersion,
}) ?bool {
if (self.tag != tag) return false;
 
return switch (tag) {
.linux => self.version_range.linux.isAtLeast(version),
.windows => self.version_range.windows.isAtLeast(version),
else => self.version_range.semver.isAtLeast(version),
return if (os.tag != tag) false else switch (tag.getVersionRangeTag()) {
.none => true,
inline .semver,
.linux,
.windows,
=> |field| @field(os.version_range, @tagName(field)).isAtLeast(ver),
};
}
 
@@ -528,11 +637,8 @@ pub const Abi = enum {
mesh,
amplification,
 
pub fn default(arch: Cpu.Arch, target_os: Os) Abi {
if (arch.isWasm()) {
return .musl;
}
switch (target_os.tag) {
pub fn default(arch: Cpu.Arch, os: Os) Abi {
return if (arch.isWasm()) .musl else switch (os.tag) {
.freestanding,
.ananas,
.cloudabi,
@@ -554,7 +660,7 @@ pub const Abi = enum {
.amdpal,
.hermit,
.other,
=> return .eabi,
=> .eabi,
.openbsd,
.freebsd,
.fuchsia,
@@ -563,12 +669,12 @@ pub const Abi = enum {
.hurd,
.haiku,
.windows,
=> return .gnu,
.uefi => return .msvc,
=> .gnu,
.uefi => .msvc,
.linux,
.wasi,
.emscripten,
=> return .musl,
=> .musl,
.opencl, // TODO: SPIR-V ABIs with Linkage capability
.glsl450,
.vulkan,
@@ -582,8 +688,8 @@ pub const Abi = enum {
.liteos, // TODO: audit this
.solaris,
.illumos,
=> return .none,
}
=> .none,
};
}
 
pub inline fn isGnu(abi: Abi) bool {
@@ -635,7 +741,7 @@ pub const ObjectFormat = enum {
/// Nvidia PTX format
nvptx,
 
pub fn fileExt(of: ObjectFormat, cpu_arch: Cpu.Arch) [:0]const u8 {
pub fn fileExt(of: ObjectFormat, arch: Cpu.Arch) [:0]const u8 {
return switch (of) {
.coff => ".obj",
.elf, .macho, .wasm => ".o",
@@ -643,18 +749,18 @@ pub const ObjectFormat = enum {
.spirv => ".spv",
.hex => ".ihex",
.raw => ".bin",
.plan9 => plan9Ext(cpu_arch),
.plan9 => arch.plan9Ext(),
.nvptx => ".ptx",
.dxcontainer => ".dxil",
};
}
 
pub fn default(os_tag: Os.Tag, cpu_arch: Cpu.Arch) ObjectFormat {
pub fn default(os_tag: Os.Tag, arch: Cpu.Arch) ObjectFormat {
return switch (os_tag) {
.windows, .uefi => .coff,
.ios, .macos, .watchos, .tvos => .macho,
.plan9 => .plan9,
else => return switch (cpu_arch) {
else => switch (arch) {
.wasm32, .wasm64 => .wasm,
.spirv32, .spirv64 => .spirv,
.nvptx, .nvptx64 => .nvptx,
@@ -725,14 +831,14 @@ pub const Cpu = struct {
 
pub fn isEnabled(set: Set, arch_feature_index: Index) bool {
const usize_index = arch_feature_index / @bitSizeOf(usize);
const bit_index = @as(ShiftInt, @intCast(arch_feature_index % @bitSizeOf(usize)));
const bit_index: ShiftInt = @intCast(arch_feature_index % @bitSizeOf(usize));
return (set.ints[usize_index] & (@as(usize, 1) << bit_index)) != 0;
}
 
/// Adds the specified feature but not its dependencies.
pub fn addFeature(set: *Set, arch_feature_index: Index) void {
const usize_index = arch_feature_index / @bitSizeOf(usize);
const bit_index = @as(ShiftInt, @intCast(arch_feature_index % @bitSizeOf(usize)));
const bit_index: ShiftInt = @intCast(arch_feature_index % @bitSizeOf(usize));
set.ints[usize_index] |= @as(usize, 1) << bit_index;
}
 
@@ -751,7 +857,7 @@ pub const Cpu = struct {
/// Removes the specified feature but not its dependents.
pub fn removeFeature(set: *Set, arch_feature_index: Index) void {
const usize_index = arch_feature_index / @bitSizeOf(usize);
const bit_index = @as(ShiftInt, @intCast(arch_feature_index % @bitSizeOf(usize)));
const bit_index: ShiftInt = @intCast(arch_feature_index % @bitSizeOf(usize));
set.ints[usize_index] &= ~(@as(usize, 1) << bit_index);
}
 
@@ -773,7 +879,7 @@ pub const Cpu = struct {
var old = set.ints;
while (true) {
for (all_features_list, 0..) |feature, index_usize| {
const index = @as(Index, @intCast(index_usize));
const index: Index = @intCast(index_usize);
if (set.isEnabled(index)) {
set.addFeatureSet(feature.dependencies);
}
@@ -785,7 +891,7 @@ pub const Cpu = struct {
}
 
pub fn asBytes(set: *const Set) *const [byte_count]u8 {
return @as(*const [byte_count]u8, @ptrCast(&set.ints));
return std.mem.sliceAsBytes(&set.ints)[0..byte_count];
}
 
pub fn eql(set: Set, other_set: Set) bool {
@@ -1231,7 +1337,7 @@ pub const Cpu = struct {
}
 
/// Returns a name that matches the lib/std/target/* source file name.
pub fn genericName(arch: Arch) []const u8 {
pub fn genericName(arch: Arch) [:0]const u8 {
return switch (arch) {
.arm, .armeb, .thumb, .thumbeb => "arm",
.aarch64, .aarch64_be, .aarch64_32 => "aarch64",
@@ -1320,6 +1426,30 @@ pub const Cpu = struct {
const finalized = array;
return &finalized;
}
 
/// 0c spim little-endian MIPS 3000 family
/// 1c 68000 Motorola MC68000
/// 2c 68020 Motorola MC68020
/// 5c arm little-endian ARM
/// 6c amd64 AMD64 and compatibles (e.g., Intel EM64T)
/// 7c arm64 ARM64 (ARMv8)
/// 8c 386 Intel x86, i486, Pentium, etc.
/// kc sparc Sun SPARC
/// qc power Power PC
/// vc mips big-endian MIPS 3000 family
pub fn plan9Ext(arch: Cpu.Arch) [:0]const u8 {
return switch (arch) {
.arm => ".5",
.x86_64 => ".6",
.aarch64 => ".7",
.x86 => ".8",
.sparc => ".k",
.powerpc, .powerpcle => ".q",
.mips, .mipsel => ".v",
// ISAs without designated characters get 'X' for lack of a better option.
else => ".X",
};
}
};
 
pub const Model = struct {
@@ -1399,112 +1529,76 @@ pub const Cpu = struct {
}
};
 
pub fn zigTriple(self: Target, allocator: Allocator) Allocator.Error![]u8 {
return Query.fromTarget(self).zigTriple(allocator);
pub fn zigTriple(target: Target, allocator: Allocator) Allocator.Error![]u8 {
return Query.fromTarget(target).zigTriple(allocator);
}
 
pub fn linuxTripleSimple(allocator: Allocator, cpu_arch: Cpu.Arch, os_tag: Os.Tag, abi: Abi) ![]u8 {
return std.fmt.allocPrint(allocator, "{s}-{s}-{s}", .{ @tagName(cpu_arch), @tagName(os_tag), @tagName(abi) });
pub fn linuxTripleSimple(allocator: Allocator, arch: Cpu.Arch, os_tag: Os.Tag, abi: Abi) ![]u8 {
return std.fmt.allocPrint(allocator, "{s}-{s}-{s}", .{ @tagName(arch), @tagName(os_tag), @tagName(abi) });
}
 
pub fn linuxTriple(self: Target, allocator: Allocator) ![]u8 {
return linuxTripleSimple(allocator, self.cpu.arch, self.os.tag, self.abi);
pub fn linuxTriple(target: Target, allocator: Allocator) ![]u8 {
return linuxTripleSimple(allocator, target.cpu.arch, target.os.tag, target.abi);
}
 
pub fn exeFileExtSimple(cpu_arch: Cpu.Arch, os_tag: Os.Tag) [:0]const u8 {
return switch (os_tag) {
.windows => ".exe",
.uefi => ".efi",
.plan9 => plan9Ext(cpu_arch),
else => switch (cpu_arch) {
.wasm32, .wasm64 => ".wasm",
else => "",
},
};
pub fn exeFileExt(target: Target) [:0]const u8 {
return target.os.tag.exeFileExt(target.cpu.arch);
}
 
pub fn exeFileExt(self: Target) [:0]const u8 {
return exeFileExtSimple(self.cpu.arch, self.os.tag);
pub fn staticLibSuffix(target: Target) [:0]const u8 {
return target.os.tag.staticLibSuffix(target.abi);
}
 
pub fn staticLibSuffix_os_abi(os_tag: Os.Tag, abi: Abi) [:0]const u8 {
if (abi == .msvc) {
return ".lib";
}
switch (os_tag) {
.windows, .uefi => return ".lib",
else => return ".a",
}
pub fn dynamicLibSuffix(target: Target) [:0]const u8 {
return target.os.tag.dynamicLibSuffix();
}
 
pub fn staticLibSuffix(self: Target) [:0]const u8 {
return staticLibSuffix_os_abi(self.os.tag, self.abi);
pub fn libPrefix(target: Target) [:0]const u8 {
return target.os.tag.libPrefix(target.abi);
}
 
pub fn dynamicLibSuffix(self: Target) [:0]const u8 {
return self.os.tag.dynamicLibSuffix();
pub inline fn isMinGW(target: Target) bool {
return target.os.tag == .windows and target.isGnu();
}
 
pub fn libPrefix_os_abi(os_tag: Os.Tag, abi: Abi) [:0]const u8 {
if (abi == .msvc) {
return "";
}
switch (os_tag) {
.windows, .uefi => return "",
else => return "lib",
}
pub inline fn isGnu(target: Target) bool {
return target.abi.isGnu();
}
 
pub fn libPrefix(self: Target) [:0]const u8 {
return libPrefix_os_abi(self.os.tag, self.abi);
pub inline fn isMusl(target: Target) bool {
return target.abi.isMusl();
}
 
pub inline fn isMinGW(self: Target) bool {
return self.os.tag == .windows and self.isGnu();
pub inline fn isAndroid(target: Target) bool {
return target.abi == .android;
}
 
pub inline fn isGnu(self: Target) bool {
return self.abi.isGnu();
pub inline fn isWasm(target: Target) bool {
return target.cpu.arch.isWasm();
}
 
pub inline fn isMusl(self: Target) bool {
return self.abi.isMusl();
pub inline fn isDarwin(target: Target) bool {
return target.os.tag.isDarwin();
}
 
pub inline fn isAndroid(self: Target) bool {
return self.abi == .android;
pub inline fn isBSD(target: Target) bool {
return target.os.tag.isBSD();
}
 
pub inline fn isWasm(self: Target) bool {
return self.cpu.arch.isWasm();
pub inline fn isBpfFreestanding(target: Target) bool {
return target.cpu.arch.isBpf() and target.os.tag == .freestanding;
}
 
pub inline fn isDarwin(self: Target) bool {
return self.os.tag.isDarwin();
pub inline fn isGnuLibC(target: Target) bool {
return target.os.tag.isGnuLibC(target.abi);
}
 
pub inline fn isBSD(self: Target) bool {
return self.os.tag.isBSD();
pub inline fn supportsNewStackCall(target: Target) bool {
return !target.cpu.arch.isWasm();
}
 
pub inline fn isBpfFreestanding(self: Target) bool {
return self.cpu.arch.isBpf() and self.os.tag == .freestanding;
}
 
pub inline fn isGnuLibC_os_tag_abi(os_tag: Os.Tag, abi: Abi) bool {
return os_tag == .linux and abi.isGnu();
}
 
pub inline fn isGnuLibC(self: Target) bool {
return isGnuLibC_os_tag_abi(self.os.tag, self.abi);
}
 
pub inline fn supportsNewStackCall(self: Target) bool {
return !self.cpu.arch.isWasm();
}
 
pub inline fn isSpirV(self: Target) bool {
return self.cpu.arch.isSpirV();
pub inline fn isSpirV(target: Target) bool {
return target.cpu.arch.isSpirV();
}
 
pub const FloatAbi = enum {
@@ -1512,15 +1606,15 @@ pub const FloatAbi = enum {
soft,
};
 
pub inline fn getFloatAbi(self: Target) FloatAbi {
return self.abi.floatAbi();
pub inline fn getFloatAbi(target: Target) FloatAbi {
return target.abi.floatAbi();
}
 
pub inline fn hasDynamicLinker(self: Target) bool {
if (self.cpu.arch.isWasm()) {
pub inline fn hasDynamicLinker(target: Target) bool {
if (target.cpu.arch.isWasm()) {
return false;
}
switch (self.os.tag) {
switch (target.os.tag) {
.freestanding,
.ios,
.tvos,
@@ -1547,259 +1641,210 @@ pub const DynamicLinker = struct {
 
/// Used to construct the dynamic linker path. This field should not be used
/// directly. See `get` and `set`.
max_byte: ?u8,
len: u8,
 
pub const none: DynamicLinker = .{
.buffer = undefined,
.max_byte = null,
};
pub const none: DynamicLinker = .{ .buffer = undefined, .len = 0 };
 
/// Asserts that the length is less than or equal to 255 bytes.
pub fn init(dl_or_null: ?[]const u8) DynamicLinker {
var result: DynamicLinker = undefined;
result.set(dl_or_null);
return result;
pub fn init(maybe_path: ?[]const u8) DynamicLinker {
var dl: DynamicLinker = undefined;
dl.set(maybe_path);
return dl;
}
 
pub fn initFmt(comptime fmt_str: []const u8, args: anytype) !DynamicLinker {
var dl: DynamicLinker = undefined;
try dl.setFmt(fmt_str, args);
return dl;
}
 
/// The returned memory has the same lifetime as the `DynamicLinker`.
pub fn get(self: *const DynamicLinker) ?[]const u8 {
const m: usize = self.max_byte orelse return null;
return self.buffer[0 .. m + 1];
pub fn get(dl: *const DynamicLinker) ?[]const u8 {
return if (dl.len > 0) dl.buffer[0..dl.len] else null;
}
 
/// Asserts that the length is less than or equal to 255 bytes.
pub fn set(self: *DynamicLinker, dl_or_null: ?[]const u8) void {
if (dl_or_null) |dl| {
@memcpy(self.buffer[0..dl.len], dl);
self.max_byte = @intCast(dl.len - 1);
} else {
self.max_byte = null;
}
pub fn set(dl: *DynamicLinker, maybe_path: ?[]const u8) void {
const path = maybe_path orelse "";
@memcpy(dl.buffer[0..path.len], path);
dl.len = @intCast(path.len);
}
 
pub fn eql(a: DynamicLinker, b: DynamicLinker) bool {
const a_m = a.max_byte orelse return b.max_byte == null;
const b_m = b.max_byte orelse return false;
if (a_m != b_m) return false;
const a_s = a.buffer[0 .. a_m + 1];
const b_s = b.buffer[0 .. a_m + 1];
return std.mem.eql(u8, a_s, b_s);
/// Asserts that the length is less than or equal to 255 bytes.
pub fn setFmt(dl: *DynamicLinker, comptime fmt_str: []const u8, args: anytype) !void {
dl.len = @intCast((try std.fmt.bufPrint(&dl.buffer, fmt_str, args)).len);
}
 
pub fn eql(lhs: DynamicLinker, rhs: DynamicLinker) bool {
return std.mem.eql(u8, lhs.buffer[0..lhs.len], rhs.buffer[0..rhs.len]);
}
 
pub fn standard(cpu: Cpu, os_tag: Os.Tag, abi: Abi) DynamicLinker {
return if (abi == .android) initFmt("/system/bin/linker{s}", .{
if (ptrBitWidth_cpu_abi(cpu, abi) == 64) "64" else "",
}) catch unreachable else if (abi.isMusl()) return initFmt("/lib/ld-musl-{s}{s}.so.1", .{
@tagName(switch (cpu.arch) {
.thumb => .arm,
.thumbeb => .armeb,
else => cpu.arch,
}),
if (cpu.arch.isArmOrThumb() and abi.floatAbi() == .hard) "hf" else "",
}) catch unreachable else switch (os_tag) {
.freebsd => init("/libexec/ld-elf.so.1"),
.netbsd => init("/libexec/ld.elf_so"),
.openbsd => init("/usr/libexec/ld.so"),
.dragonfly => init("/libexec/ld-elf.so.2"),
.solaris, .illumos => init("/lib/64/ld.so.1"),
.linux => switch (cpu.arch) {
.x86,
.sparc,
.sparcel,
=> init("/lib/ld-linux.so.2"),
 
.aarch64 => init("/lib/ld-linux-aarch64.so.1"),
.aarch64_be => init("/lib/ld-linux-aarch64_be.so.1"),
.aarch64_32 => init("/lib/ld-linux-aarch64_32.so.1"),
 
.arm,
.armeb,
.thumb,
.thumbeb,
=> initFmt("/lib/ld-linux{s}.so.3", .{switch (abi.floatAbi()) {
.hard => "-armhf",
else => "",
}}) catch unreachable,
 
.mips,
.mipsel,
.mips64,
.mips64el,
=> initFmt("/lib{s}/{s}", .{
switch (abi) {
.gnuabin32, .gnux32 => "32",
.gnuabi64 => "64",
else => "",
},
if (mips.featureSetHas(cpu.features, .nan2008))
"ld-linux-mipsn8.so.1"
else
"ld.so.1",
}) catch unreachable,
 
.powerpc, .powerpcle => init("/lib/ld.so.1"),
.powerpc64, .powerpc64le => init("/lib64/ld64.so.2"),
.s390x => init("/lib64/ld64.so.1"),
.sparc64 => init("/lib64/ld-linux.so.2"),
.x86_64 => init(switch (abi) {
.gnux32 => "/libx32/ld-linux-x32.so.2",
else => "/lib64/ld-linux-x86-64.so.2",
}),
 
.riscv32 => init("/lib/ld-linux-riscv32-ilp32.so.1"),
.riscv64 => init("/lib/ld-linux-riscv64-lp64.so.1"),
 
// Architectures in this list have been verified as not having a standard
// dynamic linker path.
.wasm32,
.wasm64,
.bpfel,
.bpfeb,
.nvptx,
.nvptx64,
.spu_2,
.avr,
.spirv32,
.spirv64,
=> none,
 
// TODO go over each item in this list and either move it to the above list, or
// implement the standard dynamic linker path code for it.
.arc,
.csky,
.hexagon,
.m68k,
.msp430,
.r600,
.amdgcn,
.tce,
.tcele,
.xcore,
.le32,
.le64,
.amdil,
.amdil64,
.hsail,
.hsail64,
.spir,
.spir64,
.kalimba,
.shave,
.lanai,
.renderscript32,
.renderscript64,
.ve,
.dxil,
.loongarch32,
.loongarch64,
.xtensa,
=> none,
},
 
.ios,
.tvos,
.watchos,
.macos,
=> init("/usr/lib/dyld"),
 
// Operating systems in this list have been verified as not having a standard
// dynamic linker path.
.freestanding,
.uefi,
.windows,
.emscripten,
.wasi,
.opencl,
.glsl450,
.vulkan,
.other,
.plan9,
=> none,
 
// TODO revisit when multi-arch for Haiku is available
.haiku => init("/system/runtime_loader"),
 
// TODO go over each item in this list and either move it to the above list, or
// implement the standard dynamic linker path code for it.
.ananas,
.cloudabi,
.fuchsia,
.kfreebsd,
.lv2,
.zos,
.minix,
.rtems,
.nacl,
.aix,
.cuda,
.nvcl,
.amdhsa,
.ps4,
.ps5,
.elfiamcu,
.mesa3d,
.contiki,
.amdpal,
.hermit,
.hurd,
.driverkit,
.shadermodel,
.liteos,
=> none,
};
}
};
 
pub fn standardDynamicLinkerPath(target: Target) DynamicLinker {
return standardDynamicLinkerPath_cpu_os_abi(target.cpu, target.os.tag, target.abi);
}
 
pub fn standardDynamicLinkerPath_cpu_os_abi(cpu: Cpu, os_tag: Os.Tag, abi: Abi) DynamicLinker {
var result = DynamicLinker.none;
const S = struct {
fn print(r: *DynamicLinker, comptime fmt: []const u8, args: anytype) DynamicLinker {
r.max_byte = @as(u8, @intCast((std.fmt.bufPrint(&r.buffer, fmt, args) catch unreachable).len - 1));
return r.*;
}
fn copy(r: *DynamicLinker, s: []const u8) DynamicLinker {
@memcpy(r.buffer[0..s.len], s);
r.max_byte = @as(u8, @intCast(s.len - 1));
return r.*;
}
};
const print = S.print;
const copy = S.copy;
 
if (abi == .android) {
const suffix = if (ptrBitWidth_cpu_abi(cpu, abi) == 64) "64" else "";
return print(&result, "/system/bin/linker{s}", .{suffix});
}
 
if (abi.isMusl()) {
const is_arm = switch (cpu.arch) {
.arm, .armeb, .thumb, .thumbeb => true,
else => false,
};
const arch_part = switch (cpu.arch) {
.arm, .thumb => "arm",
.armeb, .thumbeb => "armeb",
else => |arch| @tagName(arch),
};
const arch_suffix = if (is_arm and abi.floatAbi() == .hard) "hf" else "";
return print(&result, "/lib/ld-musl-{s}{s}.so.1", .{ arch_part, arch_suffix });
}
 
switch (os_tag) {
.freebsd => return copy(&result, "/libexec/ld-elf.so.1"),
.netbsd => return copy(&result, "/libexec/ld.elf_so"),
.openbsd => return copy(&result, "/usr/libexec/ld.so"),
.dragonfly => return copy(&result, "/libexec/ld-elf.so.2"),
.solaris, .illumos => return copy(&result, "/lib/64/ld.so.1"),
.linux => switch (cpu.arch) {
.x86,
.sparc,
.sparcel,
=> return copy(&result, "/lib/ld-linux.so.2"),
 
.aarch64 => return copy(&result, "/lib/ld-linux-aarch64.so.1"),
.aarch64_be => return copy(&result, "/lib/ld-linux-aarch64_be.so.1"),
.aarch64_32 => return copy(&result, "/lib/ld-linux-aarch64_32.so.1"),
 
.arm,
.armeb,
.thumb,
.thumbeb,
=> return copy(&result, switch (abi.floatAbi()) {
.hard => "/lib/ld-linux-armhf.so.3",
else => "/lib/ld-linux.so.3",
}),
 
.mips,
.mipsel,
.mips64,
.mips64el,
=> {
const lib_suffix = switch (abi) {
.gnuabin32, .gnux32 => "32",
.gnuabi64 => "64",
else => "",
};
const is_nan_2008 = mips.featureSetHas(cpu.features, .nan2008);
const loader = if (is_nan_2008) "ld-linux-mipsn8.so.1" else "ld.so.1";
return print(&result, "/lib{s}/{s}", .{ lib_suffix, loader });
},
 
.powerpc, .powerpcle => return copy(&result, "/lib/ld.so.1"),
.powerpc64, .powerpc64le => return copy(&result, "/lib64/ld64.so.2"),
.s390x => return copy(&result, "/lib64/ld64.so.1"),
.sparc64 => return copy(&result, "/lib64/ld-linux.so.2"),
.x86_64 => return copy(&result, switch (abi) {
.gnux32 => "/libx32/ld-linux-x32.so.2",
else => "/lib64/ld-linux-x86-64.so.2",
}),
 
.riscv32 => return copy(&result, "/lib/ld-linux-riscv32-ilp32.so.1"),
.riscv64 => return copy(&result, "/lib/ld-linux-riscv64-lp64.so.1"),
 
// Architectures in this list have been verified as not having a standard
// dynamic linker path.
.wasm32,
.wasm64,
.bpfel,
.bpfeb,
.nvptx,
.nvptx64,
.spu_2,
.avr,
.spirv32,
.spirv64,
=> return result,
 
// TODO go over each item in this list and either move it to the above list, or
// implement the standard dynamic linker path code for it.
.arc,
.csky,
.hexagon,
.m68k,
.msp430,
.r600,
.amdgcn,
.tce,
.tcele,
.xcore,
.le32,
.le64,
.amdil,
.amdil64,
.hsail,
.hsail64,
.spir,
.spir64,
.kalimba,
.shave,
.lanai,
.renderscript32,
.renderscript64,
.ve,
.dxil,
.loongarch32,
.loongarch64,
.xtensa,
=> return result,
},
 
.ios,
.tvos,
.watchos,
.macos,
=> return copy(&result, "/usr/lib/dyld"),
 
// Operating systems in this list have been verified as not having a standard
// dynamic linker path.
.freestanding,
.uefi,
.windows,
.emscripten,
.wasi,
.opencl,
.glsl450,
.vulkan,
.other,
.plan9,
=> return result,
 
// TODO revisit when multi-arch for Haiku is available
.haiku => return copy(&result, "/system/runtime_loader"),
 
// TODO go over each item in this list and either move it to the above list, or
// implement the standard dynamic linker path code for it.
.ananas,
.cloudabi,
.fuchsia,
.kfreebsd,
.lv2,
.zos,
.minix,
.rtems,
.nacl,
.aix,
.cuda,
.nvcl,
.amdhsa,
.ps4,
.ps5,
.elfiamcu,
.mesa3d,
.contiki,
.amdpal,
.hermit,
.hurd,
.driverkit,
.shadermodel,
.liteos,
=> return result,
}
}
 
/// 0c spim little-endian MIPS 3000 family
/// 1c 68000 Motorola MC68000
/// 2c 68020 Motorola MC68020
/// 5c arm little-endian ARM
/// 6c amd64 AMD64 and compatibles (e.g., Intel EM64T)
/// 7c arm64 ARM64 (ARMv8)
/// 8c 386 Intel x86, i486, Pentium, etc.
/// kc sparc Sun SPARC
/// qc power Power PC
/// vc mips big-endian MIPS 3000 family
pub fn plan9Ext(cpu_arch: Cpu.Arch) [:0]const u8 {
return switch (cpu_arch) {
.arm => ".5",
.x86_64 => ".6",
.aarch64 => ".7",
.x86 => ".8",
.sparc => ".k",
.powerpc, .powerpcle => ".q",
.mips, .mipsel => ".v",
// ISAs without designated characters get 'X' for lack of a better option.
else => ".X",
};
return DynamicLinker.standard(target.cpu, target.os.tag, target.abi);
}
 
pub fn maxIntAlignment(target: Target) u16 {
@@ -2076,7 +2121,7 @@ pub fn c_type_byte_size(t: Target, c_type: CType) u16 {
16 => 2,
32 => 4,
64 => 8,
80 => @as(u16, @intCast(std.mem.alignForward(usize, 10, c_type_alignment(t, .longdouble)))),
80 => @intCast(std.mem.alignForward(usize, 10, c_type_alignment(t, .longdouble))),
128 => 16,
else => unreachable,
},
@@ -2419,7 +2464,7 @@ pub fn c_type_alignment(target: Target, c_type: CType) u16 {
// Next-power-of-two-aligned, up to a maximum.
return @min(
std.math.ceilPowerOfTwoAssert(u16, (c_type_bit_size(target, c_type) + 7) / 8),
switch (target.cpu.arch) {
@as(u16, switch (target.cpu.arch) {
.arm, .armeb, .thumb, .thumbeb => switch (target.os.tag) {
.netbsd => switch (target.abi) {
.gnueabi,
@@ -2431,7 +2476,7 @@ pub fn c_type_alignment(target: Target, c_type: CType) u16 {
.musleabihf,
=> 8,
 
else => @as(u16, 4),
else => 4,
},
.ios, .tvos, .watchos => 4,
else => 8,
@@ -2501,7 +2546,7 @@ pub fn c_type_alignment(target: Target, c_type: CType) u16 {
.wasm32,
.wasm64,
=> 16,
},
}),
);
}
 
@@ -2559,8 +2604,8 @@ pub fn c_type_preferred_alignment(target: Target, c_type: CType) u16 {
// Next-power-of-two-aligned, up to a maximum.
return @min(
std.math.ceilPowerOfTwoAssert(u16, (c_type_bit_size(target, c_type) + 7) / 8),
switch (target.cpu.arch) {
.msp430 => @as(u16, 2),
@as(u16, switch (target.cpu.arch) {
.msp430 => 2,
 
.csky,
.xcore,
@@ -2627,7 +2672,7 @@ pub fn c_type_preferred_alignment(target: Target, c_type: CType) u16 {
.wasm32,
.wasm64,
=> 16,
},
}),
);
}
 
@@ -2767,19 +2812,7 @@ fn eqlIgnoreCase(ignore_case: bool, a: []const u8, b: []const u8) bool {
}
 
pub fn osArchName(target: std.Target) [:0]const u8 {
return switch (target.os.tag) {
.linux => switch (target.cpu.arch) {
.arm, .armeb, .thumb, .thumbeb => "arm",
.aarch64, .aarch64_be, .aarch64_32 => "aarch64",
.mips, .mipsel, .mips64, .mips64el => "mips",
.powerpc, .powerpcle, .powerpc64, .powerpc64le => "powerpc",
.riscv32, .riscv64 => "riscv",
.sparc, .sparcel, .sparc64 => "sparc",
.x86, .x86_64 => "x86",
else => @tagName(target.cpu.arch),
},
else => @tagName(target.cpu.arch),
};
return target.os.tag.archName(target.cpu.arch);
}
 
const Target = @This();
 
lib/std/Target/Query.zig added: 533, removed: 606, total 0
@@ -124,71 +124,21 @@ pub fn fromTarget(target: Target) Query {
}
 
fn updateOsVersionRange(self: *Query, os: Target.Os) void {
switch (os.tag) {
.freestanding,
.ananas,
.cloudabi,
.fuchsia,
.kfreebsd,
.lv2,
.solaris,
.illumos,
.zos,
.haiku,
.minix,
.rtems,
.nacl,
.aix,
.cuda,
.nvcl,
.amdhsa,
.ps4,
.ps5,
.elfiamcu,
.mesa3d,
.contiki,
.amdpal,
.hermit,
.hurd,
.wasi,
.emscripten,
.driverkit,
.shadermodel,
.liteos,
.uefi,
.opencl,
.glsl450,
.vulkan,
.plan9,
.other,
=> {
self.os_version_min = .{ .none = {} };
self.os_version_max = .{ .none = {} };
self.os_version_min, self.os_version_max = switch (os.tag.getVersionRangeTag()) {
.none => .{ .{ .none = {} }, .{ .none = {} } },
.semver => .{
.{ .semver = os.version_range.semver.min },
.{ .semver = os.version_range.semver.max },
},
 
.freebsd,
.macos,
.ios,
.tvos,
.watchos,
.netbsd,
.openbsd,
.dragonfly,
=> {
self.os_version_min = .{ .semver = os.version_range.semver.min };
self.os_version_max = .{ .semver = os.version_range.semver.max };
.linux => .{
.{ .semver = os.version_range.linux.range.min },
.{ .semver = os.version_range.linux.range.max },
},
 
.linux => {
self.os_version_min = .{ .semver = os.version_range.linux.range.min };
self.os_version_max = .{ .semver = os.version_range.linux.range.max };
.windows => .{
.{ .windows = os.version_range.windows.min },
.{ .windows = os.version_range.windows.max },
},
 
.windows => {
self.os_version_min = .{ .windows = os.version_range.windows.min };
self.os_version_max = .{ .windows = os.version_range.windows.max };
},
}
};
}
 
pub const ParseOptions = struct {
@@ -278,7 +228,8 @@ pub fn parse(args: ParseOptions) !Query {
 
const abi_ver_text = abi_it.rest();
if (abi_it.next() != null) {
if (Target.isGnuLibC_os_tag_abi(result.os_tag orelse builtin.os.tag, abi)) {
const tag = result.os_tag orelse builtin.os.tag;
if (tag.isGnuLibC(abi)) {
result.glibc_version = parseVersion(abi_ver_text) catch |err| switch (err) {
error.Overflow => return error.InvalidAbiVersion,
error.InvalidVersion => return error.InvalidAbiVersion,
@@ -567,88 +518,33 @@ fn parseOs(result: *Query, diags: *ParseOptions.Diagnostics, text: []const u8) !
diags.os_tag = tag;
 
const version_text = it.rest();
if (it.next() == null) return;
 
switch (tag) {
.freestanding,
.ananas,
.cloudabi,
.fuchsia,
.kfreebsd,
.lv2,
.solaris,
.illumos,
.zos,
.haiku,
.minix,
.rtems,
.nacl,
.aix,
.cuda,
.nvcl,
.amdhsa,
.ps4,
.ps5,
.elfiamcu,
.mesa3d,
.contiki,
.amdpal,
.hermit,
.hurd,
.wasi,
.emscripten,
.uefi,
.opencl,
.glsl450,
.vulkan,
.plan9,
.driverkit,
.shadermodel,
.liteos,
.other,
=> return error.InvalidOperatingSystemVersion,
 
.freebsd,
.macos,
.ios,
.tvos,
.watchos,
.netbsd,
.openbsd,
.linux,
.dragonfly,
=> {
if (version_text.len > 0) switch (tag.getVersionRangeTag()) {
.none => return error.InvalidOperatingSystemVersion,
.semver, .linux => range: {
var range_it = mem.splitSequence(u8, version_text, "...");
 
const min_text = range_it.next().?;
const min_ver = parseVersion(min_text) catch |err| switch (err) {
error.Overflow => return error.InvalidOperatingSystemVersion,
error.InvalidVersion => return error.InvalidOperatingSystemVersion,
result.os_version_min = .{
.semver = parseVersion(range_it.first()) catch |err| switch (err) {
error.Overflow => 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 = parseVersion(max_text) catch |err| switch (err) {
error.Overflow => return error.InvalidOperatingSystemVersion,
error.InvalidVersion => return error.InvalidOperatingSystemVersion,
result.os_version_max = .{
.semver = parseVersion(range_it.next() orelse break :range) catch |err| switch (err) {
error.Overflow => return error.InvalidOperatingSystemVersion,
error.InvalidVersion => return error.InvalidOperatingSystemVersion,
},
};
result.os_version_max = .{ .semver = max_ver };
},
 
.windows => {
.windows => range: {
var range_it = mem.splitSequence(u8, version_text, "...");
 
const min_text = range_it.first();
const min_ver = std.meta.stringToEnum(Target.Os.WindowsVersion, min_text) orelse
return error.InvalidOperatingSystemVersion;
result.os_version_min = .{ .windows = min_ver };
 
const max_text = range_it.next() orelse return;
const max_ver = std.meta.stringToEnum(Target.Os.WindowsVersion, max_text) orelse
return error.InvalidOperatingSystemVersion;
result.os_version_max = .{ .windows = max_ver };
result.os_version_min = .{
.windows = try Target.Os.WindowsVersion.parse(range_it.first()),
};
result.os_version_max = .{
.windows = try Target.Os.WindowsVersion.parse(range_it.next() orelse break :range),
};
},
}
};
}
 
pub fn eql(a: Query, b: Query) bool {
 
lib/std/zig/system.zig added: 533, removed: 606, total 0
@@ -430,9 +430,9 @@ pub fn abiAndDynamicLinkerFromFile(
query: Target.Query,
) AbiAndDynamicLinkerFromFileError!Target {
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 = @as(*elf.Elf32_Ehdr, @ptrCast(&hdr_buf));
const hdr64 = @as(*elf.Elf64_Ehdr, @ptrCast(&hdr_buf));
_ = try preadAtLeast(file, &hdr_buf, 0, hdr_buf.len);
const hdr32: *elf.Elf32_Ehdr = @ptrCast(&hdr_buf);
const hdr64: *elf.Elf64_Ehdr = @ptrCast(&hdr_buf);
if (!mem.eql(u8, hdr32.e_ident[0..4], elf.MAGIC)) return error.InvalidElfMagic;
const elf_endian: std.builtin.Endian = switch (hdr32.e_ident[elf.EI_DATA]) {
elf.ELFDATA2LSB => .little,
@@ -469,7 +469,7 @@ pub fn abiAndDynamicLinkerFromFile(
// Reserve some bytes so that we can deref the 64-bit struct fields
// even when the ELF file is 32-bits.
const ph_reserve: usize = @sizeOf(elf.Elf64_Phdr) - @sizeOf(elf.Elf32_Phdr);
const ph_read_byte_len = try preadMin(file, ph_buf[0 .. ph_buf.len - ph_reserve], phoff, phentsize);
const ph_read_byte_len = try preadAtLeast(file, ph_buf[0 .. ph_buf.len - ph_reserve], phoff, phentsize);
var ph_buf_i: usize = 0;
while (ph_buf_i < ph_read_byte_len and ph_i < phnum) : ({
ph_i += 1;
@@ -484,13 +484,13 @@ pub fn abiAndDynamicLinkerFromFile(
const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);
const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);
if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong;
const filesz = @as(usize, @intCast(p_filesz));
_ = try preadMin(file, result.dynamic_linker.buffer[0..filesz], p_offset, filesz);
const filesz: usize = @intCast(p_filesz);
_ = try preadAtLeast(file, result.dynamic_linker.buffer[0..filesz], p_offset, filesz);
// PT_INTERP includes a null byte in filesz.
const len = filesz - 1;
// dynamic_linker.max_byte is "max", not "len".
// We know it will fit in u8 because we check against dynamic_linker.buffer.len above.
result.dynamic_linker.max_byte = @as(u8, @intCast(len - 1));
result.dynamic_linker.len = @intCast(len);
 
// Use it to determine ABI.
const full_ld_path = result.dynamic_linker.buffer[0..len];
@@ -516,7 +516,7 @@ pub fn abiAndDynamicLinkerFromFile(
// Reserve some bytes so that we can deref the 64-bit struct fields
// even when the ELF file is 32-bits.
const dyn_reserve: usize = @sizeOf(elf.Elf64_Dyn) - @sizeOf(elf.Elf32_Dyn);
const dyn_read_byte_len = try preadMin(
const dyn_read_byte_len = try preadAtLeast(
file,
dyn_buf[0 .. dyn_buf.len - dyn_reserve],
dyn_off,
@@ -556,14 +556,14 @@ pub fn abiAndDynamicLinkerFromFile(
var sh_buf: [16 * @sizeOf(elf.Elf64_Shdr)]u8 align(@alignOf(elf.Elf64_Shdr)) = undefined;
if (sh_buf.len < shentsize) return error.InvalidElfFile;
 
_ = try preadMin(file, &sh_buf, str_section_off, shentsize);
_ = try preadAtLeast(file, &sh_buf, str_section_off, shentsize);
const shstr32: *elf.Elf32_Shdr = @ptrCast(@alignCast(&sh_buf));
const shstr64: *elf.Elf64_Shdr = @ptrCast(@alignCast(&sh_buf));
const shstrtab_off = elfInt(is_64, need_bswap, shstr32.sh_offset, shstr64.sh_offset);
const shstrtab_size = elfInt(is_64, need_bswap, shstr32.sh_size, shstr64.sh_size);
var strtab_buf: [4096:0]u8 = undefined;
const shstrtab_len = @min(shstrtab_size, strtab_buf.len);
const shstrtab_read_len = try preadMin(file, &strtab_buf, shstrtab_off, shstrtab_len);
const shstrtab_read_len = try preadAtLeast(file, &strtab_buf, shstrtab_off, shstrtab_len);
const shstrtab = strtab_buf[0..shstrtab_read_len];
 
const shnum = elfInt(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum);
@@ -572,7 +572,7 @@ pub fn abiAndDynamicLinkerFromFile(
// Reserve some bytes so that we can deref the 64-bit struct fields
// even when the ELF file is 32-bits.
const sh_reserve: usize = @sizeOf(elf.Elf64_Shdr) - @sizeOf(elf.Elf32_Shdr);
const sh_read_byte_len = try preadMin(
const sh_read_byte_len = try preadAtLeast(
file,
sh_buf[0 .. sh_buf.len - sh_reserve],
shoff,
@@ -604,7 +604,7 @@ pub fn abiAndDynamicLinkerFromFile(
const rp_max_size = ds.size - rpoff;
 
const strtab_len = @min(rp_max_size, strtab_buf.len);
const strtab_read_len = try preadMin(file, &strtab_buf, rpoff_file, strtab_len);
const strtab_read_len = try preadAtLeast(file, &strtab_buf, rpoff_file, strtab_len);
const strtab = strtab_buf[0..strtab_read_len];
 
const rpath_list = mem.sliceTo(strtab, 0);
@@ -814,9 +814,9 @@ fn glibcVerFromRPath(rpath: []const u8) !std.SemanticVersion {
 
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 = @as(*elf.Elf32_Ehdr, @ptrCast(&hdr_buf));
const hdr64 = @as(*elf.Elf64_Ehdr, @ptrCast(&hdr_buf));
_ = try preadAtLeast(file, &hdr_buf, 0, hdr_buf.len);
const hdr32: *elf.Elf32_Ehdr = @ptrCast(&hdr_buf);
const hdr64: *elf.Elf64_Ehdr = @ptrCast(&hdr_buf);
if (!mem.eql(u8, hdr32.e_ident[0..4], elf.MAGIC)) return error.InvalidElfMagic;
const elf_endian: std.builtin.Endian = switch (hdr32.e_ident[elf.EI_DATA]) {
elf.ELFDATA2LSB => .little,
@@ -838,14 +838,14 @@ fn glibcVerFromSoFile(file: fs.File) !std.SemanticVersion {
var sh_buf: [16 * @sizeOf(elf.Elf64_Shdr)]u8 align(@alignOf(elf.Elf64_Shdr)) = undefined;
if (sh_buf.len < shentsize) return error.InvalidElfFile;
 
_ = try preadMin(file, &sh_buf, str_section_off, shentsize);
_ = try preadAtLeast(file, &sh_buf, str_section_off, shentsize);
const shstr32: *elf.Elf32_Shdr = @ptrCast(@alignCast(&sh_buf));
const shstr64: *elf.Elf64_Shdr = @ptrCast(@alignCast(&sh_buf));
const shstrtab_off = elfInt(is_64, need_bswap, shstr32.sh_offset, shstr64.sh_offset);
const shstrtab_size = elfInt(is_64, need_bswap, shstr32.sh_size, shstr64.sh_size);
var strtab_buf: [4096:0]u8 = undefined;
const shstrtab_len = @min(shstrtab_size, strtab_buf.len);
const shstrtab_read_len = try preadMin(file, &strtab_buf, shstrtab_off, shstrtab_len);
const shstrtab_read_len = try preadAtLeast(file, &strtab_buf, shstrtab_off, shstrtab_len);
const shstrtab = strtab_buf[0..shstrtab_read_len];
const shnum = elfInt(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum);
var sh_i: u16 = 0;
@@ -853,7 +853,7 @@ fn glibcVerFromSoFile(file: fs.File) !std.SemanticVersion {
// Reserve some bytes so that we can deref the 64-bit struct fields
// even when the ELF file is 32-bits.
const sh_reserve: usize = @sizeOf(elf.Elf64_Shdr) - @sizeOf(elf.Elf32_Shdr);
const sh_read_byte_len = try preadMin(
const sh_read_byte_len = try preadAtLeast(
file,
sh_buf[0 .. sh_buf.len - sh_reserve],
shoff,
@@ -890,7 +890,7 @@ fn glibcVerFromSoFile(file: fs.File) !std.SemanticVersion {
 
const dynstr_size: usize = @intCast(dynstr.size);
const dynstr_bytes = buf[0..dynstr_size];
_ = try preadMin(file, dynstr_bytes, dynstr.offset, dynstr_bytes.len);
_ = try preadAtLeast(file, dynstr_bytes, dynstr.offset, dynstr_bytes.len);
var it = mem.splitScalar(u8, dynstr_bytes, 0);
var max_ver: std.SemanticVersion = .{ .major = 2, .minor = 2, .patch = 5 };
while (it.next()) |s| {
@@ -1029,7 +1029,7 @@ fn detectAbiAndDynamicLinker(
};
errdefer file.close();
 
const len = preadMin(file, &buffer, 0, buffer.len) catch |err| switch (err) {
const len = preadAtLeast(file, &buffer, 0, buffer.len) catch |err| switch (err) {
error.UnexpectedEndOfFile,
error.UnableToReadElfFile,
=> break :blk file,
@@ -1083,7 +1083,7 @@ fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os, query: Target.Quer
.abi = abi,
.ofmt = query.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch),
.dynamic_linker = if (query.dynamic_linker.get() == null)
Target.standardDynamicLinkerPath_cpu_os_abi(cpu, os.tag, abi)
Target.DynamicLinker.standard(cpu, os.tag, abi)
else
query.dynamic_linker,
};
@@ -1094,7 +1094,7 @@ const LdInfo = struct {
abi: Target.Abi,
};
 
fn preadMin(file: fs.File, buf: []u8, offset: u64, min_read_len: usize) !usize {
fn preadAtLeast(file: fs.File, buf: []u8, offset: u64, min_read_len: usize) !usize {
var i: usize = 0;
while (i < min_read_len) {
const len = file.pread(buf[i..], offset + i) catch |err| switch (err) {
 
src/Builtin.zig added: 533, removed: 606, total 0
@@ -140,13 +140,11 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void {
}),
.windows => |windows| try buffer.writer().print(
\\ .windows = .{{
\\ .min = {s},
\\ .max = {s},
\\ .min = {c},
\\ .max = {c},
\\ }}}},
\\
,
.{ windows.min, windows.max },
),
, .{ windows.min, windows.max }),
}
try buffer.appendSlice(
\\};