Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

DynamicLinker

Target.DynamicLinker
pub const DynamicLinker = struct

File

lib/std/Target.zig:2340

Code

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
    /// that this API requires no allocator.
    buffer: [255]u8,

    /// Used to construct the dynamic linker path. This field should not be used
    /// directly. See `get` and `set`.
    len: u8,

    pub const none: DynamicLinker = .{ .buffer = undefined, .len = 0 };

    /// Asserts that the length is less than or equal to 255 bytes.
    pub fn init(maybe_path: ?[]const u8) DynamicLinker {
        var dl: DynamicLinker = undefined;
        dl.set(maybe_path);
        return dl;
    }

    pub fn initFmt(comptime fmt_str: []const u8, args: anytype) !DynamicLinker {
        var dl: DynamicLinker = undefined;
        try dl.setFmt(fmt_str, args);
        return dl;
    }

    /// The returned memory has the same lifetime as the `DynamicLinker`.
    pub fn get(dl: *const DynamicLinker) ?[]const u8 {
        return if (dl.len > 0) dl.buffer[0..dl.len] else null;
    }

    /// Asserts that the length is less than or equal to 255 bytes.
    pub fn set(dl: *DynamicLinker, maybe_path: ?[]const u8) void {
        const path = maybe_path orelse "";
        @memcpy(dl.buffer[0..path.len], path);
        dl.len = @intCast(path.len);
    }

    /// Asserts that the length is less than or equal to 255 bytes.
    pub fn setFmt(dl: *DynamicLinker, comptime fmt_str: []const u8, args: anytype) !void {
        dl.len = @intCast((try std.fmt.bufPrint(&dl.buffer, fmt_str, args)).len);
    }

    pub fn eql(lhs: DynamicLinker, rhs: DynamicLinker) bool {
        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,
            .illumos,
            .serenity,

            .dragonfly,
            .freebsd,
            .netbsd,
            .openbsd,

            .driverkit,
            .ios,
            .maccatalyst,
            .macos,
            .tvos,
            .visionos,
            .watchos,
            => .arch_os,
            .hurd,
            .linux,
            => .arch_os_abi,
            .freestanding,
            .other,

            .contiki,
            .hermit,
            .managarm, // Needs to be double-checked.

            .plan9,
            .rtems,

            .uefi,
            .windows,

            .@"3ds",
            .wiiu,
            .@"switch",

            .emscripten,
            .wasi,

            .amdhsa,
            .amdpal,
            .cuda,
            .mesa3d,
            .nvcl,
            .opencl,
            .opengl,
            .vulkan,

            .psx,
            .ps3,
            .ps4,
            .ps5,
            .psp,
            .vita,

            .tios,
            .ashetos,
            => .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 => switch (cpu.arch) {
                .arm,
                .aarch64,
                .riscv64,
                .thumb,
                .x86_64,
                => init("ld.so.1"), // Fuchsia is unusual in that `DT_INTERP` is just a basename.
                else => none,
            },

            .haiku => switch (cpu.arch) {
                .arm,
                .aarch64,
                .riscv64,
                .x86,
                .x86_64,
                => init("/system/runtime_loader"),
                else => none,
            },

            .hurd => switch (cpu.arch) {
                .aarch64,
                .aarch64_be,
                => |arch| if (abi == .gnu) initFmt("/lib/ld-{s}.so.1", .{@tagName(arch)}) else 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,
            },

            .illumos,
            => switch (cpu.arch) {
                .x86,
                .x86_64,
                => initFmt("/lib/{s}ld.so.1", .{if (ptrBitWidth_cpu_abi(cpu, .none) == 64) "64/" else ""}),
                else => none,
            },

            .linux => if (abi.isAndroid())
                switch (cpu.arch) {
                    .arm => 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,
                        },
                    }),

                    .loongarch32,
                    .loongarch64,
                    => |arch| initFmt("/lib/ld-musl-{s}{s}.so.1", .{
                        @tagName(arch),
                        switch (abi) {
                            .musl => "",
                            .muslf32 => "-sp",
                            .muslsf => "-sf",
                            else => return none,
                        },
                    }),

                    .aarch64,
                    .aarch64_be,
                    .hexagon,
                    .kvx,
                    .m68k,
                    .microblaze,
                    .microblazeel,
                    .or1k,
                    .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 (cpu.has(.mips, .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 (cpu.has(.mips, .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,
                    }}),

                    .sh,
                    .sheb,
                    => |arch| initFmt("/lib/ld-musl-{t}{s}.so.1", .{
                        arch,
                        switch (abi) {
                            .musleabi => "-nofpu",
                            .musleabihf => "",
                            else => return none,
                        },
                    }),

                    .riscv32,
                    .riscv64,
                    => |arch| if (abi == .musl) initFmt("/lib/ld-musl-{s}{s}.so.1", .{
                        @tagName(arch),
                        if (cpu.has(.riscv, .d))
                            ""
                        else if (cpu.has(.riscv, .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) {
                    .arc,
                    .arceb,
                    => |arch| if (abi == .gnu) initFmt("/lib/ld-linux-{t}.so.2", .{arch}) else none,

                    .arm,
                    .armeb,
                    => initFmt("/lib/ld-linux{s}.so.3", .{switch (abi) {
                        .gnueabi => "",
                        .gnueabihf => "-armhf",
                        else => return none,
                    }}),

                    .aarch64,
                    .aarch64_be,
                    .or1k,
                    => |arch| if (abi == .gnu) initFmt("/lib/ld-linux-{s}.so.1", .{@tagName(arch)}) else none,

                    .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,
                    }}),

                    .hppa,
                    .m68k,
                    .microblaze,
                    .microblazeel,
                    .xtensa,
                    .xtensaeb,
                    => if (abi == .gnu) init("/lib/ld.so.1") else none,

                    .mips,
                    .mipsel,
                    => switch (abi) {
                        .gnueabi,
                        .gnueabihf,
                        => initFmt("/lib/ld{s}.so.1", .{
                            if (cpu.has(.mips, .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 (cpu.has(.mips, .nan2008)) "-linux-mipsn8" else "",
                    }),

                    .powerpc => switch (abi) {
                        .gnueabi,
                        .gnueabihf,
                        => init("/lib/ld.so.1"),
                        else => none,
                    },

                    .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 (cpu.has(.riscv, .d))
                            "d"
                        else if (cpu.has(.riscv, .f))
                            "f"
                        else
                            "",
                    }) else none,

                    .s390x => if (abi == .gnu) init("/lib/ld64.so.1") else none,

                    .sh,
                    .sheb,
                    => switch (abi) {
                        .gnueabi,
                        .gnueabihf,
                        => init("/lib/ld-linux.so.2"),
                        else => none,
                    },

                    .alpha,
                    .sparc,
                    .x86,
                    => if (abi == .gnu) init("/lib/ld-linux.so.2") else none,

                    .sparc64 => if (abi == .gnu) init("/lib64/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,
                    },

                    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,
                .aarch64,
                .powerpc,
                .powerpc64,
                .powerpc64le,
                .riscv64,
                .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) {
                .alpha,
                .arm,
                .armeb,
                .aarch64,
                .aarch64_be,
                .hppa,
                .m68k,
                .mips,
                .mipsel,
                .mips64,
                .mips64el,
                .powerpc,
                .riscv32,
                .riscv64,
                .sh,
                .sheb,
                .sparc,
                .sparc64,
                .x86,
                .x86_64,
                => init("/libexec/ld.elf_so"),
                else => none,
            },

            .openbsd => switch (cpu.arch) {
                .alpha,
                .arm,
                .aarch64,
                .hppa,
                .m88k,
                .mips64,
                .mips64el,
                .powerpc,
                .powerpc64,
                .riscv64,
                .sh,
                .sparc64,
                .x86,
                .x86_64,
                => init("/usr/libexec/ld.so"),
                else => none,
            },

            .driverkit,
            .ios,
            .maccatalyst,
            .macos,
            .tvos,
            .visionos,
            .watchos,
            => switch (cpu.arch) {
                .aarch64,
                .x86_64,
                => init("/usr/lib/dyld"),
                else => none,
            },

            // Operating systems in this list have been verified as not having a standard
            // dynamic linker path.
            .freestanding,
            .other,

            .contiki,
            .hermit,

            .plan9,
            .rtems,

            .uefi,
            .windows,

            .@"3ds",
            .wiiu,
            .@"switch",

            .psx,
            .psp,
            .vita,

            .emscripten,
            .wasi,

            .amdhsa,
            .amdpal,
            .cuda,
            .mesa3d,
            .nvcl,
            .opencl,
            .opengl,
            .vulkan,

            .tios,
            .ashetos,
            => 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.
            .managarm,

            .ps3,
            .ps4,
            .ps5,
            => none,
        } catch unreachable;
    }
}