Skip to main content

gaia_assembler/assembler/
mod.rs

1//! Gaia 统一编译器
2//!
3//! 提供统一的编译接口,支持编译到多个目标平台
4
5use crate::{backends::*, program::GaiaModule};
6use gaia_types::{helpers::CompilationTarget, GaiaErrorKind, *};
7
8/// Gaia 编译器
9pub struct GaiaAssembler {
10    backends: Vec<Box<dyn Backend>>,
11}
12
13impl GaiaAssembler {
14    /// 创建新的编译器实例,包含所有可用的后端
15    pub fn new() -> Self {
16        #[allow(unused_mut)]
17        let mut backends: Vec<Box<dyn Backend>> = vec![
18            Box::new(JvmBackend {}),
19            Box::new(PeBackend {}),
20            Box::new(WasiBackend {}),
21            Box::new(X86Backend {}),
22            Box::new(GcnBackend::new()),
23            Box::new(SassBackend::new()),
24        ];
25
26        #[cfg(feature = "clr")]
27        backends.push(Box::new(ClrBackend {}));
28
29        Self { backends }
30    }
31
32    /// 编译 Gaia 程序到指定目标
33    pub fn compile(&self, program: &GaiaModule, target: &CompilationTarget) -> Result<GeneratedFiles> {
34        // 优先按 host 精确选择后端,避免匹配度导致的误选
35        let mut best_backend: Option<&Box<dyn Backend>> = None;
36        let mut best_score = 0.0;
37
38        // 先尝试以 backend 的 primary_target 与传入 target 的 host 和 build 精确匹配
39        if let Some(candidate) = self.backends.iter().find(|b| {
40            let pt = b.primary_target();
41            pt.host == target.host && pt.build == target.build
42        }) {
43            best_backend = Some(candidate);
44            best_score = 100.0; // 精确匹配优先
45        }
46
47        // 若未找到精确匹配,则退回评分机制
48        if best_backend.is_none() {
49            for backend in &self.backends {
50                let score = backend.match_score(target);
51                if score > best_score {
52                    best_score = score;
53                    best_backend = Some(backend);
54                }
55            }
56        }
57
58        if best_backend.is_none() || best_score <= 0.0 {
59            return Err(GaiaErrorKind::UnsupportedTarget { target: target.clone() }.into());
60        }
61
62        // 创建配置并传递目标,以便后端依据 host/target 输出正确的文件类型
63        let mut config = crate::config::GaiaConfig::default();
64        config.target = target.clone();
65
66        // 使用选定的后端进行编译
67        best_backend.unwrap().generate(program, &config)
68    }
69
70    /// 获取所有可用的后端
71    pub fn backends(&self) -> &[Box<dyn Backend>] {
72        &self.backends
73    }
74}
75
76/// 编译到指定平台
77pub fn compile_to_platform(program: &GaiaModule, target: CompilationTarget) -> Result<Vec<u8>> {
78    let compiler = GaiaAssembler::new();
79    let generated_files = compiler.compile(program, &target)?;
80
81    // 从生成的文件中提取主要的二进制文件
82    // 通常第一个文件是主要的输出文件
83    if let Some((_, bytes)) = generated_files.files.iter().next() {
84        Ok(bytes.clone())
85    }
86    else {
87        Err(GaiaError::invalid_data("No output files generated"))
88    }
89}