use std::{io, path::PathBuf}; use clap::ValueEnum; #[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(default)] pub struct ToolchainConfig { pub branch: String, } #[derive(Debug, serde::Deserialize, serde::Serialize)] #[serde(default)] pub struct BuildComponents { pub libc: bool, // Depends on .libc pub libcxx: bool, } #[derive(Debug, Default, serde::Deserialize, serde::Serialize)] #[serde(default)] pub struct AArch64TargetConfig { pub components: BuildComponents, } #[derive(Debug, Default, serde::Deserialize, serde::Serialize)] #[serde(default)] pub struct X86_64TargetConfig { pub components: BuildComponents, } #[derive(Debug, Default, serde::Deserialize, serde::Serialize)] #[serde(default)] pub struct I686TargetConfig { pub components: BuildComponents, } #[derive(Debug, Default, serde::Deserialize, serde::Serialize)] #[serde(default)] pub struct TargetConfig { pub aarch64: AArch64TargetConfig, pub x86_64: X86_64TargetConfig, pub i686: I686TargetConfig, } #[derive(Debug, Default, serde::Deserialize, serde::Serialize)] #[serde(default)] pub struct XTaskConfig { pub toolchain: ToolchainConfig, pub target: TargetConfig, } #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, ValueEnum)] pub enum Profile { #[default] Debug, Release, } #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, ValueEnum)] #[allow(non_camel_case_types)] #[clap(rename_all = "verbatim")] pub enum Arch { #[default] aarch64, riscv64, x86_64, i686, } #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, ValueEnum)] #[allow(non_camel_case_types)] #[clap(rename_all = "verbatim")] pub enum Board { #[default] default, // AArch64 boards raspi4b, virt, } #[derive(Debug)] pub struct BuildEnv { pub config: XTaskConfig, pub verbose: bool, pub profile: Profile, pub arch: Arch, pub board: Board, pub kernel_triple: &'static str, pub kernel_linker_script: String, pub host_triple: String, pub workspace_root: PathBuf, pub kernel_output_dir: PathBuf, pub userspace_output_dir: PathBuf, pub kernel_symbol_file: PathBuf, pub llvm_sysroot: PathBuf, } impl Default for ToolchainConfig { fn default() -> Self { Self { branch: "alnyan/yggdrasil-1.84.0".into(), } } } impl Default for BuildComponents { fn default() -> Self { Self { libc: true, libcxx: true, } } } impl BuildEnv { pub fn new( config: XTaskConfig, verbose: bool, profile: Profile, arch: Arch, board: Board, workspace_root: PathBuf, ) -> Self { let kernel_triple = match (arch, board) { (Arch::aarch64, Board::virt | Board::default) => "aarch64-unknown-qemu", (Arch::riscv64, Board::virt | Board::default) => "riscv64-unknown-qemu", (Arch::aarch64, Board::raspi4b) => "aarch64-unknown-raspi4b", (Arch::x86_64, Board::default) => "x86_64-unknown-none", (Arch::i686, Board::default) => "i686-unknown-none", _ => { log::error!("Invalid arch/board combination: {arch:?}/{board:?}"); panic!(); } }; let kernel_linker_script = match arch { Arch::aarch64 => format!("arm/{kernel_triple}.ld"), Arch::riscv64 => format!("riscv/{kernel_triple}.ld"), Arch::i686 | Arch::x86_64 => format!("x86/{kernel_triple}.ld"), }; let kernel_output_dir = workspace_root.join(format!("target/{}/{}", kernel_triple, profile.dir())); let userspace_output_dir = workspace_root.join(format!( "userspace/target/{}-unknown-yggdrasil/{}", arch.name(), profile.dir() )); let kernel_symbol_file = kernel_output_dir.join("symbols.dat"); let host = env!("TARGET"); let llvm_sysroot = workspace_root.join(format!( "toolchain-c/sysroot/{}-unknown-yggdrasil", arch.name() )); Self { config, verbose, profile, arch, board, kernel_triple, kernel_linker_script, host_triple: host.into(), workspace_root, kernel_symbol_file, kernel_output_dir, userspace_output_dir, llvm_sysroot, } } pub fn dump(&self, output: &mut W) { match toml::to_string_pretty(&self.config) { Ok(string) => { writeln!(output, "{string}").ok(); } Err(error) => { log::error!("Config serialization error: {error}"); } } } } impl XTaskConfig { pub fn components(&self, env: &BuildEnv) -> &BuildComponents { match env.arch { Arch::riscv64 => todo!(), Arch::aarch64 => &self.target.aarch64.components, Arch::x86_64 => &self.target.x86_64.components, Arch::i686 => &self.target.i686.components, } } } impl Profile { pub fn dir(&self) -> &str { match self { Self::Debug => "debug", Self::Release => "release", } } pub fn name(&self) -> &str { self.dir() } } impl Arch { pub fn all() -> impl Iterator { [Self::aarch64, Self::x86_64, Self::i686].into_iter() } pub fn user_triple(&self) -> &str { match self { Self::riscv64 => "riscv64-unknown-yggdrasil", Self::aarch64 => "aarch64-unknown-yggdrasil", Self::x86_64 => "x86_64-unknown-yggdrasil", Self::i686 => "i686-unknown-yggdrasil", } } pub fn name(&self) -> &str { match self { Self::riscv64 => "riscv64", Self::aarch64 => "aarch64", Self::x86_64 => "x86_64", Self::i686 => "i686", } } }