cabin_core/compiler/
capabilities.rs1use serde::{Deserialize, Serialize};
4
5use super::identity::{
6 ArchiverIdentity, ArchiverKind, CompilerIdentity, CompilerKind, CompilerVersion,
7};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
13#[serde(rename_all = "kebab-case")]
14pub enum CapabilitySource {
15 Version,
17 AssumedDefault,
20 Unsupported,
23}
24
25impl CapabilitySource {
26 pub fn as_key(self) -> &'static str {
27 match self {
28 CapabilitySource::Version => "version",
29 CapabilitySource::AssumedDefault => "assumed-default",
30 CapabilitySource::Unsupported => "unsupported",
31 }
32 }
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
38pub struct Capability {
39 pub supported: bool,
40 pub source: CapabilitySource,
41}
42
43impl Capability {
44 pub fn supported_from(source: CapabilitySource) -> Self {
45 Self {
46 supported: true,
47 source,
48 }
49 }
50 pub fn unsupported_from(source: CapabilitySource) -> Self {
51 Self {
52 supported: false,
53 source,
54 }
55 }
56}
57
58#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
62pub struct CompilerCapabilities {
63 pub gcc_style_flags: Capability,
65 pub msvc_style_flags: Capability,
68 pub depfile_mmd_mf: Capability,
70 pub std_flag: Capability,
72 pub cxx_standard_17: Capability,
75 pub c_standard_11: Capability,
79}
80
81#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
83pub struct ArchiverCapabilities {
84 pub ar_crs: Capability,
86 pub static_library_output: Capability,
88}
89
90fn msvc_versioned_capability(
103 version: Option<&CompilerVersion>,
104 min_major: u32,
105 min_minor: u32,
106) -> Capability {
107 match version.map(|v| (v.major, v.minor.unwrap_or(0))) {
108 Some((major, minor)) if major > min_major || (major == min_major && minor >= min_minor) => {
109 Capability::supported_from(CapabilitySource::Version)
110 }
111 Some(_) => Capability::unsupported_from(CapabilitySource::Version),
112 None => Capability::supported_from(CapabilitySource::AssumedDefault),
113 }
114}
115
116pub fn derive_cxx_capabilities(identity: &CompilerIdentity) -> CompilerCapabilities {
117 let gcc_style = if identity.kind.supports_gcc_style_command_line() {
118 Capability::supported_from(CapabilitySource::Version)
119 } else if identity.kind.speaks_msvc_dialect() {
120 Capability::unsupported_from(CapabilitySource::Unsupported)
121 } else {
122 Capability::unsupported_from(CapabilitySource::AssumedDefault)
123 };
124 let msvc_style = if identity.kind.speaks_msvc_dialect() {
125 Capability::supported_from(CapabilitySource::Version)
126 } else {
127 Capability::unsupported_from(CapabilitySource::AssumedDefault)
128 };
129 let depfile_mmd_mf = if identity.kind.supports_gcc_style_command_line() {
130 Capability::supported_from(CapabilitySource::Version)
131 } else if identity.kind.speaks_msvc_dialect() {
132 Capability::unsupported_from(CapabilitySource::Unsupported)
135 } else {
136 Capability::unsupported_from(CapabilitySource::AssumedDefault)
137 };
138 let std_flag = if identity.kind.supports_gcc_style_command_line() {
139 Capability::supported_from(CapabilitySource::Version)
140 } else if identity.kind.speaks_msvc_dialect() {
141 Capability::unsupported_from(CapabilitySource::Unsupported)
142 } else {
143 Capability::unsupported_from(CapabilitySource::AssumedDefault)
144 };
145 let cxx_standard_17 = match identity.kind {
151 CompilerKind::Clang | CompilerKind::AppleClang | CompilerKind::ClangCl => {
152 Capability::supported_from(CapabilitySource::Version)
153 }
154 CompilerKind::Gcc => match identity.version.as_ref().map(|v| v.major) {
155 Some(m) if m >= 5 => Capability::supported_from(CapabilitySource::Version),
156 Some(_) => Capability::unsupported_from(CapabilitySource::Version),
157 None => Capability::supported_from(CapabilitySource::AssumedDefault),
158 },
159 CompilerKind::Msvc => msvc_versioned_capability(identity.version.as_ref(), 19, 11),
161 CompilerKind::Unknown => Capability::unsupported_from(CapabilitySource::AssumedDefault),
162 };
163 let c_standard_11 = match identity.kind {
168 CompilerKind::Clang
169 | CompilerKind::AppleClang
170 | CompilerKind::ClangCl
171 | CompilerKind::Gcc => Capability::supported_from(CapabilitySource::Version),
172 CompilerKind::Msvc => msvc_versioned_capability(identity.version.as_ref(), 19, 28),
173 CompilerKind::Unknown => Capability::unsupported_from(CapabilitySource::AssumedDefault),
174 };
175
176 CompilerCapabilities {
177 gcc_style_flags: gcc_style,
178 msvc_style_flags: msvc_style,
179 depfile_mmd_mf,
180 std_flag,
181 cxx_standard_17,
182 c_standard_11,
183 }
184}
185
186pub fn derive_ar_capabilities(identity: &ArchiverIdentity) -> ArchiverCapabilities {
189 let ar_crs = if identity.kind.supports_ar_crs() {
190 Capability::supported_from(CapabilitySource::Version)
191 } else if identity.kind == ArchiverKind::Lib {
192 Capability::unsupported_from(CapabilitySource::Unsupported)
193 } else {
194 Capability::unsupported_from(CapabilitySource::AssumedDefault)
195 };
196 let static_library_output = if identity.kind.produces_static_library() {
201 Capability::supported_from(CapabilitySource::Version)
202 } else {
203 Capability::unsupported_from(CapabilitySource::AssumedDefault)
204 };
205 ArchiverCapabilities {
206 ar_crs,
207 static_library_output,
208 }
209}