yggdrasil/xtask/src/build/toolchain.rs

150 lines
3.9 KiB
Rust
Raw Normal View History

2024-03-12 18:17:47 +02:00
// 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<String>,
target: Vec<String>,
}
#[derive(Debug, serde::Serialize)]
struct RustTargetConfig {
cc: Option<String>,
cxx: Option<String>,
}
#[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<String, RustTargetConfig>,
rust: RustRustConfig,
}
fn configure<P: AsRef<Path>>(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<P: AsRef<Path>>(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<P: AsRef<Path>>(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(())
}