blob e22fbcbf (26692B) - Raw
1 //! Contains all the same data as `Target`, additionally introducing the 2 //! concept of "the native target". The purpose of this abstraction is to 3 //! provide meaningful and unsurprising defaults. This struct does reference 4 //! any resources and it is copyable. 5 6 /// `null` means native. 7 cpu_arch: ?Target.Cpu.Arch = null, 8 9 cpu_model: CpuModel = CpuModel.determined_by_cpu_arch, 10 11 /// Sparse set of CPU features to add to the set from `cpu_model`. 12 cpu_features_add: Target.Cpu.Feature.Set = Target.Cpu.Feature.Set.empty, 13 14 /// Sparse set of CPU features to remove from the set from `cpu_model`. 15 cpu_features_sub: Target.Cpu.Feature.Set = Target.Cpu.Feature.Set.empty, 16 17 /// `null` means native. 18 os_tag: ?Target.Os.Tag = null, 19 20 /// `null` means the default version range for `os_tag`. If `os_tag` is `null` (native) 21 /// then `null` for this field means native. 22 os_version_min: ?OsVersion = null, 23 24 /// When cross compiling, `null` means default (latest known OS version). 25 /// When `os_tag` is native, `null` means equal to the native OS version. 26 os_version_max: ?OsVersion = null, 27 28 /// `null` means default when cross compiling, or native when os_tag is native. 29 /// If `isGnuLibC()` is `false`, this must be `null` and is ignored. 30 glibc_version: ?SemanticVersion = null, 31 32 /// `null` means the native C ABI, if `os_tag` is native, otherwise it means the default C ABI. 33 abi: ?Target.Abi = null, 34 35 /// When `os_tag` is `null`, then `null` means native. Otherwise it means the standard path 36 /// based on the `os_tag`. 37 dynamic_linker: Target.DynamicLinker = Target.DynamicLinker.none, 38 39 /// `null` means default for the cpu/arch/os combo. 40 ofmt: ?Target.ObjectFormat = null, 41 42 pub const CpuModel = union(enum) { 43 /// Always native 44 native, 45 46 /// Always baseline 47 baseline, 48 49 /// If CPU Architecture is native, then the CPU model will be native. Otherwise, 50 /// it will be baseline. 51 determined_by_cpu_arch, 52 53 explicit: *const Target.Cpu.Model, 54 55 pub fn eql(a: CpuModel, b: CpuModel) bool { 56 const Tag = @typeInfo(CpuModel).@"union".tag_type.?; 57 const a_tag: Tag = a; 58 const b_tag: Tag = b; 59 if (a_tag != b_tag) return false; 60 return switch (a) { 61 .native, .baseline, .determined_by_cpu_arch => true, 62 .explicit => |a_model| a_model == b.explicit, 63 }; 64 } 65 }; 66 67 pub const OsVersion = union(enum) { 68 none: void, 69 semver: SemanticVersion, 70 windows: Target.Os.WindowsVersion, 71 72 pub fn eql(a: OsVersion, b: OsVersion) bool { 73 const Tag = @typeInfo(OsVersion).@"union".tag_type.?; 74 const a_tag: Tag = a; 75 const b_tag: Tag = b; 76 if (a_tag != b_tag) return false; 77 return switch (a) { 78 .none => true, 79 .semver => |a_semver| a_semver.order(b.semver) == .eq, 80 .windows => |a_windows| a_windows == b.windows, 81 }; 82 } 83 84 pub fn eqlOpt(a: ?OsVersion, b: ?OsVersion) bool { 85 if (a == null and b == null) return true; 86 if (a == null or b == null) return false; 87 return OsVersion.eql(a.?, b.?); 88 } 89 }; 90 91 pub const SemanticVersion = std.SemanticVersion; 92 93 pub fn fromTarget(target: Target) Query { 94 var result: Query = .{ 95 .cpu_arch = target.cpu.arch, 96 .cpu_model = .{ .explicit = target.cpu.model }, 97 .os_tag = target.os.tag, 98 .os_version_min = undefined, 99 .os_version_max = undefined, 100 .abi = target.abi, 101 .glibc_version = if (target.isGnuLibC()) 102 target.os.version_range.linux.glibc 103 else 104 null, 105 }; 106 result.updateOsVersionRange(target.os); 107 108 const all_features = target.cpu.arch.allFeaturesList(); 109 var cpu_model_set = target.cpu.model.features; 110 cpu_model_set.populateDependencies(all_features); 111 { 112 // The "add" set is the full set with the CPU Model set removed. 113 const add_set = &result.cpu_features_add; 114 add_set.* = target.cpu.features; 115 add_set.removeFeatureSet(cpu_model_set); 116 } 117 { 118 // The "sub" set is the features that are on in CPU Model set and off in the full set. 119 const sub_set = &result.cpu_features_sub; 120 sub_set.* = cpu_model_set; 121 sub_set.removeFeatureSet(target.cpu.features); 122 } 123 return result; 124 } 125 126 fn updateOsVersionRange(self: *Query, os: Target.Os) void { 127 self.os_version_min, self.os_version_max = switch (os.tag.getVersionRangeTag()) { 128 .none => .{ .{ .none = {} }, .{ .none = {} } }, 129 .semver => .{ 130 .{ .semver = os.version_range.semver.min }, 131 .{ .semver = os.version_range.semver.max }, 132 }, 133 .linux => .{ 134 .{ .semver = os.version_range.linux.range.min }, 135 .{ .semver = os.version_range.linux.range.max }, 136 }, 137 .windows => .{ 138 .{ .windows = os.version_range.windows.min }, 139 .{ .windows = os.version_range.windows.max }, 140 }, 141 }; 142 } 143 144 pub const ParseOptions = struct { 145 /// This is sometimes called a "triple". It looks roughly like this: 146 /// riscv64-linux-musl 147 /// The fields are, respectively: 148 /// * CPU Architecture 149 /// * Operating System (and optional version range) 150 /// * C ABI (optional, with optional glibc version) 151 /// The string "native" can be used for CPU architecture as well as Operating System. 152 /// If the CPU Architecture is specified as "native", then the Operating System and C ABI may be omitted. 153 arch_os_abi: []const u8 = "native", 154 155 /// Looks like "name+a+b-c-d+e", where "name" is a CPU Model name, "a", "b", and "e" 156 /// are examples of CPU features to add to the set, and "c" and "d" are examples of CPU features 157 /// to remove from the set. 158 /// The following special strings are recognized for CPU Model name: 159 /// * "baseline" - The "default" set of CPU features for cross-compiling. A conservative set 160 /// of features that is expected to be supported on most available hardware. 161 /// * "native" - The native CPU model is to be detected when compiling. 162 /// If this field is not provided (`null`), then the value will depend on the 163 /// parsed CPU Architecture. If native, then this will be "native". Otherwise, it will be "baseline". 164 cpu_features: ?[]const u8 = null, 165 166 /// Absolute path to dynamic linker, to override the default, which is either a natively 167 /// detected path, or a standard path. 168 dynamic_linker: ?[]const u8 = null, 169 170 object_format: ?[]const u8 = null, 171 172 /// If this is provided, the function will populate some information about parsing failures, 173 /// so that user-friendly error messages can be delivered. 174 diagnostics: ?*Diagnostics = null, 175 176 pub const Diagnostics = struct { 177 /// If the architecture was determined, this will be populated. 178 arch: ?Target.Cpu.Arch = null, 179 180 /// If the OS name was determined, this will be populated. 181 os_name: ?[]const u8 = null, 182 183 /// If the OS tag was determined, this will be populated. 184 os_tag: ?Target.Os.Tag = null, 185 186 /// If the ABI was determined, this will be populated. 187 abi: ?Target.Abi = null, 188 189 /// If the CPU name was determined, this will be populated. 190 cpu_name: ?[]const u8 = null, 191 192 /// If error.UnknownCpuFeature is returned, this will be populated. 193 unknown_feature_name: ?[]const u8 = null, 194 }; 195 }; 196 197 pub fn parse(args: ParseOptions) !Query { 198 var dummy_diags: ParseOptions.Diagnostics = undefined; 199 const diags = args.diagnostics orelse &dummy_diags; 200 201 var result: Query = .{ 202 .dynamic_linker = Target.DynamicLinker.init(args.dynamic_linker), 203 }; 204 205 var it = mem.splitScalar(u8, args.arch_os_abi, '-'); 206 const arch_name = it.first(); 207 const arch_is_native = mem.eql(u8, arch_name, "native"); 208 if (!arch_is_native) { 209 result.cpu_arch = std.meta.stringToEnum(Target.Cpu.Arch, arch_name) orelse 210 return error.UnknownArchitecture; 211 } 212 const arch = result.cpu_arch orelse builtin.cpu.arch; 213 diags.arch = arch; 214 215 if (it.next()) |os_text| { 216 try parseOs(&result, diags, os_text); 217 } else if (!arch_is_native) { 218 return error.MissingOperatingSystem; 219 } 220 221 const opt_abi_text = it.next(); 222 if (opt_abi_text) |abi_text| { 223 var abi_it = mem.splitScalar(u8, abi_text, '.'); 224 const abi = std.meta.stringToEnum(Target.Abi, abi_it.first()) orelse 225 return error.UnknownApplicationBinaryInterface; 226 result.abi = abi; 227 diags.abi = abi; 228 229 const abi_ver_text = abi_it.rest(); 230 if (abi_it.next() != null) { 231 const tag = result.os_tag orelse builtin.os.tag; 232 if (tag.isGnuLibC(abi)) { 233 result.glibc_version = parseVersion(abi_ver_text) catch |err| switch (err) { 234 error.Overflow => return error.InvalidAbiVersion, 235 error.InvalidVersion => return error.InvalidAbiVersion, 236 }; 237 } else { 238 return error.InvalidAbiVersion; 239 } 240 } 241 } 242 243 if (it.next() != null) return error.UnexpectedExtraField; 244 245 if (args.cpu_features) |cpu_features| { 246 const all_features = arch.allFeaturesList(); 247 var index: usize = 0; 248 while (index < cpu_features.len and 249 cpu_features[index] != '+' and 250 cpu_features[index] != '-') 251 { 252 index += 1; 253 } 254 const cpu_name = cpu_features[0..index]; 255 diags.cpu_name = cpu_name; 256 257 const add_set = &result.cpu_features_add; 258 const sub_set = &result.cpu_features_sub; 259 if (mem.eql(u8, cpu_name, "native")) { 260 result.cpu_model = .native; 261 } else if (mem.eql(u8, cpu_name, "baseline")) { 262 result.cpu_model = .baseline; 263 } else { 264 result.cpu_model = .{ .explicit = try arch.parseCpuModel(cpu_name) }; 265 } 266 267 while (index < cpu_features.len) { 268 const op = cpu_features[index]; 269 const set = switch (op) { 270 '+' => add_set, 271 '-' => sub_set, 272 else => unreachable, 273 }; 274 index += 1; 275 const start = index; 276 while (index < cpu_features.len and 277 cpu_features[index] != '+' and 278 cpu_features[index] != '-') 279 { 280 index += 1; 281 } 282 const feature_name = cpu_features[start..index]; 283 for (all_features, 0..) |feature, feat_index_usize| { 284 const feat_index = @as(Target.Cpu.Feature.Set.Index, @intCast(feat_index_usize)); 285 if (mem.eql(u8, feature_name, feature.name)) { 286 set.addFeature(feat_index); 287 break; 288 } 289 } else { 290 diags.unknown_feature_name = feature_name; 291 return error.UnknownCpuFeature; 292 } 293 } 294 } 295 296 if (args.object_format) |ofmt_name| { 297 result.ofmt = std.meta.stringToEnum(Target.ObjectFormat, ofmt_name) orelse 298 return error.UnknownObjectFormat; 299 } 300 301 return result; 302 } 303 304 /// Similar to `parse` except instead of fully parsing, it only determines the CPU 305 /// architecture and returns it if it can be determined, and returns `null` otherwise. 306 /// This is intended to be used if the API user of Query needs to learn the 307 /// target CPU architecture in order to fully populate `ParseOptions`. 308 pub fn parseCpuArch(args: ParseOptions) ?Target.Cpu.Arch { 309 var it = mem.splitScalar(u8, args.arch_os_abi, '-'); 310 const arch_name = it.first(); 311 const arch_is_native = mem.eql(u8, arch_name, "native"); 312 if (arch_is_native) { 313 return builtin.cpu.arch; 314 } else { 315 return std.meta.stringToEnum(Target.Cpu.Arch, arch_name); 316 } 317 } 318 319 /// Similar to `SemanticVersion.parse`, but with following changes: 320 /// * Leading zeroes are allowed. 321 /// * Supports only 2 or 3 version components (major, minor, [patch]). If 3-rd component is omitted, it will be 0. 322 pub fn parseVersion(ver: []const u8) error{ InvalidVersion, Overflow }!SemanticVersion { 323 const parseVersionComponentFn = (struct { 324 fn parseVersionComponentInner(component: []const u8) error{ InvalidVersion, Overflow }!usize { 325 return std.fmt.parseUnsigned(usize, component, 10) catch |err| switch (err) { 326 error.InvalidCharacter => return error.InvalidVersion, 327 error.Overflow => return error.Overflow, 328 }; 329 } 330 }).parseVersionComponentInner; 331 var version_components = mem.splitScalar(u8, ver, '.'); 332 const major = version_components.first(); 333 const minor = version_components.next() orelse return error.InvalidVersion; 334 const patch = version_components.next() orelse "0"; 335 if (version_components.next() != null) return error.InvalidVersion; 336 return .{ 337 .major = try parseVersionComponentFn(major), 338 .minor = try parseVersionComponentFn(minor), 339 .patch = try parseVersionComponentFn(patch), 340 }; 341 } 342 343 test parseVersion { 344 try std.testing.expectError(error.InvalidVersion, parseVersion("1")); 345 try std.testing.expectEqual(SemanticVersion{ .major = 1, .minor = 2, .patch = 0 }, try parseVersion("1.2")); 346 try std.testing.expectEqual(SemanticVersion{ .major = 1, .minor = 2, .patch = 3 }, try parseVersion("1.2.3")); 347 try std.testing.expectError(error.InvalidVersion, parseVersion("1.2.3.4")); 348 } 349 350 pub fn isNativeCpu(self: Query) bool { 351 return self.cpu_arch == null and 352 (self.cpu_model == .native or self.cpu_model == .determined_by_cpu_arch) and 353 self.cpu_features_sub.isEmpty() and self.cpu_features_add.isEmpty(); 354 } 355 356 pub fn isNativeOs(self: Query) bool { 357 return self.os_tag == null and self.os_version_min == null and self.os_version_max == null and 358 self.dynamic_linker.get() == null and self.glibc_version == null; 359 } 360 361 pub fn isNativeAbi(self: Query) bool { 362 return self.os_tag == null and self.abi == null; 363 } 364 365 pub fn isNativeTriple(self: Query) bool { 366 return self.isNativeCpu() and self.isNativeOs() and self.isNativeAbi(); 367 } 368 369 pub fn isNative(self: Query) bool { 370 return self.isNativeTriple() and self.ofmt == null; 371 } 372 373 pub fn canDetectLibC(self: Query) bool { 374 if (self.isNativeOs()) return true; 375 if (self.os_tag) |os| { 376 if (builtin.os.tag == .macos and os.isDarwin()) return true; 377 if (os == .linux and self.abi.isAndroid()) return true; 378 } 379 return false; 380 } 381 382 /// Formats a version with the patch component omitted if it is zero, 383 /// unlike SemanticVersion.format which formats all its version components regardless. 384 fn formatVersion(version: SemanticVersion, writer: anytype) !void { 385 if (version.patch == 0) { 386 try writer.print("{d}.{d}", .{ version.major, version.minor }); 387 } else { 388 try writer.print("{d}.{d}.{d}", .{ version.major, version.minor, version.patch }); 389 } 390 } 391 392 pub fn zigTriple(self: Query, allocator: Allocator) Allocator.Error![]u8 { 393 if (self.isNativeTriple()) 394 return allocator.dupe(u8, "native"); 395 396 const arch_name = if (self.cpu_arch) |arch| @tagName(arch) else "native"; 397 const os_name = if (self.os_tag) |os_tag| @tagName(os_tag) else "native"; 398 399 var result = std.ArrayList(u8).init(allocator); 400 defer result.deinit(); 401 402 try result.writer().print("{s}-{s}", .{ arch_name, os_name }); 403 404 // The zig target syntax does not allow specifying a max os version with no min, so 405 // if either are present, we need the min. 406 if (self.os_version_min) |min| { 407 switch (min) { 408 .none => {}, 409 .semver => |v| { 410 try result.writer().writeAll("."); 411 try formatVersion(v, result.writer()); 412 }, 413 .windows => |v| { 414 try result.writer().print("{s}", .{v}); 415 }, 416 } 417 } 418 if (self.os_version_max) |max| { 419 switch (max) { 420 .none => {}, 421 .semver => |v| { 422 try result.writer().writeAll("..."); 423 try formatVersion(v, result.writer()); 424 }, 425 .windows => |v| { 426 // This is counting on a custom format() function defined on `WindowsVersion` 427 // to add a prefix '.' and make there be a total of three dots. 428 try result.writer().print("..{s}", .{v}); 429 }, 430 } 431 } 432 433 if (self.glibc_version) |v| { 434 const name = if (self.abi) |abi| @tagName(abi) else "gnu"; 435 try result.ensureUnusedCapacity(name.len + 2); 436 result.appendAssumeCapacity('-'); 437 result.appendSliceAssumeCapacity(name); 438 result.appendAssumeCapacity('.'); 439 try formatVersion(v, result.writer()); 440 } else if (self.abi) |abi| { 441 const name = @tagName(abi); 442 try result.ensureUnusedCapacity(name.len + 1); 443 result.appendAssumeCapacity('-'); 444 result.appendSliceAssumeCapacity(name); 445 } 446 447 return result.toOwnedSlice(); 448 } 449 450 /// Renders the query into a textual representation that can be parsed via the 451 /// `-mcpu` flag passed to the Zig compiler. 452 /// Appends the result to `buffer`. 453 pub fn serializeCpu(q: Query, buffer: *std.ArrayList(u8)) Allocator.Error!void { 454 try buffer.ensureUnusedCapacity(8); 455 switch (q.cpu_model) { 456 .native => { 457 buffer.appendSliceAssumeCapacity("native"); 458 }, 459 .baseline => { 460 buffer.appendSliceAssumeCapacity("baseline"); 461 }, 462 .determined_by_cpu_arch => { 463 if (q.cpu_arch == null) { 464 buffer.appendSliceAssumeCapacity("native"); 465 } else { 466 buffer.appendSliceAssumeCapacity("baseline"); 467 } 468 }, 469 .explicit => |model| { 470 try buffer.appendSlice(model.name); 471 }, 472 } 473 474 if (q.cpu_features_add.isEmpty() and q.cpu_features_sub.isEmpty()) { 475 // The CPU name alone is sufficient. 476 return; 477 } 478 479 const cpu_arch = q.cpu_arch orelse builtin.cpu.arch; 480 const all_features = cpu_arch.allFeaturesList(); 481 482 for (all_features, 0..) |feature, i_usize| { 483 const i: Target.Cpu.Feature.Set.Index = @intCast(i_usize); 484 try buffer.ensureUnusedCapacity(feature.name.len + 1); 485 if (q.cpu_features_sub.isEnabled(i)) { 486 buffer.appendAssumeCapacity('-'); 487 buffer.appendSliceAssumeCapacity(feature.name); 488 } else if (q.cpu_features_add.isEnabled(i)) { 489 buffer.appendAssumeCapacity('+'); 490 buffer.appendSliceAssumeCapacity(feature.name); 491 } 492 } 493 } 494 495 pub fn serializeCpuAlloc(q: Query, ally: Allocator) Allocator.Error![]u8 { 496 var buffer = std.ArrayList(u8).init(ally); 497 try serializeCpu(q, &buffer); 498 return buffer.toOwnedSlice(); 499 } 500 501 pub fn allocDescription(self: Query, allocator: Allocator) ![]u8 { 502 // TODO is there anything else worthy of the description that is not 503 // already captured in the triple? 504 return self.zigTriple(allocator); 505 } 506 507 pub fn setGnuLibCVersion(self: *Query, major: u32, minor: u32, patch: u32) void { 508 self.glibc_version = SemanticVersion{ .major = major, .minor = minor, .patch = patch }; 509 } 510 511 fn parseOs(result: *Query, diags: *ParseOptions.Diagnostics, text: []const u8) !void { 512 var it = mem.splitScalar(u8, text, '.'); 513 const os_name = it.first(); 514 diags.os_name = os_name; 515 const os_is_native = mem.eql(u8, os_name, "native"); 516 if (!os_is_native) { 517 result.os_tag = std.meta.stringToEnum(Target.Os.Tag, os_name) orelse 518 return error.UnknownOperatingSystem; 519 } 520 const tag = result.os_tag orelse builtin.os.tag; 521 diags.os_tag = tag; 522 523 const version_text = it.rest(); 524 if (version_text.len > 0) switch (tag.getVersionRangeTag()) { 525 .none => return error.InvalidOperatingSystemVersion, 526 .semver, .linux => range: { 527 var range_it = mem.splitSequence(u8, version_text, "..."); 528 result.os_version_min = .{ 529 .semver = parseVersion(range_it.first()) catch |err| switch (err) { 530 error.Overflow => return error.InvalidOperatingSystemVersion, 531 error.InvalidVersion => return error.InvalidOperatingSystemVersion, 532 }, 533 }; 534 result.os_version_max = .{ 535 .semver = parseVersion(range_it.next() orelse break :range) catch |err| switch (err) { 536 error.Overflow => return error.InvalidOperatingSystemVersion, 537 error.InvalidVersion => return error.InvalidOperatingSystemVersion, 538 }, 539 }; 540 }, 541 .windows => range: { 542 var range_it = mem.splitSequence(u8, version_text, "..."); 543 result.os_version_min = .{ 544 .windows = try Target.Os.WindowsVersion.parse(range_it.first()), 545 }; 546 result.os_version_max = .{ 547 .windows = try Target.Os.WindowsVersion.parse(range_it.next() orelse break :range), 548 }; 549 }, 550 }; 551 } 552 553 pub fn eql(a: Query, b: Query) bool { 554 if (a.cpu_arch != b.cpu_arch) return false; 555 if (!a.cpu_model.eql(b.cpu_model)) return false; 556 if (!a.cpu_features_add.eql(b.cpu_features_add)) return false; 557 if (!a.cpu_features_sub.eql(b.cpu_features_sub)) return false; 558 if (a.os_tag != b.os_tag) return false; 559 if (!OsVersion.eqlOpt(a.os_version_min, b.os_version_min)) return false; 560 if (!OsVersion.eqlOpt(a.os_version_max, b.os_version_max)) return false; 561 if (!versionEqualOpt(a.glibc_version, b.glibc_version)) return false; 562 if (a.abi != b.abi) return false; 563 if (!a.dynamic_linker.eql(b.dynamic_linker)) return false; 564 if (a.ofmt != b.ofmt) return false; 565 566 return true; 567 } 568 569 fn versionEqualOpt(a: ?SemanticVersion, b: ?SemanticVersion) bool { 570 if (a == null and b == null) return true; 571 if (a == null or b == null) return false; 572 return SemanticVersion.order(a.?, b.?) == .eq; 573 } 574 575 const Query = @This(); 576 const std = @import("../std.zig"); 577 const builtin = @import("builtin"); 578 const assert = std.debug.assert; 579 const Target = std.Target; 580 const mem = std.mem; 581 const Allocator = std.mem.Allocator; 582 583 test parse { 584 if (builtin.target.isGnuLibC()) { 585 var query = try Query.parse(.{}); 586 query.setGnuLibCVersion(2, 1, 1); 587 588 const text = try query.zigTriple(std.testing.allocator); 589 defer std.testing.allocator.free(text); 590 591 try std.testing.expectEqualSlices(u8, "native-native-gnu.2.1.1", text); 592 } 593 { 594 const query = try Query.parse(.{ 595 .arch_os_abi = "aarch64-linux", 596 .cpu_features = "native", 597 }); 598 599 try std.testing.expect(query.cpu_arch.? == .aarch64); 600 try std.testing.expect(query.cpu_model == .native); 601 } 602 { 603 const query = try Query.parse(.{ .arch_os_abi = "native" }); 604 605 try std.testing.expect(query.cpu_arch == null); 606 try std.testing.expect(query.isNative()); 607 608 const text = try query.zigTriple(std.testing.allocator); 609 defer std.testing.allocator.free(text); 610 try std.testing.expectEqualSlices(u8, "native", text); 611 } 612 { 613 const query = try Query.parse(.{ 614 .arch_os_abi = "x86_64-linux-gnu", 615 .cpu_features = "x86_64-sse-sse2-avx-cx8", 616 }); 617 const target = try std.zig.system.resolveTargetQuery(query); 618 619 try std.testing.expect(target.os.tag == .linux); 620 try std.testing.expect(target.abi == .gnu); 621 try std.testing.expect(target.cpu.arch == .x86_64); 622 try std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .sse)); 623 try std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .avx)); 624 try std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .cx8)); 625 try std.testing.expect(Target.x86.featureSetHas(target.cpu.features, .cmov)); 626 try std.testing.expect(Target.x86.featureSetHas(target.cpu.features, .fxsr)); 627 628 try std.testing.expect(Target.x86.featureSetHasAny(target.cpu.features, .{ .sse, .avx, .cmov })); 629 try std.testing.expect(!Target.x86.featureSetHasAny(target.cpu.features, .{ .sse, .avx })); 630 try std.testing.expect(Target.x86.featureSetHasAll(target.cpu.features, .{ .mmx, .x87 })); 631 try std.testing.expect(!Target.x86.featureSetHasAll(target.cpu.features, .{ .mmx, .x87, .sse })); 632 633 const text = try query.zigTriple(std.testing.allocator); 634 defer std.testing.allocator.free(text); 635 try std.testing.expectEqualSlices(u8, "x86_64-linux-gnu", text); 636 } 637 { 638 const query = try Query.parse(.{ 639 .arch_os_abi = "arm-linux-musleabihf", 640 .cpu_features = "generic+v8a", 641 }); 642 const target = try std.zig.system.resolveTargetQuery(query); 643 644 try std.testing.expect(target.os.tag == .linux); 645 try std.testing.expect(target.abi == .musleabihf); 646 try std.testing.expect(target.cpu.arch == .arm); 647 try std.testing.expect(target.cpu.model == &Target.arm.cpu.generic); 648 try std.testing.expect(Target.arm.featureSetHas(target.cpu.features, .v8a)); 649 650 const text = try query.zigTriple(std.testing.allocator); 651 defer std.testing.allocator.free(text); 652 try std.testing.expectEqualSlices(u8, "arm-linux-musleabihf", text); 653 } 654 { 655 const query = try Query.parse(.{ 656 .arch_os_abi = "aarch64-linux.3.10...4.4.1-gnu.2.27", 657 .cpu_features = "generic+v8a", 658 }); 659 const target = try std.zig.system.resolveTargetQuery(query); 660 661 try std.testing.expect(target.cpu.arch == .aarch64); 662 try std.testing.expect(target.os.tag == .linux); 663 try std.testing.expect(target.os.version_range.linux.range.min.major == 3); 664 try std.testing.expect(target.os.version_range.linux.range.min.minor == 10); 665 try std.testing.expect(target.os.version_range.linux.range.min.patch == 0); 666 try std.testing.expect(target.os.version_range.linux.range.max.major == 4); 667 try std.testing.expect(target.os.version_range.linux.range.max.minor == 4); 668 try std.testing.expect(target.os.version_range.linux.range.max.patch == 1); 669 try std.testing.expect(target.os.version_range.linux.glibc.major == 2); 670 try std.testing.expect(target.os.version_range.linux.glibc.minor == 27); 671 try std.testing.expect(target.os.version_range.linux.glibc.patch == 0); 672 try std.testing.expect(target.abi == .gnu); 673 674 const text = try query.zigTriple(std.testing.allocator); 675 defer std.testing.allocator.free(text); 676 try std.testing.expectEqualSlices(u8, "aarch64-linux.3.10...4.4.1-gnu.2.27", text); 677 } 678 }