veridian_kernel/pkg/ports/
rustc_bootstrap.rs1use alloc::{
8 string::{String, ToString},
9 vec::Vec,
10};
11
12use crate::error::KernelError;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum BootstrapStage {
17 Stage0,
19 Stage1,
21 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#[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 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 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 pub fn install_command(&self) -> String {
119 "python3 x.py install".to_string()
120 }
121
122 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 pub fn verify_rustc(&self, version_output: &str) -> bool {
138 version_output.contains("rustc") && version_output.contains(&self.rustc_version)
139 }
140
141 pub fn check_reproducibility(&self, stage1_hash: &[u8; 32], stage2_hash: &[u8; 32]) -> bool {
143 stage1_hash == stage2_hash
144 }
145}
146
147#[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#[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}