diff options
| author | Jacob Young <jacobly0@users.noreply.github.com> | 2024-04-14 15:24:01 -0400 |
|---|---|---|
| committer | Jacob Young <jacobly0@users.noreply.github.com> | 2024-04-14 15:33:46 -0400 |
| commit | 533f54c68ee18a910e348bf273a713842fdfd127 (patch) | |
| tree | 9294d5b3cf05181aa6479c5bc7d286c5b97a90e0 /lib/std/Target.zig | |
| parent | e45bdc6bd6e47ec3f7a06dbb48f24e842bf43a0d (diff) | |
| download | zig-533f54c68ee18a910e348bf273a713842fdfd127.tar.gz zig-533f54c68ee18a910e348bf273a713842fdfd127.zip | |
Target: cleanup
Diffstat (limited to 'lib/std/Target.zig')
| -rw-r--r-- | lib/std/Target.zig | 872 |
1 files changed, 450 insertions, 422 deletions
diff --git a/lib/std/Target.zig b/lib/std/Target.zig index 55cde46308..7b6b4a9603 100644 --- a/lib/std/Target.zig +++ b/lib/std/Target.zig @@ -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, + .wasi, + .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, + => .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, @@ -275,15 +389,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 +412,50 @@ 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 }, }, }, - .linux => return .{ + .linux => .{ .linux = .{ .range = .{ .min = .{ .major = 4, .minor = 19, .patch = 0 }, @@ -351,13 +465,13 @@ pub const Os = struct { }, }, - .windows => return .{ + .windows => .{ .windows = .{ .min = .win8_1, .max = WindowsVersion.latest, }, }, - } + }; } }; @@ -370,38 +484,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 +632,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 +655,7 @@ pub const Abi = enum { .amdpal, .hermit, .other, - => return .eabi, + => .eabi, .openbsd, .freebsd, .fuchsia, @@ -563,12 +664,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 +683,8 @@ pub const Abi = enum { .liteos, // TODO: audit this .solaris, .illumos, - => return .none, - } + => .none, + }; } pub inline fn isGnu(abi: Abi) bool { @@ -635,7 +736,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 +744,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 +826,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 +852,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 +874,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 +886,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 +1332,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 +1421,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 +1524,76 @@ pub const Cpu = struct { } }; -pub fn zigTriple(self: Target, allocator: Allocator) Allocator.Error![]u8 { - return Query.fromTarget(self).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 linuxTriple(self: Target, allocator: Allocator) ![]u8 { - return linuxTripleSimple(allocator, self.cpu.arch, self.os.tag, self.abi); +pub fn zigTriple(target: Target, allocator: Allocator) Allocator.Error![]u8 { + return Query.fromTarget(target).zigTriple(allocator); } -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(self: Target) [:0]const u8 { - return exeFileExtSimple(self.cpu.arch, self.os.tag); -} - -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 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 staticLibSuffix(self: Target) [:0]const u8 { - return staticLibSuffix_os_abi(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 dynamicLibSuffix(self: Target) [:0]const u8 { - return self.os.tag.dynamicLibSuffix(); +pub fn exeFileExt(target: Target) [:0]const u8 { + return target.os.tag.exeFileExt(target.cpu.arch); } -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 fn staticLibSuffix(target: Target) [:0]const u8 { + return target.os.tag.staticLibSuffix(target.abi); } -pub fn libPrefix(self: Target) [:0]const u8 { - return libPrefix_os_abi(self.os.tag, self.abi); +pub fn dynamicLibSuffix(target: Target) [:0]const u8 { + return target.os.tag.dynamicLibSuffix(); } -pub inline fn isMinGW(self: Target) bool { - return self.os.tag == .windows and self.isGnu(); +pub fn libPrefix(target: Target) [:0]const u8 { + return target.os.tag.libPrefix(target.abi); } -pub inline fn isGnu(self: Target) bool { - return self.abi.isGnu(); +pub inline fn isMinGW(target: Target) bool { + return target.os.tag == .windows and target.isGnu(); } -pub inline fn isMusl(self: Target) bool { - return self.abi.isMusl(); +pub inline fn isGnu(target: Target) bool { + return target.abi.isGnu(); } -pub inline fn isAndroid(self: Target) bool { - return self.abi == .android; +pub inline fn isMusl(target: Target) bool { + return target.abi.isMusl(); } -pub inline fn isWasm(self: Target) bool { - return self.cpu.arch.isWasm(); +pub inline fn isAndroid(target: Target) bool { + return target.abi == .android; } -pub inline fn isDarwin(self: Target) bool { - return self.os.tag.isDarwin(); +pub inline fn isWasm(target: Target) bool { + return target.cpu.arch.isWasm(); } -pub inline fn isBSD(self: Target) bool { - return self.os.tag.isBSD(); +pub inline fn isDarwin(target: Target) bool { + return target.os.tag.isDarwin(); } -pub inline fn isBpfFreestanding(self: Target) bool { - return self.cpu.arch.isBpf() and self.os.tag == .freestanding; +pub inline fn isBSD(target: Target) bool { + return target.os.tag.isBSD(); } -pub inline fn isGnuLibC_os_tag_abi(os_tag: Os.Tag, abi: Abi) bool { - return os_tag == .linux and abi.isGnu(); +pub inline fn isBpfFreestanding(target: Target) bool { + return target.cpu.arch.isBpf() and target.os.tag == .freestanding; } -pub inline fn isGnuLibC(self: Target) bool { - return isGnuLibC_os_tag_abi(self.os.tag, self.abi); +pub inline fn isGnuLibC(target: Target) bool { + return target.os.tag.isGnuLibC(target.abi); } -pub inline fn supportsNewStackCall(self: Target) bool { - return !self.cpu.arch.isWasm(); +pub inline fn supportsNewStackCall(target: Target) bool { + return !target.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 +1601,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 +1636,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 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}); + pub fn eql(lhs: DynamicLinker, rhs: DynamicLinker) bool { + return std.mem.eql(u8, lhs.buffer[0..lhs.len], rhs.buffer[0..rhs.len]); } - 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 }); - } + 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"), - 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 => 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"), - .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, + => initFmt("/lib/ld-linux{s}.so.3", .{switch (abi.floatAbi()) { + .hard => "-armhf", + else => "", + }}) catch unreachable, - .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, + => 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, - .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 }); + // 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, }, - .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"), + .ios, + .tvos, + .watchos, + .macos, + => init("/usr/lib/dyld"), - // Architectures in this list have been verified as not having a standard + // Operating systems 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, + .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. - .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, + .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, + }; } -} +}; -/// 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", - }; +pub fn standardDynamicLinkerPath(target: Target) DynamicLinker { + return DynamicLinker.standard(target.cpu, target.os.tag, target.abi); } pub fn maxIntAlignment(target: Target) u16 { @@ -2076,7 +2116,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 +2459,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 +2471,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 +2541,7 @@ pub fn c_type_alignment(target: Target, c_type: CType) u16 { .wasm32, .wasm64, => 16, - }, + }), ); } @@ -2559,8 +2599,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 +2667,7 @@ pub fn c_type_preferred_alignment(target: Target, c_type: CType) u16 { .wasm32, .wasm64, => 16, - }, + }), ); } @@ -2767,19 +2807,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(); |
