cabin_core/compiler/
validation.rs1use std::collections::BTreeSet;
4
5use thiserror::Error;
6
7use super::capabilities::{
8 ArchiverCapabilities, CompilerCapabilities, c_standard_capability, cxx_standard_capability,
9 standard_support_detail,
10};
11use super::identity::{ArchiverIdentity, ArchiverKind, CompilerIdentity, CompilerKind};
12use crate::language_standard::{CStandard, CxxStandard};
13
14#[derive(Debug, Error, Clone, PartialEq, Eq)]
17pub enum ToolDetectionError {
18 #[error("selected C++ compiler `{spec}` cannot be matched to a supported C++ backend")]
19 UnsupportedCxxBackend { spec: String },
20
21 #[error(
22 "selected C++ compiler `{spec}` could not be identified and the current backend requires GCC-style flags"
23 )]
24 UnknownCxxRequiresGccStyle { spec: String },
25
26 #[error(
27 "selected C++ compiler `{spec}` ({kind}) does not support the requested C++ standard `{standard}`: {detail}"
28 )]
29 CxxLacksStandard {
30 spec: String,
31 kind: CompilerKind,
32 standard: CxxStandard,
33 detail: String,
34 },
35
36 #[error(
37 "selected C++ compiler `{spec}` ({kind}) does not support the depfile flags required by the Ninja backend"
38 )]
39 CxxLacksDepfile { spec: String, kind: CompilerKind },
40
41 #[error("selected C compiler `{spec}` cannot be matched to a supported C backend")]
42 UnsupportedCBackend { spec: String },
43
44 #[error(
45 "selected C compiler `{spec}` could not be identified and the current backend requires GCC-style flags"
46 )]
47 UnknownCRequiresGccStyle { spec: String },
48
49 #[error(
50 "selected C compiler `{spec}` ({kind}) does not support the depfile flags required by the Ninja backend"
51 )]
52 CLacksDepfile { spec: String, kind: CompilerKind },
53
54 #[error(
55 "selected C compiler `{spec}` ({kind}) does not support the requested C standard `{standard}`: {detail}"
56 )]
57 CLacksStandard {
58 spec: String,
59 kind: CompilerKind,
60 standard: CStandard,
61 detail: String,
62 },
63
64 #[error("selected archiver `{spec}` is not supported by the static-library backend")]
65 UnsupportedArchiver { spec: String },
66
67 #[error(
68 "selected archiver `{spec}` could not be identified and the current backend requires `ar crs`-compatible behavior"
69 )]
70 UnknownArchiverRequiresArCompatible { spec: String },
71}
72
73pub fn validate_cxx_for_backend(
91 spec_display: &str,
92 identity: &CompilerIdentity,
93 capabilities: &CompilerCapabilities,
94) -> Result<(), ToolDetectionError> {
95 if identity.kind.speaks_msvc_dialect() {
98 if !capabilities.msvc_style_flags.supported {
99 return Err(ToolDetectionError::UnsupportedCxxBackend {
100 spec: spec_display.to_owned(),
101 });
102 }
103 return Ok(());
104 }
105 if !capabilities.gcc_style_flags.supported {
106 if identity.kind == CompilerKind::Unknown {
107 return Err(ToolDetectionError::UnknownCxxRequiresGccStyle {
108 spec: spec_display.to_owned(),
109 });
110 }
111 return Err(ToolDetectionError::UnsupportedCxxBackend {
112 spec: spec_display.to_owned(),
113 });
114 }
115 if !capabilities.depfile_mmd_mf.supported {
116 return Err(ToolDetectionError::CxxLacksDepfile {
117 spec: spec_display.to_owned(),
118 kind: identity.kind,
119 });
120 }
121 Ok(())
122}
123
124pub fn validate_cxx_standards(
133 spec_display: &str,
134 identity: &CompilerIdentity,
135 requested: &BTreeSet<CxxStandard>,
136) -> Result<(), ToolDetectionError> {
137 for &standard in requested {
138 let capability = cxx_standard_capability(identity, standard);
139 if !capability.supported {
140 return Err(ToolDetectionError::CxxLacksStandard {
141 spec: spec_display.to_owned(),
142 kind: identity.kind,
143 standard,
144 detail: standard_support_detail(capability, identity.kind),
145 });
146 }
147 }
148 Ok(())
149}
150
151pub fn validate_c_standards(
157 spec_display: &str,
158 identity: &CompilerIdentity,
159 requested: &BTreeSet<CStandard>,
160) -> Result<(), ToolDetectionError> {
161 for &standard in requested {
162 let capability = c_standard_capability(identity, standard);
163 if !capability.supported {
164 return Err(ToolDetectionError::CLacksStandard {
165 spec: spec_display.to_owned(),
166 kind: identity.kind,
167 standard,
168 detail: standard_support_detail(capability, identity.kind),
169 });
170 }
171 }
172 Ok(())
173}
174
175pub fn validate_cc_for_backend(
189 spec_display: &str,
190 identity: &CompilerIdentity,
191 capabilities: &CompilerCapabilities,
192) -> Result<(), ToolDetectionError> {
193 if identity.kind.speaks_msvc_dialect() {
198 if !capabilities.msvc_style_flags.supported {
199 return Err(ToolDetectionError::UnsupportedCBackend {
200 spec: spec_display.to_owned(),
201 });
202 }
203 return Ok(());
204 }
205 if !capabilities.gcc_style_flags.supported {
206 if identity.kind == CompilerKind::Unknown {
207 return Err(ToolDetectionError::UnknownCRequiresGccStyle {
208 spec: spec_display.to_owned(),
209 });
210 }
211 return Err(ToolDetectionError::UnsupportedCBackend {
212 spec: spec_display.to_owned(),
213 });
214 }
215 if !capabilities.depfile_mmd_mf.supported {
216 return Err(ToolDetectionError::CLacksDepfile {
217 spec: spec_display.to_owned(),
218 kind: identity.kind,
219 });
220 }
221 Ok(())
222}
223
224pub fn validate_ar_for_backend(
235 spec_display: &str,
236 identity: &ArchiverIdentity,
237 capabilities: &ArchiverCapabilities,
238) -> Result<(), ToolDetectionError> {
239 if identity.kind == ArchiverKind::Lib {
242 return Ok(());
243 }
244 if !capabilities.ar_crs.supported {
245 if identity.kind == ArchiverKind::Unknown {
246 return Err(ToolDetectionError::UnknownArchiverRequiresArCompatible {
247 spec: spec_display.to_owned(),
248 });
249 }
250 return Err(ToolDetectionError::UnsupportedArchiver {
251 spec: spec_display.to_owned(),
252 });
253 }
254 Ok(())
255}