elf_loader 0.16.0

A no_std-friendly ELF loader and runtime linker for Rust.
Documentation
use std::env;

fn main() {
    println!("cargo:rerun-if-env-changed=TARGET");
    println!("cargo:rerun-if-env-changed=CARGO_CFG_TARGET_ABI");
    println!("cargo:rerun-if-env-changed=CARGO_CFG_TARGET_ARCH");
    println!("cargo:rustc-check-cfg=cfg(riscv_float_abi, values(\"soft\", \"f\", \"d\", \"q\"))");

    let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default();
    if target_arch != "riscv32" && target_arch != "riscv64" {
        return;
    }

    let target_abi = env::var("CARGO_CFG_TARGET_ABI").unwrap_or_default();
    let float_abi = float_abi_from_target_abi(&target_abi).or_else(|| {
        env::var("TARGET")
            .ok()
            .and_then(|target| float_abi_from_target(&target))
    });

    if let Some(float_abi) = float_abi {
        println!("cargo:rustc-cfg=riscv_float_abi=\"{float_abi}\"");
    }
}

fn float_abi_from_target_abi(target_abi: &str) -> Option<&'static str> {
    match target_abi {
        "ilp32" | "lp64" => Some("soft"),
        "ilp32f" | "lp64f" => Some("f"),
        "ilp32d" | "lp64d" => Some("d"),
        _ => None,
    }
}

fn float_abi_from_target(target: &str) -> Option<&'static str> {
    let arch = target.split('-').next()?;
    let extensions = arch
        .strip_prefix("riscv32")
        .or_else(|| arch.strip_prefix("riscv64"))?;
    let single_letter_extensions = extensions.split('_').next().unwrap_or(extensions);

    if single_letter_extensions.contains('g') || single_letter_extensions.contains('d') {
        Some("d")
    } else if single_letter_extensions.contains('f') {
        Some("f")
    } else {
        Some("soft")
    }
}