Skip to main content

crossbuild_core/
registry.rs

1use std::collections::BTreeMap;
2use std::sync::Arc;
3
4use crate::error::CrossBuildError;
5use crate::model::{BuildRequest, HostInfo, TargetTriple};
6use crate::provider::{
7    LinkerProvider, LinkerResolution, SysrootProvider, SysrootResolution, ToolchainProvider,
8    ToolchainResolution,
9};
10
11/// Registry of all providers.
12#[derive(Default)]
13pub struct ProviderRegistry {
14    toolchain_providers: Vec<Arc<dyn ToolchainProvider>>,
15    sysroot_providers: Vec<Arc<dyn SysrootProvider>>,
16    linker_providers: Vec<Arc<dyn LinkerProvider>>,
17}
18
19impl std::fmt::Debug for ProviderRegistry {
20    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21        f.debug_struct("ProviderRegistry")
22            .field("toolchain_providers", &self.toolchain_provider_names())
23            .field("sysroot_providers", &self.sysroot_provider_names())
24            .field("linker_providers", &self.linker_provider_names())
25            .finish()
26    }
27}
28
29impl ProviderRegistry {
30    /// Creates a new empty registry.
31    pub fn new() -> Self {
32        Self {
33            toolchain_providers: Vec::new(),
34            sysroot_providers: Vec::new(),
35            linker_providers: Vec::new(),
36        }
37    }
38
39    /// Registers a toolchain provider.
40    pub fn register_toolchain(&mut self, provider: Box<dyn ToolchainProvider>) {
41        self.toolchain_providers.push(Arc::from(provider));
42        self.toolchain_providers.sort_by_key(|p| -p.priority());
43    }
44
45    /// Registers a sysroot provider.
46    pub fn register_sysroot(&mut self, provider: Box<dyn SysrootProvider>) {
47        self.sysroot_providers.push(Arc::from(provider));
48        self.sysroot_providers.sort_by_key(|p| -p.priority());
49    }
50
51    /// Registers a linker provider.
52    pub fn register_linker(&mut self, provider: Box<dyn LinkerProvider>) {
53        self.linker_providers.push(Arc::from(provider));
54        self.linker_providers.sort_by_key(|p| -p.priority());
55    }
56
57    /// Resolves the best toolchain provider for a target.
58    pub fn resolve_toolchain(
59        &self,
60        target: &TargetTriple,
61        host: &HostInfo,
62        request: &BuildRequest,
63    ) -> Result<ToolchainResolution, CrossBuildError> {
64        for provider in &self.toolchain_providers {
65            if provider.can_provide(target, host) {
66                return provider.resolve(target, host, request);
67            }
68        }
69
70        Err(CrossBuildError::ProviderNotFound {
71            provider_type: "toolchain".to_string(),
72            target: target.triple.clone(),
73        })
74    }
75
76    /// Resolves the best sysroot provider for a target.
77    pub fn resolve_sysroot(
78        &self,
79        target: &TargetTriple,
80        host: &HostInfo,
81        request: &BuildRequest,
82    ) -> Result<Option<SysrootResolution>, CrossBuildError> {
83        for provider in &self.sysroot_providers {
84            if provider.can_provide(target, host) {
85                let res = provider.resolve(target, host, request);
86                match res {
87                    Ok(resolution) => return Ok(Some(resolution)),
88                    Err(CrossBuildError::SysrootNotNeeded) => return Ok(None),
89                    Err(e) => return Err(e),
90                }
91            }
92        }
93        Ok(None)
94    }
95
96    /// Resolves the best linker provider for a target.
97    pub fn resolve_linker(
98        &self,
99        target: &TargetTriple,
100        host: &HostInfo,
101        request: &BuildRequest,
102    ) -> Result<LinkerResolution, CrossBuildError> {
103        for provider in &self.linker_providers {
104            if provider.can_provide(target, host) {
105                return provider.resolve(target, host, request);
106            }
107        }
108
109        Err(CrossBuildError::ProviderNotFound {
110            provider_type: "linker".to_string(),
111            target: target.triple.clone(),
112        })
113    }
114
115    /// Returns names of registered toolchain providers.
116    pub fn toolchain_provider_names(&self) -> Vec<&str> {
117        self.toolchain_providers.iter().map(|p| p.name()).collect()
118    }
119
120    /// Returns names of registered sysroot providers.
121    pub fn sysroot_provider_names(&self) -> Vec<&str> {
122        self.sysroot_providers.iter().map(|p| p.name()).collect()
123    }
124
125    /// Returns names of registered linker providers.
126    pub fn linker_provider_names(&self) -> Vec<&str> {
127        self.linker_providers.iter().map(|p| p.name()).collect()
128    }
129
130    /// Gets a toolchain provider by name.
131    pub fn get_toolchain_provider(&self, name: &str) -> Option<&Arc<dyn ToolchainProvider>> {
132        self.toolchain_providers.iter().find(|p| p.name() == name)
133    }
134
135    /// Gets a sysroot provider by name.
136    pub fn get_sysroot_provider(&self, name: &str) -> Option<&Arc<dyn SysrootProvider>> {
137        self.sysroot_providers.iter().find(|p| p.name() == name)
138    }
139
140    /// Gets a linker provider by name.
141    pub fn get_linker_provider(&self, name: &str) -> Option<&Arc<dyn LinkerProvider>> {
142        self.linker_providers.iter().find(|p| p.name() == name)
143    }
144
145    /// Resolves all providers for a target and returns a complete resolution.
146    pub fn resolve_all(
147        &self,
148        target: &TargetTriple,
149        host: &HostInfo,
150        request: &BuildRequest,
151    ) -> Result<CompleteResolution, CrossBuildError> {
152        let toolchain = self.resolve_toolchain(target, host, request)?;
153        let sysroot = self.resolve_sysroot(target, host, request)?;
154        let linker = self.resolve_linker(target, host, request)?;
155
156        Ok(CompleteResolution {
157            toolchain,
158            sysroot,
159            linker,
160        })
161    }
162}
163
164/// Complete resolution from all providers.
165#[derive(Debug, Clone)]
166pub struct CompleteResolution {
167    pub toolchain: ToolchainResolution,
168    pub sysroot: Option<SysrootResolution>,
169    pub linker: LinkerResolution,
170}
171
172impl CompleteResolution {
173    /// Returns the merged environment variables from all providers.
174    pub fn merged_env(&self) -> BTreeMap<String, String> {
175        let mut env = BTreeMap::new();
176        env.extend(self.toolchain.env.clone());
177        env.extend(self.linker.env.clone());
178        if let Some(ref sysroot) = self.sysroot {
179            env.extend(sysroot.env.clone());
180        }
181        env
182    }
183}