package("rust") set_kind("toolchain") set_homepage("https://rust-lang.org") set_description("Rust is a general-purpose programming language emphasizing performance, type safety, and concurrency.") add_versions("1.86.0", "") add_deps("ca-certificates", {host = true, private = true}) add_deps("rustup", {host = true, private = true, system = false}) add_configs("target_plat", {description = "Target platform (for cross-compilation)", default = nil, type = "string"}) add_configs("target_arch", {description = "Target arch (for cross-compilation)", default = nil, type = "string"}) if is_plat("cross") then add_configs("target_system", {description = "Target system (for cross-compilation)", default = "unknown-linux", type = "string"}) add_configs("target_abi", {description = "Target ABI (for cross-compilation)", default = "gnu", type = "string"}) end on_load(function (package) if package:config("target_plat") == nil then package:config_set("target_plat", package:plat()) end if package:config("target_arch") == nil then package:config_set("target_arch", package:arch()) end end) on_install(function (package) import("core.tools.rustc.target_triple", {try = true}) -- introduced in xmake 3.0.0 local plat = package:config("target_plat") local arch = package:config("target_arch") if not target_triple then if plat == "mingw" or plat == "msys" then plat = "windows" end local package_plat = package:plat() if package_plat == "mingw" or package_plat == "msys" then package_plat = "windows" end if plat ~= package_plat or arch ~= package:arch() then os.raise("rust cross-compilation requires xmake dev or xmake 3.0.0") end end local rustup = assert(os.getenv("RUSTUP_HOME"), "cannot find rustup home!") local version = package:version():shortstr() local toolchain_name = version local toolchain_dir if target_triple then local host_target = assert(target_triple(package:plat(), package:arch()), "failed to build target triple for plat/arch, if you think this is a bug please create an issue") toolchain_name = toolchain_name .. "-" .. host_target toolchain_dir = toolchain_name elseif package:is_plat("msys", "mingw") and is_host("windows") then -- we have to handle mingw case because rustup will install a msvc toolchain by default on Windows toolchain_name = toolchain_name .. (package:is_arch("i386") and "-x86_64-pc-windows-gnu" or "-i686-pc-windows-gnu") toolchain_dir = toolchain_name else toolchain_dir = toolchain_name .. "-*" end os.vrunv("rustup", {"install", "--no-self-update", toolchain_name}) if target_triple or plat == "cross" then local target if plat == "cross" then local system = package:config("target_system") local abi = package:config("target_abi") target = arch .. "-" .. system .. "-" .. abi else target = assert(target_triple(plat, arch), "failed to build target triple for target_plat/target_arch, if you think this is a bug please create an issue") end if target ~= host_target then os.vrunv("rustup", {"target", "add", target}) end end os.vmv(path.join(rustup, "toolchains", toolchain_dir, "*"), package:installdir()) -- cleanup to prevent rustup to think the toolchain is still installed os.vrm(path.join(rustup, "toolchains", toolchain_dir)) os.vrm(path.join(rustup, "update-hashes", toolchain_dir)) package:addenv("RC", "bin/rustc" .. (is_host("windows") and ".exe" or "")) package:mark_as_pathenv("RC") end) on_test(function (package) os.vrun("cargo --version") os.vrun("rustc --version") end)