⚠️ VeridianOS Kernel Documentation - This is low-level kernel code. All functions are unsafe unless explicitly marked otherwise. no_std

veridian_kernel/pkg/ports/
rustc_bootstrap.rs

1//! Rustc Bootstrap (Stage 0 -> Stage 1 -> Stage 2)
2//!
3//! Bootstraps the Rust compiler natively on VeridianOS using a cross-compiled
4//! rustc (from Phase 6.5) as the seed compiler. Manages the multi-stage
5//! build process and config.toml generation.
6
7use alloc::{
8    string::{String, ToString},
9    vec::Vec,
10};
11
12use crate::error::KernelError;
13
14/// Bootstrap stages
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum BootstrapStage {
17    /// Using cross-compiled seed compiler
18    Stage0,
19    /// First native build (compiled by seed)
20    Stage1,
21    /// Self-hosted build (compiled by Stage 1)
22    Stage2,
23}
24
25impl BootstrapStage {
26    pub fn next(self) -> Option<Self> {
27        match self {
28            Self::Stage0 => Some(Self::Stage1),
29            Self::Stage1 => Some(Self::Stage2),
30            Self::Stage2 => None,
31        }
32    }
33}
34
35/// Rustc bootstrap configuration
36#[derive(Debug, Clone)]
37pub struct RustcBootstrapConfig {
38    pub rustc_version: String,
39    pub target_triple: String,
40    pub seed_rustc_path: String,
41    pub seed_cargo_path: String,
42    pub llvm_root: String,
43    pub install_prefix: String,
44    pub enable_docs: bool,
45    pub enable_extended: bool,
46    pub current_stage: BootstrapStage,
47}
48
49impl Default for RustcBootstrapConfig {
50    fn default() -> Self {
51        Self {
52            rustc_version: "1.93.1".to_string(),
53            target_triple: "x86_64-unknown-veridian".to_string(),
54            seed_rustc_path: "/usr/local/bin/rustc".to_string(),
55            seed_cargo_path: "/usr/local/bin/cargo".to_string(),
56            llvm_root: "/usr/local".to_string(),
57            install_prefix: "/usr/local".to_string(),
58            enable_docs: false,
59            enable_extended: true,
60            current_stage: BootstrapStage::Stage0,
61        }
62    }
63}
64
65impl RustcBootstrapConfig {
66    /// Generate config.toml for x.py
67    pub fn generate_config_toml(&self) -> String {
68        let mut config = String::new();
69
70        config.push_str("[build]\n");
71        config.push_str(&alloc::format!("host = [\"{}\"]\n", self.target_triple));
72        config.push_str(&alloc::format!("target = [\"{}\"]\n", self.target_triple));
73        config.push_str(&alloc::format!("cargo = \"{}\"\n", self.seed_cargo_path));
74        config.push_str(&alloc::format!("rustc = \"{}\"\n", self.seed_rustc_path));
75        config.push_str("docs = false\n");
76        config.push_str("extended = true\n");
77        config.push_str("tools = [\"cargo\"]\n");
78        config.push_str("vendor = true\n");
79        config.push('\n');
80
81        config.push_str("[llvm]\n");
82        config.push_str("link-shared = false\n");
83        config.push_str("targets = \"X86;AArch64;RISCV\"\n");
84        config.push('\n');
85
86        config.push_str("[rust]\n");
87        config.push_str("codegen-units = 1\n");
88        config.push_str("lto = \"thin\"\n");
89        config.push_str("debug = false\n");
90        config.push_str("optimize = true\n");
91        config.push_str("channel = \"nightly\"\n");
92        config.push('\n');
93
94        config.push_str(&alloc::format!("[target.{}]\n", self.target_triple));
95        config.push_str(&alloc::format!(
96            "llvm-config = \"{}/bin/llvm-config\"\n",
97            self.llvm_root
98        ));
99        config.push('\n');
100
101        config.push_str("[install]\n");
102        config.push_str(&alloc::format!("prefix = \"{}\"\n", self.install_prefix));
103
104        config
105    }
106
107    /// Generate x.py build command for a given stage
108    pub fn build_command(&self, stage: BootstrapStage) -> String {
109        let stage_num = match stage {
110            BootstrapStage::Stage0 => 0,
111            BootstrapStage::Stage1 => 1,
112            BootstrapStage::Stage2 => 2,
113        };
114        alloc::format!("python3 x.py build --stage {}", stage_num)
115    }
116
117    /// Generate x.py install command
118    pub fn install_command(&self) -> String {
119        "python3 x.py install".to_string()
120    }
121
122    /// Advance to next stage
123    pub fn advance_stage(&mut self) -> Result<(), KernelError> {
124        match self.current_stage.next() {
125            Some(next) => {
126                self.current_stage = next;
127                Ok(())
128            }
129            None => Err(KernelError::InvalidArgument {
130                name: "stage",
131                value: "already at final stage",
132            }),
133        }
134    }
135
136    /// Verify that a rustc binary at the given path produces expected output
137    pub fn verify_rustc(&self, version_output: &str) -> bool {
138        version_output.contains("rustc") && version_output.contains(&self.rustc_version)
139    }
140
141    /// Check if Stage 2 output matches Stage 1 (reproducibility)
142    pub fn check_reproducibility(&self, stage1_hash: &[u8; 32], stage2_hash: &[u8; 32]) -> bool {
143        stage1_hash == stage2_hash
144    }
145}
146
147/// Rustdoc generation configuration
148#[derive(Debug, Clone)]
149pub struct RustdocConfig {
150    pub crate_name: String,
151    pub source_dir: String,
152    pub output_dir: String,
153    pub features: Vec<String>,
154}
155
156impl RustdocConfig {
157    pub fn new(crate_name: &str, source_dir: &str) -> Self {
158        Self {
159            crate_name: crate_name.to_string(),
160            source_dir: source_dir.to_string(),
161            output_dir: alloc::format!("{}/target/doc", source_dir),
162            features: Vec::new(),
163        }
164    }
165
166    pub fn build_command(&self) -> String {
167        let mut cmd = String::from("cargo doc --no-deps");
168        if !self.features.is_empty() {
169            cmd.push_str(&alloc::format!(" --features {}", self.features.join(",")));
170        }
171        cmd
172    }
173}
174
175// ---------------------------------------------------------------------------
176// Tests
177// ---------------------------------------------------------------------------
178
179#[cfg(test)]
180mod tests {
181    use super::*;
182
183    #[test]
184    fn test_bootstrap_stage_next() {
185        assert_eq!(BootstrapStage::Stage0.next(), Some(BootstrapStage::Stage1));
186        assert_eq!(BootstrapStage::Stage1.next(), Some(BootstrapStage::Stage2));
187        assert_eq!(BootstrapStage::Stage2.next(), None);
188    }
189
190    #[test]
191    fn test_default_config() {
192        let config = RustcBootstrapConfig::default();
193        assert_eq!(config.current_stage, BootstrapStage::Stage0);
194        assert!(config.target_triple.contains("veridian"));
195    }
196
197    #[test]
198    fn test_generate_config_toml() {
199        let config = RustcBootstrapConfig::default();
200        let toml = config.generate_config_toml();
201        assert!(toml.contains("[build]"));
202        assert!(toml.contains("[llvm]"));
203        assert!(toml.contains("[rust]"));
204        assert!(toml.contains("[install]"));
205        assert!(toml.contains("veridian"));
206    }
207
208    #[test]
209    fn test_build_command() {
210        let config = RustcBootstrapConfig::default();
211        let cmd = config.build_command(BootstrapStage::Stage1);
212        assert!(cmd.contains("--stage 1"));
213    }
214
215    #[test]
216    fn test_advance_stage() {
217        let mut config = RustcBootstrapConfig::default();
218        assert_eq!(config.current_stage, BootstrapStage::Stage0);
219        config.advance_stage().unwrap();
220        assert_eq!(config.current_stage, BootstrapStage::Stage1);
221        config.advance_stage().unwrap();
222        assert_eq!(config.current_stage, BootstrapStage::Stage2);
223        assert!(config.advance_stage().is_err());
224    }
225
226    #[test]
227    fn test_verify_rustc() {
228        let config = RustcBootstrapConfig::default();
229        assert!(config.verify_rustc("rustc 1.93.1 (abcdef 2026-01-01)"));
230        assert!(!config.verify_rustc("gcc 14.2.0"));
231    }
232
233    #[test]
234    fn test_reproducibility() {
235        let config = RustcBootstrapConfig::default();
236        let hash1 = [0xAB; 32];
237        let hash2 = [0xAB; 32];
238        let hash3 = [0xCD; 32];
239        assert!(config.check_reproducibility(&hash1, &hash2));
240        assert!(!config.check_reproducibility(&hash1, &hash3));
241    }
242
243    #[test]
244    fn test_rustdoc_config() {
245        let config = RustdocConfig::new("mylib", "/src/mylib");
246        assert_eq!(config.crate_name, "mylib");
247        assert!(config.output_dir.contains("target/doc"));
248    }
249
250    #[test]
251    fn test_rustdoc_command() {
252        let config = RustdocConfig::new("mylib", "/src/mylib");
253        let cmd = config.build_command();
254        assert!(cmd.contains("cargo doc"));
255    }
256
257    #[test]
258    fn test_rustdoc_features() {
259        let mut config = RustdocConfig::new("mylib", "/src/mylib");
260        config.features.push("alloc".to_string());
261        let cmd = config.build_command();
262        assert!(cmd.contains("--features alloc"));
263    }
264
265    #[test]
266    fn test_install_command() {
267        let config = RustcBootstrapConfig::default();
268        let cmd = config.install_command();
269        assert!(cmd.contains("x.py install"));
270    }
271}