// use std::{collections::HashMap, path::Path}; use std::{collections::HashMap, path::Path, process::Command}; use crate::{env::BuildEnv, error::Error, util}; const TOOLCHAIN_URL: &str = "https://git.alnyan.me/yggdrasil/yggdrasil-rust"; #[derive(Debug, serde::Serialize)] struct RustBuildConfig { host: Vec, target: Vec, } #[derive(Debug, serde::Serialize)] struct RustTargetConfig { cc: Option, cxx: Option, } #[derive(Debug, serde::Serialize)] struct RustRustConfig { incremental: bool, } #[derive(Debug, serde::Serialize)] #[serde(rename_all = "kebab-case")] struct RustToolchainConfig { profile: String, changelog_seen: u32, change_id: u32, build: RustBuildConfig, target: HashMap, rust: RustRustConfig, } fn configure>(env: &BuildEnv, config_toml_path: P) -> Result<(), Error> { let config = RustToolchainConfig { profile: "user".into(), changelog_seen: 2, change_id: 102579, build: RustBuildConfig { host: vec![env.host_triple.clone()], target: vec![ env.host_triple.clone(), "x86_64-unknown-yggdrasil".into(), "aarch64-unknown-yggdrasil".into(), ], }, target: HashMap::from_iter([( "aarch64-unknown-yggdrasil".into(), RustTargetConfig { cc: Some("aarch64-linux-gnu-gcc".into()), cxx: Some("aarch64-linux-gnu-g++".into()), }, )]), rust: RustRustConfig { incremental: true }, }; let toml = toml::to_string_pretty(&config)?; std::fs::write(config_toml_path, toml.as_bytes())?; Ok(()) } pub fn is_toolchain_linked() -> bool { util::run_external_command("cargo", ["+ygg-stage1", "--version"], true).is_ok() } fn link_rustup_toolchain>(env: &BuildEnv, toolchain_root: P) -> Result<(), Error> { util::run_external_command( "rustup", [ "toolchain", "link", "ygg-stage1", &format!( "{}", toolchain_root .as_ref() .join("build") .join(&env.host_triple) .join("stage1") .display() ), ], false, ) } fn do_build>(toolchain_root: P) -> Result<(), Error> { let status = Command::new("./x") .current_dir(toolchain_root) .args(["build", "--stage=1"]) .status()?; if status.success() { Ok(()) } else { Err(Error::ToolchainBuildFailed) } } pub fn fetch(env: &BuildEnv, branch: &str) -> Result<(), Error> { let path = env.workspace_root.join("toolchain"); match git2::Repository::open(&path) { Ok(_) => {} Err(err) if err.code() == git2::ErrorCode::NotFound => { log::info!( "Fetching toolchain: src={}, branch={}", TOOLCHAIN_URL, branch ); git2::build::RepoBuilder::new() .branch(branch) .clone(TOOLCHAIN_URL, &path)?; } Err(err) => return Err(err.into()), } Ok(()) } pub fn build(env: &BuildEnv) -> Result<(), Error> { let toolchain_path = env.workspace_root.join("toolchain"); let config_toml_path = toolchain_path.join("config.toml"); assert!(toolchain_path.exists()); // Write config.toml if !config_toml_path.exists() { configure(env, config_toml_path)?; } log::info!("Building toolchain"); do_build(&toolchain_path)?; if !is_toolchain_linked() { log::info!("Linking the newly built toolchain to +ygg-stage1"); link_rustup_toolchain(env, &toolchain_path)?; } else { log::debug!("Toolchain already linked"); } Ok(()) }