|
//! Contains all the same data as `Target`, additionally introducing the concept of "the native target". //! The purpose of this abstraction is to provide meaningful and unsurprising defaults. //! This struct does reference any resources and it is copyable. |
CpuModel
|
const CrossTarget = @This(); const std = @import("../std.zig"); const builtin = @import("builtin"); const assert = std.debug.assert; const Target = std.Target; const mem = std.mem; |
OsVersionSparse set of CPU features to add to the set from |
/// `null` means native. cpu_arch: ?Target.Cpu.Arch = null, |
SemanticVersionSparse set of CPU features to remove from the set from |
cpu_model: CpuModel = CpuModel.determined_by_cpu_arch, |
DynamicLinker
|
/// Sparse set of CPU features to add to the set from `cpu_model`. cpu_features_add: Target.Cpu.Feature.Set = Target.Cpu.Feature.Set.empty, |
fromTarget()
|
/// Sparse set of CPU features to remove from the set from `cpu_model`. cpu_features_sub: Target.Cpu.Feature.Set = Target.Cpu.Feature.Set.empty, |
toTarget()When cross compiling, |
/// `null` means native. os_tag: ?Target.Os.Tag = null, |
ParseOptions
|
/// `null` means the default version range for `os_tag`. If `os_tag` is `null` (native) /// then `null` for this field means native. os_version_min: ?OsVersion = null, |
Diagnostics
|
/// When cross compiling, `null` means default (latest known OS version). /// When `os_tag` is native, `null` means equal to the native OS version. os_version_max: ?OsVersion = null, |
parse()When |
/// `null` means default when cross compiling, or native when os_tag is native. /// If `isGnuLibC()` is `false`, this must be `null` and is ignored. glibc_version: ?SemanticVersion = null, |
parseCpuArch()
|
/// `null` means the native C ABI, if `os_tag` is native, otherwise it means the default C ABI. abi: ?Target.Abi = null, |
getCpu()Always native |
/// When `os_tag` is `null`, then `null` means native. Otherwise it means the standard path /// based on the `os_tag`. dynamic_linker: DynamicLinker = DynamicLinker{}, |
getCpuArch()Always baseline |
/// `null` means default for the cpu/arch/os combo. ofmt: ?Target.ObjectFormat = null, |
getCpuModel()If CPU Architecture is native, then the CPU model will be native. Otherwise, it will be baseline. |
pub const CpuModel = union(enum) { /// Always native native, |
getCpuFeatures()TODO deprecated, use |
/// Always baseline baseline, |
getOs()This is sometimes called a "triple". It looks roughly like this: riscv64-linux-musl The fields are, respectively: * CPU Architecture * Operating System (and optional version range) * C ABI (optional, with optional glibc version) The string "native" can be used for CPU architecture as well as Operating System. If the CPU Architecture is specified as "native", then the Operating System and C ABI may be omitted. |
/// If CPU Architecture is native, then the CPU model will be native. Otherwise, /// it will be baseline. determined_by_cpu_arch, |
getOsTag()Looks like "name+a+b-c-d+e", where "name" is a CPU Model name, "a", "b", and "e"
are examples of CPU features to add to the set, and "c" and "d" are examples of CPU features
to remove from the set.
The following special strings are recognized for CPU Model name:
* "baseline" - The "default" set of CPU features for cross-compiling. A conservative set
of features that is expected to be supported on most available hardware.
* "native" - The native CPU model is to be detected when compiling.
If this field is not provided ( |
explicit: *const Target.Cpu.Model, }; |
getOsVersionMin()Absolute path to dynamic linker, to override the default, which is either a natively detected path, or a standard path. |
pub const OsVersion = union(enum) { none: void, semver: SemanticVersion, windows: Target.Os.WindowsVersion, }; |
getOsVersionMax()If this is provided, the function will populate some information about parsing failures, so that user-friendly error messages can be delivered. |
pub const SemanticVersion = std.SemanticVersion; |
getAbi()If the architecture was determined, this will be populated. |
pub const DynamicLinker = Target.DynamicLinker; |
isFreeBSD()If the OS name was determined, this will be populated. |
pub fn fromTarget(target: Target) CrossTarget { var result: CrossTarget = .{ .cpu_arch = target.cpu.arch, .cpu_model = .{ .explicit = target.cpu.model }, .os_tag = target.os.tag, .os_version_min = undefined, .os_version_max = undefined, .abi = target.abi, .glibc_version = if (target.isGnuLibC()) target.os.version_range.linux.glibc else null, }; result.updateOsVersionRange(target.os); |
isDarwin()If the OS tag was determined, this will be populated. |
const all_features = target.cpu.arch.allFeaturesList(); var cpu_model_set = target.cpu.model.features; cpu_model_set.populateDependencies(all_features); { // The "add" set is the full set with the CPU Model set removed. const add_set = &result.cpu_features_add; add_set.* = target.cpu.features; add_set.removeFeatureSet(cpu_model_set); } { // The "sub" set is the features that are on in CPU Model set and off in the full set. const sub_set = &result.cpu_features_sub; sub_set.* = cpu_model_set; sub_set.removeFeatureSet(target.cpu.features); } return result; |
zigTriple()If the ABI was determined, this will be populated. |
} |
isOpenBSD()If the CPU name was determined, this will be populated. |
fn updateOsVersionRange(self: *CrossTarget, os: Target.Os) void { switch (os.tag) { .freestanding, .ananas, .cloudabi, .fuchsia, .kfreebsd, .lv2, .solaris, .zos, .haiku, .minix, .rtems, .nacl, .aix, .cuda, .nvcl, .amdhsa, .ps4, .ps5, .elfiamcu, .mesa3d, .contiki, .amdpal, .hermit, .hurd, .wasi, .emscripten, .driverkit, .shadermodel, .uefi, .opencl, .glsl450, .vulkan, .plan9, .other, => { self.os_version_min = .{ .none = {} }; self.os_version_max = .{ .none = {} }; }, |
isUefi()If error.UnknownCpuFeature is returned, this will be populated. |
.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 }; }, |
isDragonFlyBSD()Similar to |
.linux => { self.os_version_min = .{ .semver = os.version_range.linux.range.min }; self.os_version_max = .{ .semver = os.version_range.linux.range.max }; }, |
isLinux()Parses a version with an omitted patch component, such as "1.0", which SemanticVersion.parse is not capable of. |
.windows => { self.os_version_min = .{ .windows = os.version_range.windows.min }; self.os_version_max = .{ .windows = os.version_range.windows.max }; }, } |
zigTriple()TODO deprecated, use |
} |
exeFileExt()TODO deprecated, use |
/// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`. pub fn toTarget(self: CrossTarget) Target { return .{ .cpu = self.getCpu(), .os = self.getOs(), .abi = self.getAbi(), .ofmt = self.getObjectFormat(), }; |
zigTriple()TODO deprecated, use |
} |
dynamicLibSuffix()TODO deprecated, use |
pub const ParseOptions = struct { /// This is sometimes called a "triple". It looks roughly like this: /// riscv64-linux-musl /// The fields are, respectively: /// * CPU Architecture /// * Operating System (and optional version range) /// * C ABI (optional, with optional glibc version) /// The string "native" can be used for CPU architecture as well as Operating System. /// If the CPU Architecture is specified as "native", then the Operating System and C ABI may be omitted. arch_os_abi: []const u8 = "native", |
libPrefix()TODO deprecated, use |
/// Looks like "name+a+b-c-d+e", where "name" is a CPU Model name, "a", "b", and "e" /// are examples of CPU features to add to the set, and "c" and "d" are examples of CPU features /// to remove from the set. /// The following special strings are recognized for CPU Model name: /// * "baseline" - The "default" set of CPU features for cross-compiling. A conservative set /// of features that is expected to be supported on most available hardware. /// * "native" - The native CPU model is to be detected when compiling. /// If this field is not provided (`null`), then the value will depend on the /// parsed CPU Architecture. If native, then this will be "native". Otherwise, it will be "baseline". cpu_features: ?[]const u8 = null, |
isNativeCpu()Formats a version with the patch component omitted if it is zero, unlike SemanticVersion.format which formats all its version components regardless. |
/// Absolute path to dynamic linker, to override the default, which is either a natively /// detected path, or a standard path. dynamic_linker: ?[]const u8 = null, |
isNativeOs()Returned slice must be freed by the caller. |
object_format: ?[]const u8 = null, |
isNativeAbi() |
/// If this is provided, the function will populate some information about parsing failures, /// so that user-friendly error messages can be delivered. diagnostics: ?*Diagnostics = null, |
isNative() |
pub const Diagnostics = struct { /// If the architecture was determined, this will be populated. arch: ?Target.Cpu.Arch = null, |
zigTriple() |
/// If the OS name was determined, this will be populated. os_name: ?[]const u8 = null, |
allocDescription() |
/// If the OS tag was determined, this will be populated. os_tag: ?Target.Os.Tag = null, |
linuxTriple() |
/// If the ABI was determined, this will be populated. abi: ?Target.Abi = null, |
wantSharedLibSymLinks() |
/// If the CPU name was determined, this will be populated. cpu_name: ?[]const u8 = null, |
VcpkgLinkage |
/// If error.UnknownCpuFeature is returned, this will be populated. unknown_feature_name: ?[]const u8 = null, }; }; |
vcpkgTriplet() |
pub fn parse(args: ParseOptions) !CrossTarget { var dummy_diags: ParseOptions.Diagnostics = undefined; const diags = args.diagnostics orelse &dummy_diags; |
isGnuLibC() |
var result: CrossTarget = .{ .dynamic_linker = DynamicLinker.init(args.dynamic_linker), }; |
setGnuLibCVersion() |
var it = mem.splitScalar(u8, args.arch_os_abi, '-'); const arch_name = it.first(); const arch_is_native = mem.eql(u8, arch_name, "native"); if (!arch_is_native) { result.cpu_arch = std.meta.stringToEnum(Target.Cpu.Arch, arch_name) orelse return error.UnknownArchitecture; } const arch = result.getCpuArch(); diags.arch = arch; |
getObjectFormat() |
if (it.next()) |os_text| { try parseOs(&result, diags, os_text); } else if (!arch_is_native) { return error.MissingOperatingSystem; } |
updateCpuFeatures() |
const opt_abi_text = it.next(); if (opt_abi_text) |abi_text| { var abi_it = mem.splitScalar(u8, abi_text, '.'); const abi = std.meta.stringToEnum(Target.Abi, abi_it.first()) orelse return error.UnknownApplicationBinaryInterface; result.abi = abi; diags.abi = abi; |
Test:CrossTarget.parse |
const abi_ver_text = abi_it.rest(); if (abi_it.next() != null) { if (result.isGnuLibC()) { result.glibc_version = parseVersion(abi_ver_text) catch |err| switch (err) { error.Overflow => return error.InvalidAbiVersion, error.InvalidVersion => return error.InvalidAbiVersion, }; } else { return error.InvalidAbiVersion; } } } if (it.next() != null) return error.UnexpectedExtraField; if (args.cpu_features) |cpu_features| { const all_features = arch.allFeaturesList(); var index: usize = 0; while (index < cpu_features.len and cpu_features[index] != '+' and cpu_features[index] != '-') { index += 1; } const cpu_name = cpu_features[0..index]; diags.cpu_name = cpu_name; const add_set = &result.cpu_features_add; const sub_set = &result.cpu_features_sub; if (mem.eql(u8, cpu_name, "native")) { result.cpu_model = .native; } else if (mem.eql(u8, cpu_name, "baseline")) { result.cpu_model = .baseline; } else { result.cpu_model = .{ .explicit = try arch.parseCpuModel(cpu_name) }; } while (index < cpu_features.len) { const op = cpu_features[index]; const set = switch (op) { '+' => add_set, '-' => sub_set, else => unreachable, }; index += 1; const start = index; while (index < cpu_features.len and cpu_features[index] != '+' and cpu_features[index] != '-') { index += 1; } const feature_name = cpu_features[start..index]; for (all_features, 0..) |feature, feat_index_usize| { const feat_index = @as(Target.Cpu.Feature.Set.Index, @intCast(feat_index_usize)); if (mem.eql(u8, feature_name, feature.name)) { set.addFeature(feat_index); break; } } else { diags.unknown_feature_name = feature_name; return error.UnknownCpuFeature; } } } if (args.object_format) |ofmt_name| { result.ofmt = std.meta.stringToEnum(Target.ObjectFormat, ofmt_name) orelse return error.UnknownObjectFormat; } return result; } /// Similar to `parse` except instead of fully parsing, it only determines the CPU /// architecture and returns it if it can be determined, and returns `null` otherwise. /// This is intended to be used if the API user of CrossTarget needs to learn the /// target CPU architecture in order to fully populate `ParseOptions`. pub fn parseCpuArch(args: ParseOptions) ?Target.Cpu.Arch { var it = mem.splitScalar(u8, args.arch_os_abi, '-'); const arch_name = it.first(); const arch_is_native = mem.eql(u8, arch_name, "native"); if (arch_is_native) { return builtin.cpu.arch; } else { return std.meta.stringToEnum(Target.Cpu.Arch, arch_name); } } /// Parses a version with an omitted patch component, such as "1.0", /// which SemanticVersion.parse is not capable of. fn parseVersion(ver: []const u8) !SemanticVersion { const parseVersionComponent = struct { fn parseVersionComponent(component: []const u8) !usize { return std.fmt.parseUnsigned(usize, component, 10) catch |err| { switch (err) { error.InvalidCharacter => return error.InvalidVersion, error.Overflow => return error.Overflow, } }; } }.parseVersionComponent; var version_components = mem.split(u8, ver, "."); const major = version_components.first(); const minor = version_components.next() orelse return error.InvalidVersion; const patch = version_components.next() orelse "0"; if (version_components.next() != null) return error.InvalidVersion; return .{ .major = try parseVersionComponent(major), .minor = try parseVersionComponent(minor), .patch = try parseVersionComponent(patch), }; } /// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`. pub fn getCpu(self: CrossTarget) Target.Cpu { switch (self.cpu_model) { .native => { // This works when doing `zig build` because Zig generates a build executable using // native CPU model & features. However this will not be accurate otherwise, and // will need to be integrated with `std.zig.system.NativeTargetInfo.detect`. return builtin.cpu; }, .baseline => { var adjusted_baseline = Target.Cpu.baseline(self.getCpuArch()); self.updateCpuFeatures(&adjusted_baseline.features); return adjusted_baseline; }, .determined_by_cpu_arch => if (self.cpu_arch == null) { // This works when doing `zig build` because Zig generates a build executable using // native CPU model & features. However this will not be accurate otherwise, and // will need to be integrated with `std.zig.system.NativeTargetInfo.detect`. return builtin.cpu; } else { var adjusted_baseline = Target.Cpu.baseline(self.getCpuArch()); self.updateCpuFeatures(&adjusted_baseline.features); return adjusted_baseline; }, .explicit => |model| { var adjusted_model = model.toCpu(self.getCpuArch()); self.updateCpuFeatures(&adjusted_model.features); return adjusted_model; }, } } pub fn getCpuArch(self: CrossTarget) Target.Cpu.Arch { return self.cpu_arch orelse builtin.cpu.arch; } pub fn getCpuModel(self: CrossTarget) *const Target.Cpu.Model { return switch (self.cpu_model) { .explicit => |cpu_model| cpu_model, else => self.getCpu().model, }; } pub fn getCpuFeatures(self: CrossTarget) Target.Cpu.Feature.Set { return self.getCpu().features; } /// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`. pub fn getOs(self: CrossTarget) Target.Os { // `builtin.os` works when doing `zig build` because Zig generates a build executable using // native OS version range. However this will not be accurate otherwise, and // will need to be integrated with `std.zig.system.NativeTargetInfo.detect`. var adjusted_os = if (self.os_tag) |os_tag| os_tag.defaultVersionRange(self.getCpuArch()) else builtin.os; if (self.os_version_min) |min| switch (min) { .none => {}, .semver => |semver| switch (self.getOsTag()) { .linux => adjusted_os.version_range.linux.range.min = semver, else => adjusted_os.version_range.semver.min = semver, }, .windows => |win_ver| adjusted_os.version_range.windows.min = win_ver, }; if (self.os_version_max) |max| switch (max) { .none => {}, .semver => |semver| switch (self.getOsTag()) { .linux => adjusted_os.version_range.linux.range.max = semver, else => adjusted_os.version_range.semver.max = semver, }, .windows => |win_ver| adjusted_os.version_range.windows.max = win_ver, }; if (self.glibc_version) |glibc| { assert(self.isGnuLibC()); adjusted_os.version_range.linux.glibc = glibc; } return adjusted_os; } pub fn getOsTag(self: CrossTarget) Target.Os.Tag { return self.os_tag orelse builtin.os.tag; } /// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`. pub fn getOsVersionMin(self: CrossTarget) OsVersion { if (self.os_version_min) |version_min| return version_min; var tmp: CrossTarget = undefined; tmp.updateOsVersionRange(self.getOs()); return tmp.os_version_min.?; } /// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`. pub fn getOsVersionMax(self: CrossTarget) OsVersion { if (self.os_version_max) |version_max| return version_max; var tmp: CrossTarget = undefined; tmp.updateOsVersionRange(self.getOs()); return tmp.os_version_max.?; } /// TODO deprecated, use `std.zig.system.NativeTargetInfo.detect`. pub fn getAbi(self: CrossTarget) Target.Abi { if (self.abi) |abi| return abi; if (self.os_tag == null) { // This works when doing `zig build` because Zig generates a build executable using // native CPU model & features. However this will not be accurate otherwise, and // will need to be integrated with `std.zig.system.NativeTargetInfo.detect`. return builtin.abi; } return Target.Abi.default(self.getCpuArch(), self.getOs()); } pub fn isFreeBSD(self: CrossTarget) bool { return self.getOsTag() == .freebsd; } pub fn isDarwin(self: CrossTarget) bool { return self.getOsTag().isDarwin(); } pub fn isNetBSD(self: CrossTarget) bool { return self.getOsTag() == .netbsd; } pub fn isOpenBSD(self: CrossTarget) bool { return self.getOsTag() == .openbsd; } pub fn isUefi(self: CrossTarget) bool { return self.getOsTag() == .uefi; } pub fn isDragonFlyBSD(self: CrossTarget) bool { return self.getOsTag() == .dragonfly; } pub fn isLinux(self: CrossTarget) bool { return self.getOsTag() == .linux; } pub fn isWindows(self: CrossTarget) bool { return self.getOsTag() == .windows; } pub fn exeFileExt(self: CrossTarget) [:0]const u8 { return Target.exeFileExtSimple(self.getCpuArch(), self.getOsTag()); } pub fn staticLibSuffix(self: CrossTarget) [:0]const u8 { return Target.staticLibSuffix_os_abi(self.getOsTag(), self.getAbi()); } pub fn dynamicLibSuffix(self: CrossTarget) [:0]const u8 { return self.getOsTag().dynamicLibSuffix(); } pub fn libPrefix(self: CrossTarget) [:0]const u8 { return Target.libPrefix_os_abi(self.getOsTag(), self.getAbi()); } pub fn isNativeCpu(self: CrossTarget) bool { return self.cpu_arch == null and (self.cpu_model == .native or self.cpu_model == .determined_by_cpu_arch) and self.cpu_features_sub.isEmpty() and self.cpu_features_add.isEmpty(); } pub fn isNativeOs(self: CrossTarget) bool { return self.os_tag == null and self.os_version_min == null and self.os_version_max == null and self.dynamic_linker.get() == null and self.glibc_version == null; } pub fn isNativeAbi(self: CrossTarget) bool { return self.os_tag == null and self.abi == null; } pub fn isNative(self: CrossTarget) bool { return self.isNativeCpu() and self.isNativeOs() and self.isNativeAbi(); } /// Formats a version with the patch component omitted if it is zero, /// unlike SemanticVersion.format which formats all its version components regardless. fn formatVersion(version: SemanticVersion, writer: anytype) !void { if (version.patch == 0) { try writer.print("{d}.{d}", .{ version.major, version.minor }); } else { try writer.print("{d}.{d}.{d}", .{ version.major, version.minor, version.patch }); } } pub fn zigTriple(self: CrossTarget, allocator: mem.Allocator) error{OutOfMemory}![]u8 { if (self.isNative()) { return allocator.dupe(u8, "native"); } const arch_name = if (self.cpu_arch) |arch| @tagName(arch) else "native"; const os_name = if (self.os_tag) |os_tag| @tagName(os_tag) else "native"; var result = std.ArrayList(u8).init(allocator); defer result.deinit(); try result.writer().print("{s}-{s}", .{ arch_name, os_name }); // The zig target syntax does not allow specifying a max os version with no min, so // if either are present, we need the min. if (self.os_version_min != null or self.os_version_max != null) { switch (self.getOsVersionMin()) { .none => {}, .semver => |v| { try result.writer().writeAll("."); try formatVersion(v, result.writer()); }, .windows => |v| try result.writer().print("{s}", .{v}), } } if (self.os_version_max) |max| { switch (max) { .none => {}, .semver => |v| { try result.writer().writeAll("..."); try formatVersion(v, result.writer()); }, .windows => |v| try result.writer().print("..{s}", .{v}), } } if (self.glibc_version) |v| { try result.writer().print("-{s}.", .{@tagName(self.getAbi())}); try formatVersion(v, result.writer()); } else if (self.abi) |abi| { try result.writer().print("-{s}", .{@tagName(abi)}); } return result.toOwnedSlice(); } pub fn allocDescription(self: CrossTarget, allocator: mem.Allocator) ![]u8 { // TODO is there anything else worthy of the description that is not // already captured in the triple? return self.zigTriple(allocator); } pub fn linuxTriple(self: CrossTarget, allocator: mem.Allocator) ![]u8 { return Target.linuxTripleSimple(allocator, self.getCpuArch(), self.getOsTag(), self.getAbi()); } pub fn wantSharedLibSymLinks(self: CrossTarget) bool { return self.getOsTag() != .windows; } pub const VcpkgLinkage = std.builtin.LinkMode; /// Returned slice must be freed by the caller. pub fn vcpkgTriplet(self: CrossTarget, allocator: mem.Allocator, linkage: VcpkgLinkage) ![]u8 { const arch = switch (self.getCpuArch()) { .x86 => "x86", .x86_64 => "x64", .arm, .armeb, .thumb, .thumbeb, .aarch64_32, => "arm", .aarch64, .aarch64_be, => "arm64", else => return error.UnsupportedVcpkgArchitecture, }; const os = switch (self.getOsTag()) { .windows => "windows", .linux => "linux", .macos => "macos", else => return error.UnsupportedVcpkgOperatingSystem, }; const static_suffix = switch (linkage) { .Static => "-static", .Dynamic => "", }; return std.fmt.allocPrint(allocator, "{s}-{s}{s}", .{ arch, os, static_suffix }); } pub fn isGnuLibC(self: CrossTarget) bool { return Target.isGnuLibC_os_tag_abi(self.getOsTag(), self.getAbi()); } pub fn setGnuLibCVersion(self: *CrossTarget, major: u32, minor: u32, patch: u32) void { assert(self.isGnuLibC()); self.glibc_version = SemanticVersion{ .major = major, .minor = minor, .patch = patch }; } pub fn getObjectFormat(self: CrossTarget) Target.ObjectFormat { return self.ofmt orelse Target.ObjectFormat.default(self.getOsTag(), self.getCpuArch()); } pub fn updateCpuFeatures(self: CrossTarget, set: *Target.Cpu.Feature.Set) void { set.removeFeatureSet(self.cpu_features_sub); set.addFeatureSet(self.cpu_features_add); set.populateDependencies(self.getCpuArch().allFeaturesList()); set.removeFeatureSet(self.cpu_features_sub); } fn parseOs(result: *CrossTarget, diags: *ParseOptions.Diagnostics, text: []const u8) !void { var it = mem.splitScalar(u8, text, '.'); const os_name = it.first(); diags.os_name = os_name; const os_is_native = mem.eql(u8, os_name, "native"); if (!os_is_native) { result.os_tag = std.meta.stringToEnum(Target.Os.Tag, os_name) orelse return error.UnknownOperatingSystem; } const tag = result.getOsTag(); diags.os_tag = tag; const version_text = it.rest(); if (it.next() == null) return; switch (tag) { .freestanding, .ananas, .cloudabi, .fuchsia, .kfreebsd, .lv2, .solaris, .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, .other, => return error.InvalidOperatingSystemVersion, .freebsd, .macos, .ios, .tvos, .watchos, .netbsd, .openbsd, .linux, .dragonfly, => { 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 = 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 = max_ver }; }, .windows => { 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 }; }, } } test "CrossTarget.parse" { if (builtin.target.isGnuLibC()) { var cross_target = try CrossTarget.parse(.{}); cross_target.setGnuLibCVersion(2, 1, 1); const text = try cross_target.zigTriple(std.testing.allocator); defer std.testing.allocator.free(text); var buf: [256]u8 = undefined; const triple = std.fmt.bufPrint( buf[0..], "native-native-{s}.2.1.1", .{@tagName(builtin.abi)}, ) catch unreachable; try std.testing.expectEqualSlices(u8, triple, text); } { const cross_target = try CrossTarget.parse(.{ .arch_os_abi = "aarch64-linux", .cpu_features = "native", }); try std.testing.expect(cross_target.cpu_arch.? == .aarch64); try std.testing.expect(cross_target.cpu_model == .native); } { const cross_target = try CrossTarget.parse(.{ .arch_os_abi = "native" }); try std.testing.expect(cross_target.cpu_arch == null); try std.testing.expect(cross_target.isNative()); const text = try cross_target.zigTriple(std.testing.allocator); defer std.testing.allocator.free(text); try std.testing.expectEqualSlices(u8, "native", text); } { const cross_target = try CrossTarget.parse(.{ .arch_os_abi = "x86_64-linux-gnu", .cpu_features = "x86_64-sse-sse2-avx-cx8", }); const target = cross_target.toTarget(); try std.testing.expect(target.os.tag == .linux); try std.testing.expect(target.abi == .gnu); try std.testing.expect(target.cpu.arch == .x86_64); try std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .sse)); try std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .avx)); try std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .cx8)); try std.testing.expect(Target.x86.featureSetHas(target.cpu.features, .cmov)); try std.testing.expect(Target.x86.featureSetHas(target.cpu.features, .fxsr)); try std.testing.expect(Target.x86.featureSetHasAny(target.cpu.features, .{ .sse, .avx, .cmov })); try std.testing.expect(!Target.x86.featureSetHasAny(target.cpu.features, .{ .sse, .avx })); try std.testing.expect(Target.x86.featureSetHasAll(target.cpu.features, .{ .mmx, .x87 })); try std.testing.expect(!Target.x86.featureSetHasAll(target.cpu.features, .{ .mmx, .x87, .sse })); const text = try cross_target.zigTriple(std.testing.allocator); defer std.testing.allocator.free(text); try std.testing.expectEqualSlices(u8, "x86_64-linux-gnu", text); } { const cross_target = try CrossTarget.parse(.{ .arch_os_abi = "arm-linux-musleabihf", .cpu_features = "generic+v8a", }); const target = cross_target.toTarget(); try std.testing.expect(target.os.tag == .linux); try std.testing.expect(target.abi == .musleabihf); try std.testing.expect(target.cpu.arch == .arm); try std.testing.expect(target.cpu.model == &Target.arm.cpu.generic); try std.testing.expect(Target.arm.featureSetHas(target.cpu.features, .v8a)); const text = try cross_target.zigTriple(std.testing.allocator); defer std.testing.allocator.free(text); try std.testing.expectEqualSlices(u8, "arm-linux-musleabihf", text); } { const cross_target = try CrossTarget.parse(.{ .arch_os_abi = "aarch64-linux.3.10...4.4.1-gnu.2.27", .cpu_features = "generic+v8a", }); const target = cross_target.toTarget(); try std.testing.expect(target.cpu.arch == .aarch64); try std.testing.expect(target.os.tag == .linux); try std.testing.expect(target.os.version_range.linux.range.min.major == 3); try std.testing.expect(target.os.version_range.linux.range.min.minor == 10); try std.testing.expect(target.os.version_range.linux.range.min.patch == 0); try std.testing.expect(target.os.version_range.linux.range.max.major == 4); try std.testing.expect(target.os.version_range.linux.range.max.minor == 4); try std.testing.expect(target.os.version_range.linux.range.max.patch == 1); try std.testing.expect(target.os.version_range.linux.glibc.major == 2); try std.testing.expect(target.os.version_range.linux.glibc.minor == 27); try std.testing.expect(target.os.version_range.linux.glibc.patch == 0); try std.testing.expect(target.abi == .gnu); const text = try cross_target.zigTriple(std.testing.allocator); defer std.testing.allocator.free(text); try std.testing.expectEqualSlices(u8, "aarch64-linux.3.10...4.4.1-gnu.2.27", text); } } |
Generated by zstd-live on 2025-08-13 02:35:14 UTC. |