170 lines
4.4 KiB
Rust
170 lines
4.4 KiB
Rust
// use std::{collections::HashMap, path::Path};
|
|
|
|
use std::{
|
|
collections::HashMap, fs::OpenOptions, os::unix::fs::OpenOptionsExt, path::Path,
|
|
process::Command,
|
|
};
|
|
|
|
use crate::{
|
|
env::BuildEnv,
|
|
error::Error,
|
|
util::{self, git_clone},
|
|
};
|
|
|
|
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,
|
|
|
|
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(),
|
|
|
|
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)
|
|
}
|
|
}
|
|
|
|
fn install_shims<P: AsRef<Path>>(env: &BuildEnv, toolchain_root: P) -> Result<(), Error> {
|
|
use std::io::Write;
|
|
|
|
let toolchain_root = toolchain_root.as_ref();
|
|
let build_dir = toolchain_root.join("build").join(&env.host_triple);
|
|
let stage1_rustlib = build_dir
|
|
.join("stage1/lib/rustlib/")
|
|
.join(&env.host_triple)
|
|
.join("lib");
|
|
let stage1_tools_bin = build_dir.join("stage1-tools-bin");
|
|
let stage1_bin = build_dir.join("stage1/bin");
|
|
|
|
let rust_analyzer = stage1_bin.join("rust-analyzer");
|
|
|
|
let mut file = OpenOptions::new()
|
|
.write(true)
|
|
.truncate(true)
|
|
.create(true)
|
|
.mode(0o755)
|
|
.open(rust_analyzer)?;
|
|
|
|
writeln!(file, "#!/bin/sh")?;
|
|
writeln!(
|
|
file,
|
|
"LD_LIBRARY_PATH={} {}/rust-analyzer",
|
|
stage1_rustlib.display(),
|
|
stage1_tools_bin.display()
|
|
)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn fetch(env: &BuildEnv, branch: &str) -> Result<(), Error> {
|
|
let path = env.workspace_root.join("toolchain");
|
|
git_clone(path, TOOLCHAIN_URL, branch, false)
|
|
}
|
|
|
|
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)?;
|
|
log::info!("Installing rust tool shims");
|
|
install_shims(env, &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(())
|
|
}
|