Function standard [src]
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.
Prototype
pub fn standard(cpu: Cpu, os: Os, abi: Abi) DynamicLinker
Parameters
cpu: Cpu
os: Os
abi: Abi
Source
pub fn standard(cpu: Cpu, os: Os, abi: Abi) DynamicLinker {
return switch (os.tag) {
.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 => 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),
switch (abi) {
.gnu => "",
.gnuilp32 => "_ilp32",
else => return none,
},
}),
.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,
}}),
else => none,
},
.linux => if (abi.isAndroid())
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, // TODO: `-sp` and `-sf` ABI support in LLVM 20.
.m68k,
.powerpc64,
.powerpc64le,
.s390x,
=> |arch| if (abi == .musl) initFmt("/lib/ld-musl-{s}.so.1", .{@tagName(arch)}) else none,
.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}.so.1", .{
switch (abi) {
.muslabi64 => "64",
.muslabin32 => "n32",
else => return none,
},
if (mips.featureSetHas(cpu.features, .mips64r6)) "r6" else "",
if (arch == .mips64el) "el" else "",
}),
.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 => if (abi == .gnu) init("/lib/ld-linux-arc.so.2") else none,
.arm,
.armeb,
.thumb,
.thumbeb,
=> 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),
switch (abi) {
.gnu => "",
.gnuilp32 => "_ilp32",
else => return none,
},
}),
// TODO: `-be` architecture support.
.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 => return none,
}}),
.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) {
.gnuabi64 => "64",
.gnuabin32 => "32",
else => return none,
},
if (mips.featureSetHas(cpu.features, .nan2008)) "-linux-mipsn8" else "",
}),
.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| if (abi == .gnu) initFmt("/lib/ld-linux-{s}{s}.so.1", .{
switch (arch) {
.riscv32 => "riscv32-ilp32",
.riscv64 => "riscv64-lp64",
else => unreachable,
},
if (riscv.featureSetHas(cpu.features, .d))
"d"
else if (riscv.featureSetHas(cpu.features, .f))
"f"
else
"",
}) else none,
.s390x => if (abi == .gnu) init("/lib/ld64.so.1") else none,
.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 => 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 => if (abi == .gnu) init("/lib/ld.so.1") else none,
else => none,
}
else
none, // Not a known Linux libc.
.serenity => switch (cpu.arch) {
.aarch64,
.riscv64,
.x86_64,
=> init("/usr/lib/Loader.so"),
else => none,
},
.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 => 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 => 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 => switch (cpu.arch) {
.arm,
.thumb,
.aarch64,
.mips64,
.mips64el,
.powerpc,
.powerpc64,
.riscv64,
.sparc64,
.x86,
.x86_64,
=> init("/usr/libexec/ld.so"),
else => none,
},
.driverkit,
.ios,
.macos,
.tvos,
.visionos,
.watchos,
=> switch (cpu.arch) {
.aarch64,
.x86_64,
=> init("/usr/lib/dyld"),
else => none,
},
.illumos,
.solaris,
=> 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.
.freestanding,
.other,
.contiki,
.elfiamcu,
.hermit,
.aix,
.plan9,
.rtems,
.zos,
.uefi,
.windows,
.emscripten,
.wasi,
.amdhsa,
.amdpal,
.cuda,
.mesa3d,
.nvcl,
.opencl,
.opengl,
.vulkan,
=> none,
// TODO go over each item in this list and either move it to the above list, or
// implement the standard dynamic linker path code for it.
.ps3,
.ps4,
.ps5,
=> none,
} catch unreachable;
}