DoxigAlpha

getExternalExecutor

Return whether or not the given host is capable of running executables of the other target.

Function parameters

Parameters

#
host:*const std.Target
candidate:*const std.Target

Type definitions in this namespace

Types

#

Return whether or not the given host is capable of running executables of

Functions

#
getExternalExecutor
Return whether or not the given host is capable of running executables of
resolveTargetQuery
Given a `Target.Query`, which specifies in detail which parts of the

Error sets in this namespace

Error Sets

#

Source

Implementation

#
pub fn getExternalExecutor(
    host: *const std.Target,
    candidate: *const std.Target,
    options: GetExternalExecutorOptions,
) Executor {
    const os_match = host.os.tag == candidate.os.tag;
    const cpu_ok = cpu_ok: {
        if (host.cpu.arch == candidate.cpu.arch)
            break :cpu_ok true;

        if (host.cpu.arch == .x86_64 and candidate.cpu.arch == .x86)
            break :cpu_ok true;

        if (host.cpu.arch == .aarch64 and candidate.cpu.arch == .arm)
            break :cpu_ok true;

        if (host.cpu.arch == .aarch64_be and candidate.cpu.arch == .armeb)
            break :cpu_ok true;

        // TODO additionally detect incompatible CPU features.
        // Note that in some cases the OS kernel will emulate missing CPU features
        // when an illegal instruction is encountered.

        break :cpu_ok false;
    };

    var bad_result: Executor = .bad_os_or_cpu;

    if (os_match and cpu_ok) native: {
        if (options.link_libc) {
            if (candidate.dynamic_linker.get()) |candidate_dl| {
                fs.cwd().access(candidate_dl, .{}) catch {
                    bad_result = .{ .bad_dl = candidate_dl };
                    break :native;
                };
            }
        }
        return .native;
    }

    // If the OS match and OS is macOS and CPU is arm64, we can use Rosetta 2
    // to emulate the foreign architecture.
    if (options.allow_rosetta and os_match and
        host.os.tag == .macos and host.cpu.arch == .aarch64)
    {
        switch (candidate.cpu.arch) {
            .x86_64 => return .rosetta,
            else => return bad_result,
        }
    }

    // If the OS matches, we can use QEMU to emulate a foreign architecture.
    if (options.allow_qemu and os_match and (!cpu_ok or options.qemu_fixes_dl)) {
        return switch (candidate.cpu.arch) {
            .aarch64 => Executor{ .qemu = "qemu-aarch64" },
            .aarch64_be => Executor{ .qemu = "qemu-aarch64_be" },
            .arm, .thumb => Executor{ .qemu = "qemu-arm" },
            .armeb, .thumbeb => Executor{ .qemu = "qemu-armeb" },
            .hexagon => Executor{ .qemu = "qemu-hexagon" },
            .loongarch64 => Executor{ .qemu = "qemu-loongarch64" },
            .m68k => Executor{ .qemu = "qemu-m68k" },
            .mips => Executor{ .qemu = "qemu-mips" },
            .mipsel => Executor{ .qemu = "qemu-mipsel" },
            .mips64 => Executor{
                .qemu = switch (candidate.abi) {
                    .gnuabin32, .muslabin32 => "qemu-mipsn32",
                    else => "qemu-mips64",
                },
            },
            .mips64el => Executor{
                .qemu = switch (candidate.abi) {
                    .gnuabin32, .muslabin32 => "qemu-mipsn32el",
                    else => "qemu-mips64el",
                },
            },
            .or1k => Executor{ .qemu = "qemu-or1k" },
            .powerpc => Executor{ .qemu = "qemu-ppc" },
            .powerpc64 => Executor{ .qemu = "qemu-ppc64" },
            .powerpc64le => Executor{ .qemu = "qemu-ppc64le" },
            .riscv32 => Executor{ .qemu = "qemu-riscv32" },
            .riscv64 => Executor{ .qemu = "qemu-riscv64" },
            .s390x => Executor{ .qemu = "qemu-s390x" },
            .sparc => Executor{
                .qemu = if (candidate.cpu.has(.sparc, .v8plus))
                    "qemu-sparc32plus"
                else
                    "qemu-sparc",
            },
            .sparc64 => Executor{ .qemu = "qemu-sparc64" },
            .x86 => Executor{ .qemu = "qemu-i386" },
            .x86_64 => switch (candidate.abi) {
                .gnux32, .muslx32 => return bad_result,
                else => Executor{ .qemu = "qemu-x86_64" },
            },
            .xtensa => Executor{ .qemu = "qemu-xtensa" },
            else => bad_result,
        };
    }

    if (options.allow_wasmtime and candidate.cpu.arch.isWasm()) {
        return Executor{ .wasmtime = "wasmtime" };
    }

    switch (candidate.os.tag) {
        .windows => {
            if (options.allow_wine) {
                const wine_supported = switch (candidate.cpu.arch) {
                    .thumb => switch (host.cpu.arch) {
                        .arm, .thumb, .aarch64 => true,
                        else => false,
                    },
                    .aarch64 => host.cpu.arch == .aarch64,
                    .x86 => host.cpu.arch.isX86(),
                    .x86_64 => host.cpu.arch == .x86_64,
                    else => false,
                };
                return if (wine_supported) Executor{ .wine = "wine" } else bad_result;
            }
            return bad_result;
        },
        .driverkit, .macos => {
            if (options.allow_darling) {
                // This check can be loosened once darling adds a QEMU-based emulation
                // layer for non-host architectures:
                // https://github.com/darlinghq/darling/issues/863
                if (candidate.cpu.arch != host.cpu.arch) {
                    return bad_result;
                }
                return Executor{ .darling = "darling" };
            }
            return bad_result;
        },
        else => return bad_result,
    }
}