commit e27b4647d86e3bdaf2c4fd95db2e7d359afd7fc4 (tree)
parent 8abbdb56a4fce176cb8ec24e5d4724ac16196a0b
Author: Alex Rønne Petersen <alex@alexrp.com>
Date: Sat, 2 Nov 2024 10:29:41 +0100
Merge pull request #21617 from alexrp/target-dyld-stuff
Improve the `DynamicLinker` API and fix `detectAbiAndDynamicLinker()` for non-Linux/Hurd ELF hosts
Diffstat:
3 files changed, 357 insertions(+), 217 deletions(-)
diff --git a/lib/std/Target.zig b/lib/std/Target.zig
@@ -2059,30 +2059,6 @@ pub inline fn floatAbi(target: Target) FloatAbi {
return target.abi.floatAbi();
}
-pub inline fn hasDynamicLinker(target: Target) bool {
- if (target.cpu.arch.isWasm()) {
- return false;
- }
- switch (target.os.tag) {
- .freestanding,
- .ios,
- .tvos,
- .watchos,
- .macos,
- .visionos,
- .uefi,
- .windows,
- .emscripten,
- .opencl,
- .opengl,
- .vulkan,
- .plan9,
- .other,
- => return false,
- else => return true,
- }
-}
-
pub const DynamicLinker = struct {
/// Contains the memory used to store the dynamic linker path. This field
/// should not be used directly. See `get` and `set`. This field exists so
@@ -2129,209 +2105,306 @@ pub const DynamicLinker = struct {
return std.mem.eql(u8, lhs.buffer[0..lhs.len], rhs.buffer[0..rhs.len]);
}
+ pub const Kind = enum {
+ /// No dynamic linker.
+ none,
+ /// Dynamic linker path is determined by the arch/OS components.
+ arch_os,
+ /// Dynamic linker path is determined by the arch/OS/ABI components.
+ arch_os_abi,
+ };
+
+ pub fn kind(os: Os.Tag) Kind {
+ return switch (os) {
+ .fuchsia,
+
+ .haiku,
+ .serenity,
+
+ .dragonfly,
+ .freebsd,
+ .netbsd,
+ .openbsd,
+
+ .bridgeos,
+ .driverkit,
+ .ios,
+ .macos,
+ .tvos,
+ .visionos,
+ .watchos,
+
+ .illumos,
+ .solaris,
+ => .arch_os,
+ .hurd,
+ .linux,
+ => .arch_os_abi,
+ .freestanding,
+ .other,
+
+ .contiki,
+ .elfiamcu,
+ .hermit,
+
+ .aix,
+ .plan9,
+ .rtems,
+ .zos,
+
+ .uefi,
+ .windows,
+
+ .emscripten,
+ .wasi,
+
+ .amdhsa,
+ .amdpal,
+ .cuda,
+ .mesa3d,
+ .nvcl,
+ .opencl,
+ .opengl,
+ .vulkan,
+
+ .ps3,
+ .ps4,
+ .ps5,
+ => .none,
+ };
+ }
+
+ /// The strictness of this function depends on the value of `kind(os.tag)`:
+ ///
+ /// * `.none`: Ignores all arguments and just returns `none`.
+ /// * `.arch_os`: Ignores `abi` and returns the dynamic linker matching `cpu` and `os`.
+ /// * `.arch_os_abi`: Returns the dynamic linker matching `cpu`, `os`, and `abi`.
+ ///
+ /// In the case of `.arch_os` in particular, callers should be aware that a valid dynamic linker
+ /// being returned only means that the `cpu` + `os` combination represents a platform that
+ /// actually exists and which has an established dynamic linker path that does not change with
+ /// the ABI; it does not necessarily mean that `abi` makes any sense at all for that platform.
+ /// The responsibility for determining whether `abi` is valid in this case rests with the
+ /// caller. `Abi.default()` can be used to pick a best-effort default ABI for such platforms.
pub fn standard(cpu: Cpu, os: Os, abi: Abi) DynamicLinker {
return switch (os.tag) {
- .fuchsia => init("ld.so.1"), // Fuchsia is unusual in that `DT_INTERP` is just a basename.
+ .fuchsia => switch (cpu.arch) {
+ .aarch64,
+ .riscv64,
+ .x86_64,
+ => init("ld.so.1"), // Fuchsia is unusual in that `DT_INTERP` is just a basename.
+ else => none,
+ },
- .haiku => init("/system/runtime_loader"),
+ .haiku => switch (cpu.arch) {
+ .arm,
+ .thumb,
+ .aarch64,
+ .m68k,
+ .powerpc,
+ .riscv64,
+ .sparc64,
+ .x86,
+ .x86_64,
+ => init("/system/runtime_loader"),
+ else => none,
+ },
.hurd => switch (cpu.arch) {
.aarch64,
.aarch64_be,
=> |arch| initFmt("/lib/ld-{s}{s}.so.1", .{
@tagName(arch),
- if (abi == .gnuilp32) "_ilp32" else "",
+ switch (abi) {
+ .gnu => "",
+ .gnuilp32 => "_ilp32",
+ else => return none,
+ },
}),
- .x86 => init("/lib/ld.so.1"),
- .x86_64 => initFmt("/lib/ld-{s}.so.1", .{if (abi == .gnux32) "x32" else "x86-64"}),
+ .x86 => if (abi == .gnu) init("/lib/ld.so.1") else none,
+ .x86_64 => initFmt("/lib/ld-{s}.so.1", .{switch (abi) {
+ .gnu => "x86-64",
+ .gnux32 => "x32",
+ else => return none,
+ }}),
- // These are unsupported by Hurd/glibc.
- .amdgcn,
- .arc,
- .arm,
- .armeb,
- .thumb,
- .thumbeb,
- .avr,
- .bpfel,
- .bpfeb,
- .csky,
- .hexagon,
- .kalimba,
- .lanai,
- .loongarch32,
- .loongarch64,
- .m68k,
- .mips,
- .mipsel,
- .mips64,
- .mips64el,
- .msp430,
- .nvptx,
- .nvptx64,
- .powerpc,
- .powerpcle,
- .powerpc64,
- .powerpc64le,
- .propeller1,
- .propeller2,
- .riscv32,
- .riscv64,
- .s390x,
- .sparc,
- .sparc64,
- .spirv,
- .spirv32,
- .spirv64,
- .spu_2,
- .ve,
- .wasm32,
- .wasm64,
- .xcore,
- .xtensa,
- => none,
+ else => none,
},
.linux => if (abi.isAndroid())
- initFmt("/system/bin/linker{s}", .{if (ptrBitWidth_cpu_abi(cpu, abi) == 64) "64" else ""})
+ switch (cpu.arch) {
+ .arm,
+ .thumb,
+ => if (abi == .androideabi) init("/system/bin/linker") else none,
+
+ .aarch64,
+ .riscv64,
+ .x86,
+ .x86_64,
+ => if (abi == .android) initFmt("/system/bin/linker{s}", .{
+ if (ptrBitWidth_cpu_abi(cpu, abi) == 64) "64" else "",
+ }) else none,
+
+ else => none,
+ }
else if (abi.isMusl())
switch (cpu.arch) {
.arm,
.armeb,
.thumb,
.thumbeb,
+ => |arch| initFmt("/lib/ld-musl-arm{s}{s}.so.1", .{
+ if (arch == .armeb or arch == .thumbeb) "eb" else "",
+ switch (abi) {
+ .musleabi => "",
+ .musleabihf => "hf",
+ else => return none,
+ },
+ }),
+
.aarch64,
.aarch64_be,
- .loongarch64,
+ .loongarch64, // TODO: `-sp` and `-sf` ABI support in LLVM 20.
.m68k,
- .powerpc,
.powerpc64,
.powerpc64le,
- .riscv32,
- .riscv64,
.s390x,
- .x86,
- .x86_64,
- => |arch| initFmt("/lib/ld-musl-{s}{s}.so.1", .{
- switch (arch) {
- .thumb => "arm",
- .thumbeb => "armeb",
- .x86 => "i386",
- .x86_64 => if (abi == .muslx32) "x32" else "x86_64",
- else => @tagName(arch),
- },
- switch (arch) {
- .arm, .armeb, .thumb, .thumbeb => if (abi.floatAbi() == .hard) "hf" else "",
- .aarch64, .aarch64_be => if (abi == .gnuilp32) "_ilp32" else "",
- .riscv32, .riscv64 => if (std.Target.riscv.featureSetHas(cpu.features, .d))
- ""
- else if (std.Target.riscv.featureSetHas(cpu.features, .f))
- "-sp"
- else
- "-sf",
- else => if (abi.floatAbi() == .soft) "-sf" else "",
- },
- }),
+ => |arch| if (abi == .musl) initFmt("/lib/ld-musl-{s}.so.1", .{@tagName(arch)}) else none,
- // The naming scheme for MIPS is a bit irregular.
.mips,
.mipsel,
+ => |arch| initFmt("/lib/ld-musl-mips{s}{s}{s}.so.1", .{
+ if (mips.featureSetHas(cpu.features, .mips32r6)) "r6" else "",
+ if (arch == .mipsel) "el" else "",
+ switch (abi) {
+ .musleabi => "-sf",
+ .musleabihf => "",
+ else => return none,
+ },
+ }),
+
.mips64,
.mips64el,
- => |arch| initFmt("/lib/ld-musl-mips{s}{s}{s}{s}.so.1", .{
- if (arch.isMIPS64()) "64" else "", // TODO: `n32` ABI support in LLVM 20.
- if (mips.featureSetHas(cpu.features, if (arch.isMIPS64()) .mips64r6 else .mips32r6)) "r6" else "",
- if (arch.endian() == .little) "el" else "",
- if (abi.floatAbi() == .soft) "-sf" else "",
+ => |arch| initFmt("/lib/ld-musl-mips{s}{s}{s}.so.1", .{
+ // TODO: `n32` ABI support in LLVM 20.
+ switch (abi) {
+ .musl => "64",
+ else => return none,
+ },
+ if (mips.featureSetHas(cpu.features, .mips64r6)) "r6" else "",
+ if (arch == .mips64el) "el" else "",
}),
- // These are unsupported by musl.
- .amdgcn,
- .arc,
- .avr,
- .csky,
- .bpfel,
- .bpfeb,
- .hexagon,
- .kalimba,
- .lanai,
- .loongarch32,
- .msp430,
- .nvptx,
- .nvptx64,
- .powerpcle,
- .propeller1,
- .propeller2,
- .sparc,
- .sparc64,
- .spirv,
- .spirv32,
- .spirv64,
- .spu_2,
- .ve,
- .wasm32,
- .wasm64,
- .xcore,
- .xtensa,
- => none,
+ .powerpc => initFmt("/lib/ld-musl-powerpc{s}.so.1", .{switch (abi) {
+ .musleabi => "-sf",
+ .musleabihf => "",
+ else => return none,
+ }}),
+
+ .riscv32,
+ .riscv64,
+ => |arch| if (abi == .musl) initFmt("/lib/ld-musl-{s}{s}.so.1", .{
+ @tagName(arch),
+ if (riscv.featureSetHas(cpu.features, .d))
+ ""
+ else if (riscv.featureSetHas(cpu.features, .f))
+ "-sp"
+ else
+ "-sf",
+ }) else none,
+
+ .x86 => if (abi == .musl) init("/lib/ld-musl-i386.so.1") else none,
+ .x86_64 => initFmt("/lib/ld-musl-{s}.so.1", .{switch (abi) {
+ .musl => "x86_64",
+ .muslx32 => "x32",
+ else => return none,
+ }}),
+
+ else => none,
}
else if (abi.isGnu())
switch (cpu.arch) {
// TODO: `eb` architecture support.
// TODO: `700` ABI support.
- .arc => init("/lib/ld-linux-arc.so.2"),
+ .arc => if (abi == .gnu) init("/lib/ld-linux-arc.so.2") else none,
// TODO: OABI support (`/lib/ld-linux.so.2`).
.arm,
.armeb,
.thumb,
.thumbeb,
- => initFmt("/lib/ld-linux{s}.so.3", .{if (abi.floatAbi() == .hard) "-armhf" else ""}),
+ => initFmt("/lib/ld-linux{s}.so.3", .{switch (abi) {
+ .gnueabi => "",
+ .gnueabihf => "-armhf",
+ else => return none,
+ }}),
.aarch64,
.aarch64_be,
=> |arch| initFmt("/lib/ld-linux-{s}{s}.so.1", .{
@tagName(arch),
- if (abi == .gnuilp32) "_ilp32" else "",
+ switch (abi) {
+ .gnu => "",
+ .gnuilp32 => "_ilp32",
+ else => return none,
+ },
}),
// TODO: `-be` architecture support.
- .csky => initFmt("/lib/ld-linux-cskyv2{s}.so.1", .{if (abi.floatAbi() == .hard) "-hf" else ""}),
+ .csky => initFmt("/lib/ld-linux-cskyv2{s}.so.1", .{switch (abi) {
+ .gnueabi => "",
+ .gnueabihf => "-hf",
+ else => return none,
+ }}),
.loongarch64 => initFmt("/lib64/ld-linux-loongarch-{s}.so.1", .{switch (abi) {
+ .gnu => "lp64d",
.gnuf32 => "lp64f",
.gnusf => "lp64s",
- else => "lp64d",
+ else => return none,
}}),
- .m68k => init("/lib/ld.so.1"),
+ .m68k => if (abi == .gnu) init("/lib/ld.so.1") else none,
.mips,
.mipsel,
+ => switch (abi) {
+ .gnueabi,
+ .gnueabihf,
+ => initFmt("/lib/ld{s}.so.1", .{
+ if (mips.featureSetHas(cpu.features, .nan2008)) "-linux-mipsn8" else "",
+ }),
+ else => none,
+ },
+
.mips64,
.mips64el,
=> initFmt("/lib{s}/ld{s}.so.1", .{
switch (abi) {
- .gnuabin32 => "32",
.gnuabi64 => "64",
- else => "",
+ .gnuabin32 => "32",
+ else => return none,
},
if (mips.featureSetHas(cpu.features, .nan2008)) "-linux-mipsn8" else "",
}),
- .powerpc => init("/lib/ld.so.1"),
- // TODO: ELFv2 ABI opt-in support.
- .powerpc64 => init("/lib64/ld64.so.1"),
- .powerpc64le => init("/lib64/ld64.so.2"),
+ .powerpc => switch (abi) {
+ .gnueabi,
+ .gnueabihf,
+ => init("/lib/ld.so.1"),
+ else => none,
+ },
+ // TODO: ELFv2 ABI (`/lib64/ld64.so.2`) opt-in support.
+ .powerpc64 => if (abi == .gnu) init("/lib64/ld64.so.1") else none,
+ .powerpc64le => if (abi == .gnu) init("/lib64/ld64.so.2") else none,
.riscv32,
.riscv64,
- => |arch| initFmt("/lib/ld-linux-{s}-{s}{s}.so.1", .{
- @tagName(arch),
+ => |arch| if (abi == .gnu) initFmt("/lib/ld-linux-{s}{s}.so.1", .{
switch (arch) {
- .riscv32 => "ilp32",
- .riscv64 => "lp64",
+ .riscv32 => "riscv32-ilp32",
+ .riscv64 => "riscv64-lp64",
else => unreachable,
},
if (riscv.featureSetHas(cpu.features, .d))
@@ -2340,78 +2413,130 @@ pub const DynamicLinker = struct {
"f"
else
"",
- }),
+ }) else none,
- .s390x => init("/lib/ld64.so.1"),
+ .s390x => if (abi == .gnu) init("/lib/ld64.so.1") else none,
- .sparc => init("/lib/ld-linux.so.2"),
- .sparc64 => init("/lib64/ld-linux.so.2"),
+ .sparc => if (abi == .gnu) init("/lib/ld-linux.so.2") else none,
+ .sparc64 => if (abi == .gnu) init("/lib64/ld-linux.so.2") else none,
- .x86 => init("/lib/ld-linux.so.2"),
- .x86_64 => init(if (abi == .gnux32) "/libx32/ld-linux-x32.so.2" else "/lib64/ld-linux-x86-64.so.2"),
+ .x86 => if (abi == .gnu) init("/lib/ld-linux.so.2") else none,
+ .x86_64 => switch (abi) {
+ .gnu => init("/lib64/ld-linux-x86-64.so.2"),
+ .gnux32 => init("/libx32/ld-linux-x32.so.2"),
+ else => none,
+ },
- .xtensa => init("/lib/ld.so.1"),
+ .xtensa => if (abi == .gnu) init("/lib/ld.so.1") else none,
- // These are unsupported by glibc.
- .amdgcn,
- .avr,
- .bpfeb,
- .bpfel,
- .hexagon,
- .kalimba,
- .lanai,
- .loongarch32,
- .msp430,
- .nvptx,
- .nvptx64,
- .powerpcle,
- .propeller1,
- .propeller2,
- .spirv,
- .spirv32,
- .spirv64,
- .spu_2,
- .ve,
- .wasm32,
- .wasm64,
- .xcore,
- => none,
+ else => none,
}
else
none, // Not a known Linux libc.
- .serenity => init("/usr/lib/Loader.so"),
+ .serenity => switch (cpu.arch) {
+ .aarch64,
+ .riscv64,
+ .x86_64,
+ => init("/usr/lib/Loader.so"),
+ else => none,
+ },
- .dragonfly => initFmt("{s}/libexec/ld-elf.so.2", .{
+ .dragonfly => if (cpu.arch == .x86_64) initFmt("{s}/libexec/ld-elf.so.2", .{
if (os.version_range.semver.isAtLeast(.{ .major = 3, .minor = 8, .patch = 0 }) orelse false)
""
else
"/usr",
- }),
+ }) else none,
- .freebsd => initFmt("{s}/libexec/ld-elf.so.1", .{
- if (os.version_range.semver.isAtLeast(.{ .major = 6, .minor = 0, .patch = 0 }) orelse false)
- ""
- else
- "/usr",
- }),
+ .freebsd => switch (cpu.arch) {
+ .arm,
+ .armeb,
+ .thumb,
+ .thumbeb,
+ .aarch64,
+ .mips,
+ .mipsel,
+ .mips64,
+ .mips64el,
+ .powerpc,
+ .powerpc64,
+ .powerpc64le,
+ .riscv64,
+ .sparc64,
+ .x86,
+ .x86_64,
+ => initFmt("{s}/libexec/ld-elf.so.1", .{
+ if (os.version_range.semver.isAtLeast(.{ .major = 6, .minor = 0, .patch = 0 }) orelse false)
+ ""
+ else
+ "/usr",
+ }),
+ else => none,
+ },
- .netbsd => init("/libexec/ld.elf_so"),
+ .netbsd => switch (cpu.arch) {
+ .arm,
+ .armeb,
+ .thumb,
+ .thumbeb,
+ .aarch64,
+ .aarch64_be,
+ .m68k,
+ .mips,
+ .mipsel,
+ .mips64,
+ .mips64el,
+ .powerpc,
+ .riscv64,
+ .sparc,
+ .sparc64,
+ .x86,
+ .x86_64,
+ => init("/libexec/ld.elf_so"),
+ else => none,
+ },
- .openbsd => init("/usr/libexec/ld.so"),
+ .openbsd => switch (cpu.arch) {
+ .arm,
+ .thumb,
+ .aarch64,
+ .mips64,
+ .mips64el,
+ .powerpc,
+ .powerpc64,
+ .riscv64,
+ .sparc64,
+ .x86,
+ .x86_64,
+ => init("/usr/libexec/ld.so"),
+ else => none,
+ },
- .bridgeos,
+ .bridgeos => if (cpu.arch == .aarch64) init("/usr/lib/dyld") else none,
.driverkit,
.ios,
.macos,
.tvos,
.visionos,
.watchos,
- => init("/usr/lib/dyld"),
+ => switch (cpu.arch) {
+ .aarch64,
+ .x86_64,
+ => init("/usr/lib/dyld"),
+ else => none,
+ },
.illumos,
.solaris,
- => initFmt("/lib/{s}ld.so.1", .{if (ptrBitWidth_cpu_abi(cpu, abi) == 64) "64/" else ""}),
+ => switch (cpu.arch) {
+ .sparc,
+ .sparc64,
+ .x86,
+ .x86_64,
+ => initFmt("/lib/{s}ld.so.1", .{if (ptrBitWidth_cpu_abi(cpu, .none) == 64) "64/" else ""}),
+ else => none,
+ },
// Operating systems in this list have been verified as not having a standard
// dynamic linker path.
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
@@ -967,14 +967,15 @@ fn detectAbiAndDynamicLinker(
os: Target.Os,
query: Target.Query,
) DetectError!Target {
- const native_target_has_ld = comptime builtin.target.hasDynamicLinker();
+ const native_target_has_ld = comptime Target.DynamicLinker.kind(builtin.os.tag) != .none;
const is_linux = builtin.target.os.tag == .linux;
const is_solarish = builtin.target.os.tag.isSolarish();
+ const is_darwin = builtin.target.os.tag.isDarwin();
const have_all_info = query.dynamic_linker.get() != null and
query.abi != null and (!is_linux or query.abi.?.isGnu());
const os_is_non_native = query.os_tag != null;
// The Solaris/illumos environment is always the same.
- if (!native_target_has_ld or have_all_info or os_is_non_native or is_solarish) {
+ if (!native_target_has_ld or have_all_info or os_is_non_native or is_solarish or is_darwin) {
return defaultAbiAndDynamicLinker(cpu, os, query);
}
if (query.abi) |abi| {
@@ -999,26 +1000,33 @@ fn detectAbiAndDynamicLinker(
};
var ld_info_list_buffer: [all_abis.len]LdInfo = undefined;
var ld_info_list_len: usize = 0;
- const ofmt = query.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch);
-
- for (all_abis) |abi| {
- // This may be a nonsensical parameter. We detect this with
- // error.UnknownDynamicLinkerPath and skip adding it to `ld_info_list`.
- const target: Target = .{
- .cpu = cpu,
- .os = os,
- .abi = abi,
- .ofmt = ofmt,
- };
- const ld = target.standardDynamicLinkerPath();
- if (ld.get() == null) continue;
- ld_info_list_buffer[ld_info_list_len] = .{
- .ld = ld,
- .abi = abi,
- };
- ld_info_list_len += 1;
+ switch (Target.DynamicLinker.kind(os.tag)) {
+ // The OS has no dynamic linker. Leave the list empty and rely on `Abi.default()` to pick
+ // something sensible in `abiAndDynamicLinkerFromFile()`.
+ .none => {},
+ // The OS has a system-wide dynamic linker. Unfortunately, this implies that there's no
+ // useful ABI information that we can glean from it merely being present. That means the
+ // best we can do for this case (for now) is also `Abi.default()`.
+ .arch_os => {},
+ // The OS can have different dynamic linker paths depending on libc/ABI. In this case, we
+ // need to gather all the valid arch/OS/ABI combinations. `abiAndDynamicLinkerFromFile()`
+ // will then look for a dynamic linker with a matching path on the system and pick the ABI
+ // we associated it with here.
+ .arch_os_abi => for (all_abis) |abi| {
+ const ld = Target.DynamicLinker.standard(cpu, os, abi);
+
+ // Does the generated target triple actually have a standard dynamic linker path?
+ if (ld.get() == null) continue;
+
+ ld_info_list_buffer[ld_info_list_len] = .{
+ .ld = ld,
+ .abi = abi,
+ };
+ ld_info_list_len += 1;
+ },
}
+
const ld_info_list = ld_info_list_buffer[0..ld_info_list_len];
// Best case scenario: the executable is dynamically linked, and we can iterate
diff --git a/test/llvm_targets.zig b/test/llvm_targets.zig
@@ -249,10 +249,12 @@ const targets = [_]std.Target.Query{
.{ .cpu_arch = .s390x, .os_tag = .zos, .abi = .none },
.{ .cpu_arch = .sparc, .os_tag = .freestanding, .abi = .none },
+ .{ .cpu_arch = .sparc, .os_tag = .illumos, .abi = .none },
.{ .cpu_arch = .sparc, .os_tag = .linux, .abi = .gnu },
.{ .cpu_arch = .sparc, .os_tag = .linux, .abi = .none },
.{ .cpu_arch = .sparc, .os_tag = .netbsd, .abi = .none },
.{ .cpu_arch = .sparc, .os_tag = .rtems, .abi = .none },
+ .{ .cpu_arch = .sparc, .os_tag = .solaris, .abi = .none },
.{ .cpu_arch = .sparc64, .os_tag = .freebsd, .abi = .none },
.{ .cpu_arch = .sparc64, .os_tag = .freestanding, .abi = .none },
@@ -269,6 +271,9 @@ const targets = [_]std.Target.Query{
.{ .cpu_arch = .thumb, .os_tag = .freebsd, .abi = .eabihf },
.{ .cpu_arch = .thumb, .os_tag = .freestanding, .abi = .eabi },
.{ .cpu_arch = .thumb, .os_tag = .freestanding, .abi = .eabihf },
+ .{ .cpu_arch = .thumb, .os_tag = .haiku, .abi = .eabi },
+ .{ .cpu_arch = .thumb, .os_tag = .haiku, .abi = .eabihf },
+ .{ .cpu_arch = .thumb, .os_tag = .linux, .abi = .androideabi },
.{ .cpu_arch = .thumb, .os_tag = .linux, .abi = .eabi },
.{ .cpu_arch = .thumb, .os_tag = .linux, .abi = .eabihf },
.{ .cpu_arch = .thumb, .os_tag = .linux, .abi = .musleabi },
@@ -314,6 +319,7 @@ const targets = [_]std.Target.Query{
.{ .cpu_arch = .x86, .os_tag = .freestanding, .abi = .none },
.{ .cpu_arch = .x86, .os_tag = .haiku, .abi = .none },
.{ .cpu_arch = .x86, .os_tag = .hurd, .abi = .gnu },
+ .{ .cpu_arch = .x86, .os_tag = .illumos, .abi = .none },
.{ .cpu_arch = .x86, .os_tag = .linux, .abi = .android },
.{ .cpu_arch = .x86, .os_tag = .linux, .abi = .gnu },
.{ .cpu_arch = .x86, .os_tag = .linux, .abi = .musl },
@@ -322,6 +328,7 @@ const targets = [_]std.Target.Query{
.{ .cpu_arch = .x86, .os_tag = .netbsd, .abi = .none },
.{ .cpu_arch = .x86, .os_tag = .openbsd, .abi = .none },
.{ .cpu_arch = .x86, .os_tag = .rtems, .abi = .none },
+ .{ .cpu_arch = .x86, .os_tag = .solaris, .abi = .none },
.{ .cpu_arch = .x86, .os_tag = .uefi, .abi = .none },
.{ .cpu_arch = .x86, .os_tag = .windows, .abi = .gnu },
.{ .cpu_arch = .x86, .os_tag = .windows, .abi = .itanium },