authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-09-17 22:28:42+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-09-17 22:28:42+02:00
log955228b682dc48a3815707f318280af12a3daf00
tree10899c853010cf4117778eb6d75ae287f5d77528
parent6b3b6ec32c5c45095c77f4af99ec21f7d75b82ef
parentb61678c1b631f78c3a5da4eca2e77ae3577c1093

Merge pull request '`std.Target.Query`: rework native ABI detection a bit' (#36867) from alexrp/zig:abi-detect into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/36867 Reviewed-by: Andrew Kelley <andrew@ziglang.org>

5 files changed, 143 insertions(+), 180 deletions(-)

lib/std/Target.zig+9-16
......@@ -499,7 +499,10 @@ pub const Os = struct {
499499
500500 break :blk default_min;
501501 },
502 .android = 29,
502 .android = switch (arch) {
503 .riscv64 => 35,
504 else => 29,
505 },
503506 },
504507 },
505508 .rtems => .{
......@@ -2532,8 +2535,8 @@ pub const DynamicLinker = struct {
25322535 /// the ABI; it does not necessarily mean that `abi` makes any sense at all for that platform.
25332536 /// The responsibility for determining whether `abi` is valid in this case rests with the
25342537 /// caller. `Abi.default()` can be used to pick a best-effort default ABI for such platforms.
2535 pub fn standard(cpu: Cpu, os: Os, abi: Abi) DynamicLinker {
2536 return switch (os.tag) {
2538 pub fn standard(cpu: Cpu, os: Os.Tag, abi: Abi) DynamicLinker {
2539 return switch (os) {
25372540 .fuchsia => switch (cpu.arch) {
25382541 .arm,
25392542 .aarch64,
......@@ -2833,12 +2836,7 @@ pub const DynamicLinker = struct {
28332836 else => none,
28342837 },
28352838
2836 .dragonfly => if (cpu.arch == .x86_64) initFmt("{s}/libexec/ld-elf.so.2", .{
2837 if (os.version_range.semver.isAtLeast(.{ .major = 3, .minor = 8, .patch = 0 }) orelse false)
2838 ""
2839 else
2840 "/usr",
2841 }) else none,
2839 .dragonfly => if (cpu.arch == .x86_64) init("/libexec/ld-elf.so.2") else none,
28422840
28432841 .freebsd => switch (cpu.arch) {
28442842 .arm,
......@@ -2849,12 +2847,7 @@ pub const DynamicLinker = struct {
28492847 .riscv64,
28502848 .x86,
28512849 .x86_64,
2852 => initFmt("{s}/libexec/ld-elf.so.1", .{
2853 if (os.version_range.semver.isAtLeast(.{ .major = 6, .minor = 0, .patch = 0 }) orelse false)
2854 ""
2855 else
2856 "/usr",
2857 }),
2850 => init("/libexec/ld-elf.so.1"),
28582851 else => none,
28592852 },
28602853
......@@ -2968,7 +2961,7 @@ pub const DynamicLinker = struct {
29682961};
29692962
29702963pub fn standardDynamicLinkerPath(target: *const Target) DynamicLinker {
2971 return DynamicLinker.standard(target.cpu, target.os, target.abi);
2964 return DynamicLinker.standard(target.cpu, target.os.tag, target.abi);
29722965}
29732966
29742967pub fn ptrBitWidth_cpu_abi(cpu: Cpu, abi: Abi) u16 {
lib/std/Target/Query.zig+36-43
......@@ -26,33 +26,37 @@ cpu_features_sub: Target.Cpu.Feature.Set = .empty,
2626/// `null` means native.
2727os_tag: ?Target.Os.Tag = null,
2828
29/// `null` means the default version range for `os_tag`. If `os_tag` is `null` (native)
30/// then `null` for this field means native.
29/// `null` means native when `os_tag` is native; otherwise, the default minimum version for
30/// `cpu_arch`, `os_tag`, and `abi`.
3131os_version_min: ?OsVersion = null,
3232
33/// When cross compiling, `null` means default (latest known OS version).
34/// When `os_tag` is native, `null` means equal to the native OS version.
33/// `null` means native when `os_tag` is native; otherwise, the latest known OS version.
3534os_version_max: ?OsVersion = null,
3635
37/// `null` means default when cross compiling, or native when `os_tag` is native.
38/// If `isGnu()` is `false`, this must be `null` and is ignored.
36/// `null` means native when `abi` is native; otherwise, the default minimum version for `cpu_arch`,
37/// `os_tag`, and `abi`.
38///
39/// Must be `null` when `abi` is `null` or `isGnu()` is `false`.
3940glibc_version: ?SemanticVersion = null,
4041
41/// `null` means default when cross compiling, or native when `os_tag` is native.
42/// If `isAndroid()` is `false`, this must be `null` and is ignored.
42/// `null` means native when `abi` is native; otherwise, the default minimum version for `cpu_arch`
43/// and `abi`.
44///
45/// Must be `null` when `abi` is `null` or `isAndroid()` is `false`.
4346android_api_level: ?u32 = null,
4447
45/// `null` means the native C ABI, if `os_tag` is native, otherwise it means the default C ABI.
48/// `null` means native if `os_tag` is native; otherwise, best-effort default for `cpu_arch` and
49/// `os_tag`.
4650abi: ?Target.Abi = null,
4751
48/// When `os_tag` is `null`, then `null` means native. Otherwise it means the standard path
49/// based on the `os_tag`. When `dynamic_linker` is a non-`null` empty string, no dynamic
50/// linker is used regardless of `os_tag`.
51dynamic_linker: ?Target.DynamicLinker = null,
52
53/// `null` means default for the cpu/arch/os combo.
52/// `null` means default for the `cpu_arch` and `os_tag` combination.
5453ofmt: ?Target.ObjectFormat = null,
5554
55/// `null` means native when `abi` is native; otherwise, the standard path based on `cpu_arch`,
56/// `os_tag`, and `abi`. A non-`null` empty string means no dynamic linker is used regardless of the
57/// values of other fields.
58dynamic_linker: ?Target.DynamicLinker = null,
59
5660pub const CpuModel = union(enum) {
5761 /// Always native
5862 native,
......@@ -175,12 +179,12 @@ pub const ParseOptions = struct {
175179 /// parsed CPU Architecture. If native, then this will be "native". Otherwise, it will be "baseline".
176180 cpu_features: ?[]const u8 = null,
177181
182 object_format: ?[]const u8 = null,
183
178184 /// Absolute path to dynamic linker, to override the default, which is either a natively
179185 /// detected path, or a standard path.
180186 dynamic_linker: ?[]const u8 = null,
181187
182 object_format: ?[]const u8 = null,
183
184188 /// If this is provided, the function will populate some information about parsing failures,
185189 /// so that user-friendly error messages can be delivered.
186190 diagnostics: ?*Diagnostics = null,
......@@ -381,12 +385,16 @@ pub fn isNativeCpu(self: Query) bool {
381385}
382386
383387pub fn isNativeOs(self: Query) bool {
384 return self.os_tag == null and self.os_version_min == null and self.os_version_max == null and
385 self.dynamic_linker == null and self.glibc_version == null and self.android_api_level == null;
388 return self.os_tag == null and
389 self.os_version_min == null and
390 self.os_version_max == null;
386391}
387392
388393pub fn isNativeAbi(self: Query) bool {
389 return self.os_tag == null and self.abi == null;
394 return self.os_tag == null and
395 self.abi == null and
396 self.glibc_version == null and
397 self.android_api_level == null;
390398}
391399
392400pub fn isNativeTriple(self: Query) bool {
......@@ -394,11 +402,13 @@ pub fn isNativeTriple(self: Query) bool {
394402}
395403
396404pub fn isNative(self: Query) bool {
397 return self.isNativeTriple() and self.ofmt == null;
405 return self.isNativeTriple() and
406 self.ofmt == null and
407 self.dynamic_linker == null;
398408}
399409
400410pub fn canDetectLibC(self: Query) bool {
401 if (self.isNativeOs()) return true;
411 if (self.isNativeOs() and self.isNativeAbi()) return true;
402412 if (self.os_tag) |os| {
403413 if (builtin.os.tag == .macos and os.isDarwin()) return true;
404414 if (os == .linux) {
......@@ -459,14 +469,14 @@ pub fn zigTriple(self: Query, gpa: Allocator) Allocator.Error![]u8 {
459469 }
460470
461471 if (self.glibc_version) |v| {
462 const name = if (self.abi) |abi| @tagName(abi) else "gnu";
472 const name = @tagName(self.abi.?);
463473 try result.ensureUnusedCapacity(gpa, name.len + 2);
464474 result.appendAssumeCapacity('-');
465475 result.appendSliceAssumeCapacity(name);
466476 result.appendAssumeCapacity('.');
467477 try formatVersion(v, gpa, &result);
468478 } else if (self.android_api_level) |lvl| {
469 const name = if (self.abi) |abi| @tagName(abi) else "android";
479 const name = @tagName(self.abi.?);
470480 try result.ensureUnusedCapacity(gpa, name.len + 2);
471481 result.appendAssumeCapacity('-');
472482 result.appendSliceAssumeCapacity(name);
......@@ -538,6 +548,7 @@ pub fn allocDescription(self: Query, allocator: Allocator) ![]u8 {
538548 return self.zigTriple(allocator);
539549}
540550
551/// Deprecated; set `glibc_version` directly. Will be removed in 0.18.0.
541552pub fn setGnuLibCVersion(self: *Query, major: u32, minor: u32, patch: u32) void {
542553 self.glibc_version = SemanticVersion{ .major = major, .minor = minor, .patch = patch };
543554}
......@@ -599,8 +610,8 @@ pub fn eql(a: Query, b: Query) bool {
599610 if (!versionEqualOpt(a.glibc_version, b.glibc_version)) return false;
600611 if (a.android_api_level != b.android_api_level) return false;
601612 if (a.abi != b.abi) return false;
602 if (!dynamicLinkerEqualOpt(a.dynamic_linker, b.dynamic_linker)) return false;
603613 if (a.ofmt != b.ofmt) return false;
614 if (!dynamicLinkerEqualOpt(a.dynamic_linker, b.dynamic_linker)) return false;
604615
605616 return true;
606617}
......@@ -620,24 +631,6 @@ fn dynamicLinkerEqualOpt(a: ?Target.DynamicLinker, b: ?Target.DynamicLinker) boo
620631test parse {
621632 const io = std.testing.io;
622633
623 if (builtin.target.isGnuLibC()) {
624 var query = try Query.parse(.{});
625 query.setGnuLibCVersion(2, 1, 1);
626
627 const text = try query.zigTriple(std.testing.allocator);
628 defer std.testing.allocator.free(text);
629
630 try std.testing.expectEqualSlices(u8, "native-native-gnu.2.1.1", text);
631 }
632 if (builtin.target.abi.isAndroid()) {
633 var query = try Query.parse(.{});
634 query.android_api_level = 30;
635
636 const text = try query.zigTriple(std.testing.allocator);
637 defer std.testing.allocator.free(text);
638
639 try std.testing.expectEqualSlices(u8, "native-native-android.30", text);
640 }
641634 {
642635 const query = try Query.parse(.{
643636 .arch_os_abi = "aarch64-linux",
lib/std/zig/system.zig+92-107
......@@ -374,16 +374,14 @@ pub fn resolveTargetQuery(io: Io, query: Target.Query) DetectError!Target {
374374 }
375375
376376 var cpu = switch (query.cpu_model) {
377 .native => detectNativeCpuAndFeatures(io, query_cpu_arch, os, query),
378 .baseline => Target.Cpu.baseline(query_cpu_arch, os),
377 .native => detectNativeCpuAndFeatures(io, query_cpu_arch),
378 .baseline => null,
379379 .determined_by_arch_os => if (query.cpu_arch == null)
380 detectNativeCpuAndFeatures(io, query_cpu_arch, os, query)
380 detectNativeCpuAndFeatures(io, query_cpu_arch)
381381 else
382 Target.Cpu.baseline(query_cpu_arch, os),
382 null,
383383 .explicit => |model| model.toCpu(query_cpu_arch),
384 } orelse backup_cpu_detection: {
385 break :backup_cpu_detection Target.Cpu.baseline(query_cpu_arch, os);
386 };
384 } orelse Target.Cpu.baseline(query_cpu_arch, os);
387385
388386 // For x86, we need to populate some CPU feature flags depending on architecture
389387 // and mode:
......@@ -421,6 +419,7 @@ pub fn resolveTargetQuery(io: Io, query: Target.Query) DetectError!Target {
421419 var result = detectAbiAndDynamicLinker(io, cpu, os, query) catch |err| switch (err) {
422420 error.Canceled => |e| return e,
423421 error.Unexpected => |e| return e,
422 error.ApiLevelQueryFailed => |e| return e,
424423 error.WouldBlock => return error.Unexpected,
425424 error.ConnectionResetByPeer => return error.Unexpected,
426425 error.NotOpenForReading => return error.Unexpected,
......@@ -499,27 +498,6 @@ pub fn resolveTargetQuery(io: Io, query: Target.Query) DetectError!Target {
499498 }
500499 }
501500
502 if (builtin.os.tag == .linux and result.isBionicLibC() and query.os_tag == null and query.android_api_level == null) {
503 result.os.version_range.linux.android = detectAndroidApiLevel(io) catch |err| return switch (err) {
504 error.InvalidWtf8,
505 error.InvalidBatchScriptArg,
506 => unreachable, // Windows-only
507 error.ApiLevelQueryFailed => |e| e,
508 else => blk: {
509 std.log.err("spawning or reading from getprop failed ({s})", .{@errorName(err)});
510 switch (err) {
511 error.SystemResources,
512 error.FileSystem,
513 error.ProcessFdQuotaExceeded,
514 error.SystemFdQuotaExceeded,
515 error.SymLinkLoop,
516 => |e| break :blk e,
517 else => break :blk error.ApiLevelQueryFailed,
518 }
519 },
520 };
521 }
522
523501 return result;
524502}
525503
......@@ -535,13 +513,12 @@ fn updateCpuFeatures(
535513 set.removeFeatureSet(sub_set);
536514}
537515
538fn detectNativeCpuAndFeatures(io: Io, cpu_arch: Target.Cpu.Arch, os: Target.Os, query: Target.Query) ?Target.Cpu {
539 // Here we switch on a comptime value rather than `cpu_arch`. This is valid because `cpu_arch`,
540 // although it is a runtime value, is guaranteed to be one of the architectures in the set
541 // of the respective switch prong.
542 switch (builtin.cpu.arch) {
543 .loongarch32, .loongarch64 => return @import("system/loongarch.zig").detectNativeCpuAndFeatures(cpu_arch, os, query),
544 .x86_64, .x86 => return @import("system/x86.zig").detectNativeCpuAndFeatures(cpu_arch, os, query),
516fn detectNativeCpuAndFeatures(io: Io, cpu_arch: Target.Cpu.Arch) ?Target.Cpu {
517 const family = builtin.target.cpu.arch.family();
518 assert(cpu_arch.family() == family);
519 switch (family) {
520 .loongarch => return @import("system/loongarch.zig").detectNativeCpuAndFeatures(cpu_arch),
521 .x86 => return @import("system/x86.zig").detectNativeCpuAndFeatures(cpu_arch),
545522 else => {},
546523 }
547524
......@@ -594,11 +571,13 @@ fn abiAndDynamicLinkerFromFile(
594571 ld_info_list: []const LdInfo,
595572 query: Target.Query,
596573) AbiAndDynamicLinkerFromFileError!Target {
574 assert(query.abi == null); // See the early exit in `detectAbiAndDynamicLinker`.
575
597576 const io = file_reader.io;
598577 var result: Target = .{
599578 .cpu = cpu,
600579 .os = os,
601 .abi = query.abi orelse Target.Abi.default(cpu.arch, os.tag),
580 .abi = Target.Abi.default(cpu.arch, os.tag),
602581 .ofmt = query.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch),
603582 .dynamic_linker = query.dynamic_linker orelse .none,
604583 };
......@@ -612,26 +591,25 @@ fn abiAndDynamicLinkerFromFile(
612591 .INTERP => {
613592 got_dyn_section = true;
614593
615 if (look_for_ld) {
616 const p_filesz = phdr.filesz;
617 if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong;
618 const filesz: usize = @intCast(p_filesz);
619 try file_reader.seekTo(phdr.offset);
620 try file_reader.interface.readSliceAll(result.dynamic_linker.buffer[0..filesz]);
621 // PT.INTERP includes a null byte in filesz.
622 const len = filesz - 1;
623 // dynamic_linker.max_byte is "max", not "len".
624 // We know it will fit in u8 because we check against dynamic_linker.buffer.len above.
625 result.dynamic_linker.len = @intCast(len);
626
627 // Use it to determine ABI.
628 const full_ld_path = result.dynamic_linker.buffer[0..len];
629 for (ld_info_list) |ld_info| {
630 const standard_ld_basename = fs.path.basename(ld_info.ld.get().?);
631 if (std.mem.endsWith(u8, full_ld_path, standard_ld_basename)) {
632 result.abi = ld_info.abi;
633 break;
634 }
594 var interp: Target.DynamicLinker = .none;
595 const p_filesz = phdr.filesz;
596 if (p_filesz < 2) return error.InvalidElfFile;
597 if (p_filesz > interp.buffer.len) return error.NameTooLong;
598 const filesz: usize = @intCast(p_filesz);
599 try file_reader.seekTo(phdr.offset);
600 try file_reader.interface.readSliceAll(interp.buffer[0..filesz]);
601 // PT.INTERP includes a null byte in filesz.
602 const len = filesz - 1;
603 // dynamic_linker.max_byte is "max", not "len".
604 // We know it will fit in u8 because we check against dynamic_linker.buffer.len above.
605 interp.len = @intCast(len);
606
607 // Use it to determine ABI.
608 for (ld_info_list) |ld_info| {
609 if (std.mem.endsWith(u8, interp.get().?, fs.path.basename(ld_info.ld.get().?))) {
610 result.abi = ld_info.abi;
611 if (look_for_ld) result.dynamic_linker = interp;
612 break;
635613 }
636614 }
637615 },
......@@ -653,6 +631,10 @@ fn abiAndDynamicLinkerFromFile(
653631 };
654632 }
655633
634 if (look_for_ld and result.dynamic_linker.get() == null) {
635 result.dynamic_linker = .standard(cpu, os.tag, result.abi);
636 }
637
656638 if (!got_dyn_section) {
657639 return error.StaticElfFile;
658640 }
......@@ -954,17 +936,14 @@ fn glibcVerFromSoFile(file_reader: *Io.File.Reader) !std.SemanticVersion {
954936/// file recursively. If that does not provide the answer, then the function falls back to
955937/// defaults.
956938fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Target.Query) !Target {
957 const native_target_has_ld = comptime Target.DynamicLinker.kind(builtin.os.tag) != .none;
958 const is_linux = builtin.target.os.tag == .linux;
959 const is_illumos = builtin.target.os.tag == .illumos;
960 const is_darwin = builtin.target.os.tag.isDarwin();
961 const have_all_info = query.dynamic_linker != null and
962 query.abi != null and (!is_linux or query.abi.?.isGnu());
963 const os_is_non_native = query.os_tag != null;
964 // The illumos environment is always the same.
965 if (!native_target_has_ld or have_all_info or os_is_non_native or is_illumos or is_darwin) {
939 const native_os_uses_elf = comptime Target.ObjectFormat.default(builtin.target.os.tag, builtin.target.cpu.arch) == .elf;
940 const native_ld_needs_abi = comptime Target.DynamicLinker.kind(builtin.target.os.tag) == .arch_os_abi;
941 if (!native_os_uses_elf or !native_ld_needs_abi or query.os_tag != null or query.abi != null) {
966942 return defaultAbiAndDynamicLinker(cpu, os, query);
967943 }
944
945 assert(os.tag == builtin.target.os.tag);
946
968947 // The current target's ABI cannot be relied on for this. For example, we may build the zig
969948 // compiler for target riscv64-linux-musl and provide a tarball for users to download.
970949 // A user could then run that zig compiler on riscv64-linux-gnu. This use case is well-defined
......@@ -982,30 +961,17 @@ fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Targ
982961 var ld_info_list_buffer: [all_abis.len]LdInfo = undefined;
983962 var ld_info_list_len: usize = 0;
984963
985 switch (Target.DynamicLinker.kind(os.tag)) {
986 // The OS has no dynamic linker. Leave the list empty and rely on `Abi.default()` to pick
987 // something sensible in `abiAndDynamicLinkerFromFile()`.
988 .none => {},
989 // The OS has a system-wide dynamic linker. Unfortunately, this implies that there's no
990 // useful ABI information that we can glean from it merely being present. That means the
991 // best we can do for this case (for now) is also `Abi.default()`.
992 .arch_os => {},
993 // The OS can have different dynamic linker paths depending on libc/ABI. In this case, we
994 // need to gather all the valid arch/OS/ABI combinations. `abiAndDynamicLinkerFromFile()`
995 // will then look for a dynamic linker with a matching path on the system and pick the ABI
996 // we associated it with here.
997 .arch_os_abi => for (all_abis) |abi| {
998 const ld = Target.DynamicLinker.standard(cpu, os, abi);
999
1000 // Does the generated target triple actually have a standard dynamic linker path?
1001 if (ld.get() == null) continue;
1002
1003 ld_info_list_buffer[ld_info_list_len] = .{
1004 .ld = ld,
1005 .abi = abi,
1006 };
1007 ld_info_list_len += 1;
1008 },
964 for (all_abis) |abi| {
965 const ld: Target.DynamicLinker = .standard(cpu, os.tag, abi);
966
967 // Does the generated target triple actually have a standard dynamic linker path?
968 if (ld.get() == null) continue;
969
970 ld_info_list_buffer[ld_info_list_len] = .{
971 .ld = ld,
972 .abi = abi,
973 };
974 ld_info_list_len += 1;
1009975 }
1010976
1011977 const ld_info_list = ld_info_list_buffer[0..ld_info_list_len];
......@@ -1034,13 +1000,9 @@ fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Targ
10341000 // it uses the file it references instead, doing the same logic
10351001 // recursively in case it finds another shebang line.
10361002
1037 var file_name: []const u8 = switch (os.tag) {
1038 // Since /usr/bin/env is hard-coded into the shebang line of many
1039 // portable scripts, it's a reasonably reliable path to start with.
1040 else => "/usr/bin/env",
1041 // Haiku does not have a /usr root directory.
1042 .haiku => "/bin/env",
1043 };
1003 // Since /usr/bin/env is hard-coded into the shebang line of many
1004 // portable scripts, it's a reasonably reliable path to start with.
1005 var file_name: []const u8 = "/usr/bin/env";
10441006
10451007 while (true) {
10461008 const file = Io.Dir.openFileAbsolute(io, file_name, .{}) catch |err| switch (err) {
......@@ -1062,7 +1024,7 @@ fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Targ
10621024 error.NetworkNotFound,
10631025 error.FileTooBig,
10641026 error.Unexpected,
1065 => |e| if (e == error.FileNotFound and os.tag == .linux and mem.eql(u8, file_name, "/usr/bin/env")) {
1027 => |e| if (builtin.target.os.tag == .linux and e == error.FileNotFound and mem.eql(u8, file_name, "/usr/bin/env")) {
10661028 // Android does not have a /usr directory, so try again
10671029 file_name = "/system/bin/env";
10681030 continue;
......@@ -1116,7 +1078,7 @@ fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Targ
11161078 };
11171079 defer file_reader.file.close(io);
11181080
1119 return abiAndDynamicLinkerFromFile(&file_reader, &header, cpu, os, ld_info_list, query) catch |err| switch (err) {
1081 var result = abiAndDynamicLinkerFromFile(&file_reader, &header, cpu, os, ld_info_list, query) catch |err| switch (err) {
11201082 error.FileSystem,
11211083 error.SystemResources,
11221084 error.SymLinkLoop,
......@@ -1132,6 +1094,29 @@ fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Targ
11321094 return defaultAbiAndDynamicLinker(cpu, os, query);
11331095 },
11341096 };
1097
1098 if (builtin.target.os.tag == .linux and result.isBionicLibC() and query.android_api_level == null) {
1099 result.os.version_range.linux.android = detectAndroidApiLevel(io) catch |err| return switch (err) {
1100 error.InvalidWtf8,
1101 error.InvalidBatchScriptArg,
1102 => unreachable, // Windows-only
1103 error.ApiLevelQueryFailed => |e| e,
1104 else => blk: {
1105 std.log.err("spawning or reading from getprop failed ({s})", .{@errorName(err)});
1106 switch (err) {
1107 error.SystemResources,
1108 error.FileSystem,
1109 error.ProcessFdQuotaExceeded,
1110 error.SystemFdQuotaExceeded,
1111 error.SymLinkLoop,
1112 => |e| break :blk e,
1113 else => break :blk error.ApiLevelQueryFailed,
1114 }
1115 },
1116 };
1117 }
1118
1119 return result;
11351120}
11361121
11371122fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os, query: Target.Query) Target {
......@@ -1141,7 +1126,7 @@ fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os, query: Target.Quer
11411126 .os = os,
11421127 .abi = abi,
11431128 .ofmt = query.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch),
1144 .dynamic_linker = query.dynamic_linker orelse .standard(cpu, os, abi),
1129 .dynamic_linker = query.dynamic_linker orelse .standard(cpu, os.tag, abi),
11451130 };
11461131}
11471132
......@@ -1169,13 +1154,6 @@ fn detectAndroidApiLevel(io: Io) !u32 {
11691154 var stdout_buf: [92 + 1]u8 = undefined;
11701155 var reader = child.stdout.?.readerStreaming(io, &.{});
11711156 const n = try reader.interface.readSliceShort(&stdout_buf);
1172 const api_level = std.fmt.parseInt(u32, stdout_buf[0 .. n - 1], 10) catch |e| {
1173 std.log.err(
1174 "Could not parse API level, unexpected getprop output '{s}' ({s})",
1175 .{ stdout_buf[0 .. n - 1], @errorName(e) },
1176 );
1177 return error.ApiLevelQueryFailed;
1178 };
11791157
11801158 switch (try child.wait(io)) {
11811159 .exited => |code| if (code != 0) {
......@@ -1196,7 +1174,14 @@ fn detectAndroidApiLevel(io: Io) !u32 {
11961174 },
11971175 }
11981176
1199 return api_level;
1177 const result = mem.trimEnd(u8, stdout_buf[0..n], "\n");
1178 return std.fmt.parseInt(u32, result, 10) catch |e| {
1179 std.log.err(
1180 "Could not parse API level, unexpected getprop output '{s}' ({s})",
1181 .{ result, @errorName(e) },
1182 );
1183 return error.ApiLevelQueryFailed;
1184 };
12001185}
12011186
12021187test {
lib/std/zig/system/loongarch.zig+1-8
......@@ -18,14 +18,7 @@ fn setFeature(cpu: *std.Target.Cpu, feature: std.Target.loongarch.Feature, enabl
1818 if (enabled) cpu.features.addFeature(idx) else cpu.features.removeFeature(idx);
1919}
2020
21pub fn detectNativeCpuAndFeatures(
22 arch: std.Target.Cpu.Arch,
23 os: std.Target.Os,
24 query: std.Target.Query,
25) ?std.Target.Cpu {
26 _ = os;
27 _ = query;
28
21pub fn detectNativeCpuAndFeatures(arch: std.Target.Cpu.Arch) ?std.Target.Cpu {
2922 const variant: Variant = @fromBackingInt(@intCast(cpucfg(1) & 0b11));
3023
3124 var cpu: std.Target.Cpu = .{
lib/std/zig/system/x86.zig+5-6
......@@ -41,8 +41,7 @@ inline fn hasMask(input: u32, mask: u32) bool {
4141 return (input & mask) == mask;
4242}
4343
44pub fn detectNativeCpuAndFeatures(arch: Target.Cpu.Arch, os: Target.Os, query: Target.Query) Target.Cpu {
45 _ = query;
44pub fn detectNativeCpuAndFeatures(arch: Target.Cpu.Arch) Target.Cpu {
4645 var cpu = Target.Cpu{
4746 .arch = arch,
4847 .model = Target.Cpu.Model.generic(arch),
......@@ -50,7 +49,7 @@ pub fn detectNativeCpuAndFeatures(arch: Target.Cpu.Arch, os: Target.Os, query: T
5049 };
5150
5251 // First we detect features, to use as hints when detecting CPU Model.
53 detectNativeFeatures(&cpu, os.tag);
52 detectNativeFeatures(&cpu);
5453
5554 var leaf = cpuid(0, 0);
5655 const max_leaf = leaf.eax;
......@@ -90,7 +89,7 @@ pub fn detectNativeCpuAndFeatures(arch: Target.Cpu.Arch, os: Target.Os, query: T
9089 // Add the CPU model's feature set into the working set, but then
9190 // override with actual detected features again.
9291 cpu.features.addFeatureSet(cpu.model.features);
93 detectNativeFeatures(&cpu, os.tag);
92 detectNativeFeatures(&cpu);
9493
9594 cpu.features.populateDependencies(cpu.arch.allFeaturesList());
9695
......@@ -215,7 +214,7 @@ fn detectAmdProcessor(cpu: *const Target.Cpu, family: u32, model: u32) ?*const T
215214 };
216215}
217216
218fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void {
217fn detectNativeFeatures(cpu: *Target.Cpu) void {
219218 var leaf = cpuid(0, 0);
220219
221220 const max_level = leaf.eax;
......@@ -268,7 +267,7 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void {
268267 // Darwin lazily saves the AVX512 context on first use: trust that the OS will
269268 // save the AVX512 context if we use AVX512 instructions, even if the bit is not
270269 // set right now.
271 const has_avx512_save = if (os_tag.isDarwin())
270 const has_avx512_save = if (builtin.target.os.tag.isDarwin())
272271 true
273272 else
274273 xcr0.zmm_hi256 and xcr0.hi16_zmm;