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

veridian_kernel/pkg/ports/
llvm.rs

1//! LLVM Native Build Port
2//!
3//! Portfile for building LLVM 19 natively on VeridianOS. Handles CMake
4//! configuration, memory validation, single-threaded linking, and
5//! installation to the system toolchain directory.
6
7use alloc::{
8    string::{String, ToString},
9    vec,
10    vec::Vec,
11};
12
13use crate::{
14    error::KernelError,
15    pkg::{build_system::BuildConfig, ports::BuildType},
16};
17
18/// LLVM version
19pub const LLVM_VERSION: &str = "19.1.0";
20
21/// Minimum memory required for LLVM build (4GB)
22pub const LLVM_MIN_MEMORY_MB: u64 = 4096;
23
24/// LLVM build configuration
25pub struct LlvmPortConfig {
26    pub version: String,
27    pub targets: Vec<String>,
28    pub enable_assertions: bool,
29    pub single_threaded_link: bool,
30    pub build_type: String,
31    pub install_prefix: String,
32}
33
34impl Default for LlvmPortConfig {
35    fn default() -> Self {
36        Self {
37            version: LLVM_VERSION.to_string(),
38            targets: vec![
39                "X86".to_string(),
40                "AArch64".to_string(),
41                "RISCV".to_string(),
42            ],
43            enable_assertions: false,
44            single_threaded_link: true,
45            build_type: "Release".to_string(),
46            install_prefix: "/usr/local".to_string(),
47        }
48    }
49}
50
51impl LlvmPortConfig {
52    /// Generate CMake arguments
53    pub fn cmake_args(&self) -> Vec<String> {
54        let mut args = Vec::new();
55
56        args.push(alloc::format!(
57            "-DCMAKE_INSTALL_PREFIX={}",
58            self.install_prefix
59        ));
60        args.push(alloc::format!("-DCMAKE_BUILD_TYPE={}", self.build_type));
61        args.push(alloc::format!(
62            "-DLLVM_TARGETS_TO_BUILD={}",
63            self.targets.join(";")
64        ));
65
66        if self.enable_assertions {
67            args.push("-DLLVM_ENABLE_ASSERTIONS=ON".to_string());
68        } else {
69            args.push("-DLLVM_ENABLE_ASSERTIONS=OFF".to_string());
70        }
71
72        // Optimize TableGen for faster builds
73        args.push("-DLLVM_OPTIMIZED_TABLEGEN=ON".to_string());
74
75        // Single-threaded link to reduce memory usage
76        if self.single_threaded_link {
77            args.push("-DLLVM_PARALLEL_LINK_JOBS=1".to_string());
78        }
79
80        // Disable unused projects
81        args.push("-DLLVM_ENABLE_PROJECTS=clang;lld".to_string());
82        args.push("-DLLVM_ENABLE_RUNTIMES=".to_string());
83
84        // Use lld for faster linking
85        args.push("-DLLVM_USE_LINKER=lld".to_string());
86
87        // Minimize build size
88        args.push("-DLLVM_BUILD_DOCS=OFF".to_string());
89        args.push("-DLLVM_BUILD_TESTS=OFF".to_string());
90        args.push("-DLLVM_INCLUDE_TESTS=OFF".to_string());
91        args.push("-DLLVM_INCLUDE_EXAMPLES=OFF".to_string());
92        args.push("-DLLVM_INCLUDE_BENCHMARKS=OFF".to_string());
93
94        args
95    }
96
97    /// Generate BuildConfig for the build orchestrator
98    pub fn to_build_config(&self) -> BuildConfig {
99        let mut config = BuildConfig::new("llvm", &self.version);
100        config.source_url = alloc::format!(
101            "https://github.com/llvm/llvm-project/releases/download/llvmorg-{}/llvm-project-{}.src.tar.xz",
102            self.version, self.version
103        );
104        config.build_type = BuildType::CMake;
105        config.configure_flags = self.cmake_args();
106        config.install_prefix = self.install_prefix.clone();
107        config
108    }
109
110    /// Validate system has enough resources
111    pub fn validate_resources(&self, available_memory_mb: u64) -> Result<(), KernelError> {
112        if available_memory_mb < LLVM_MIN_MEMORY_MB {
113            return Err(KernelError::OutOfMemory {
114                requested: LLVM_MIN_MEMORY_MB as usize,
115                available: available_memory_mb as usize,
116            });
117        }
118        Ok(())
119    }
120}
121
122// ---------------------------------------------------------------------------
123// Tests
124// ---------------------------------------------------------------------------
125
126#[cfg(test)]
127mod tests {
128    use super::*;
129
130    #[test]
131    fn test_default_config() {
132        let config = LlvmPortConfig::default();
133        assert_eq!(config.version, LLVM_VERSION);
134        assert!(config.targets.contains(&"X86".to_string()));
135        assert!(config.single_threaded_link);
136    }
137
138    #[test]
139    fn test_cmake_args() {
140        let config = LlvmPortConfig::default();
141        let args = config.cmake_args();
142        assert!(args.iter().any(|a| a.contains("CMAKE_INSTALL_PREFIX")));
143        assert!(args.iter().any(|a| a.contains("LLVM_TARGETS_TO_BUILD")));
144        assert!(args.iter().any(|a| a.contains("OPTIMIZED_TABLEGEN")));
145    }
146
147    #[test]
148    fn test_cmake_args_assertions() {
149        let mut config = LlvmPortConfig::default();
150        config.enable_assertions = true;
151        let args = config.cmake_args();
152        assert!(args.iter().any(|a| a == "-DLLVM_ENABLE_ASSERTIONS=ON"));
153    }
154
155    #[test]
156    fn test_to_build_config() {
157        let config = LlvmPortConfig::default();
158        let build = config.to_build_config();
159        assert_eq!(build.name, "llvm");
160        assert_eq!(build.build_type, BuildType::CMake);
161        assert!(build.source_url.contains("llvm-project"));
162    }
163
164    #[test]
165    fn test_validate_resources_ok() {
166        let config = LlvmPortConfig::default();
167        assert!(config.validate_resources(8192).is_ok());
168    }
169
170    #[test]
171    fn test_validate_resources_oom() {
172        let config = LlvmPortConfig::default();
173        assert!(config.validate_resources(2048).is_err());
174    }
175
176    #[test]
177    fn test_version() {
178        assert!(!LLVM_VERSION.is_empty());
179    }
180
181    #[test]
182    fn test_min_memory() {
183        assert!(LLVM_MIN_MEMORY_MB >= 4096);
184    }
185}