1#[derive(Default)]
44pub struct TargetInfo {
45 isa: Option<Isa>,
46 arch: Option<Arch>,
47 profile: Option<Profile>,
48 abi: Option<Abi>,
49}
50
51impl TargetInfo {
52 pub fn isa(&self) -> Option<Isa> {
54 self.isa
55 }
56
57 pub fn arch(&self) -> Option<Arch> {
59 self.arch
60 }
61
62 pub fn profile(&self) -> Option<Profile> {
64 self.profile
65 }
66
67 pub fn abi(&self) -> Option<Abi> {
69 self.abi
70 }
71}
72
73pub fn process() -> TargetInfo {
76 let target = std::env::var("TARGET").expect("build script TARGET variable");
77 process_target(&target)
78}
79
80pub fn process_target(target: &str) -> TargetInfo {
82 let mut target_info = TargetInfo::default();
83 if let Some(isa) = Isa::get(target) {
84 println!(r#"cargo:rustc-cfg=arm_isa="{}""#, isa);
85 target_info.isa = Some(isa);
86 }
87 println!(
88 r#"cargo:rustc-check-cfg=cfg(arm_isa, values({}))"#,
89 Isa::values()
90 );
91
92 if let Some(arch) = Arch::get(target) {
93 println!(r#"cargo:rustc-cfg=arm_architecture="{}""#, arch);
94 target_info.arch = Some(arch);
95 }
96 println!(
97 r#"cargo:rustc-check-cfg=cfg(arm_architecture, values({}))"#,
98 Arch::values()
99 );
100
101 if let Some(profile) = Profile::get(target) {
102 println!(r#"cargo:rustc-cfg=arm_profile="{}""#, profile);
103 target_info.profile = Some(profile);
104 }
105 println!(
106 r#"cargo:rustc-check-cfg=cfg(arm_profile, values({}))"#,
107 Profile::values()
108 );
109
110 if let Some(abi) = Abi::get(target) {
111 println!(r#"cargo:rustc-cfg=arm_abi="{}""#, abi);
112 target_info.abi = Some(abi);
113 }
114 println!(
115 r#"cargo:rustc-check-cfg=cfg(arm_abi, values({}))"#,
116 Abi::values()
117 );
118
119 target_info
120}
121
122#[derive(Debug, Copy, Clone, PartialEq, Eq)]
124pub enum Isa {
125 A64,
127 A32,
129 T32,
131}
132
133impl Isa {
134 pub fn get(target: &str) -> Option<Isa> {
136 if target.starts_with("arm") {
137 Some(Isa::A32)
138 } else if target.starts_with("thumb") {
139 Some(Isa::T32)
140 } else if target.starts_with("aarch64") {
141 Some(Isa::A64)
142 } else {
143 None
144 }
145 }
146
147 pub fn values() -> String {
149 let string_versions: Vec<String> = [Isa::A64, Isa::A32, Isa::T32]
150 .iter()
151 .map(|i| format!(r#""{i}""#))
152 .collect();
153 string_versions.join(", ")
154 }
155}
156
157impl core::fmt::Display for Isa {
158 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
159 write!(
160 f,
161 "{}",
162 match self {
163 Isa::A64 => "a64",
164 Isa::A32 => "a32",
165 Isa::T32 => "t32",
166 }
167 )
168 }
169}
170
171#[derive(Debug, Copy, Clone, PartialEq, Eq)]
175pub enum Arch {
176 Armv4T,
178 Armv5TE,
180 Armv6,
182 Armv6M,
184 Armv7M,
186 Armv7EM,
188 Armv8MBase,
190 Armv8MMain,
192 Armv7R,
194 Armv8R,
196 Armv7A,
198 Armv8A,
200}
201
202impl Arch {
203 pub fn get(target: &str) -> Option<Arch> {
205 if target.starts_with("armv4t-") || target.starts_with("thumbv4t-") {
206 Some(Arch::Armv4T)
207 } else if target.starts_with("armv5te-") || target.starts_with("thumbv5te-") {
208 Some(Arch::Armv5TE)
209 } else if target.starts_with("thumbv6m-") {
210 Some(Arch::Armv6M)
211 } else if target.starts_with("thumbv7m-") {
212 Some(Arch::Armv7M)
213 } else if target.starts_with("thumbv7em-") {
214 Some(Arch::Armv7EM)
215 } else if target.starts_with("thumbv8m.base-") {
216 Some(Arch::Armv8MBase)
217 } else if target.starts_with("thumbv8m.main-") {
218 Some(Arch::Armv8MMain)
219 } else if target.starts_with("armv7r-") || target.starts_with("armebv7r") {
220 Some(Arch::Armv7R)
221 } else if target.starts_with("armv8r-") {
222 Some(Arch::Armv8R)
223 } else if target.starts_with("armv7a-") {
224 Some(Arch::Armv7A)
225 } else if target.starts_with("aarch64-") || target.starts_with("aarch64be-") {
226 Some(Arch::Armv8A)
227 } else if target.starts_with("arm-") {
228 Some(Arch::Armv6)
230 } else {
231 None
232 }
233 }
234
235 pub fn profile(&self) -> Profile {
237 match self {
238 Arch::Armv6M | Arch::Armv7M | Arch::Armv7EM | Arch::Armv8MBase | Arch::Armv8MMain => {
239 Profile::M
240 }
241 Arch::Armv4T | Arch::Armv5TE | Arch::Armv6 => Profile::Legacy,
242 Arch::Armv7R | Arch::Armv8R => Profile::R,
243 Arch::Armv7A | Arch::Armv8A => Profile::A,
244 }
245 }
246
247 pub fn values() -> String {
249 let string_versions: Vec<String> = [
250 Arch::Armv4T,
251 Arch::Armv5TE,
252 Arch::Armv6,
253 Arch::Armv6M,
254 Arch::Armv7M,
255 Arch::Armv7EM,
256 Arch::Armv8MBase,
257 Arch::Armv8MMain,
258 Arch::Armv7R,
259 Arch::Armv8R,
260 Arch::Armv7A,
261 Arch::Armv8A,
262 ]
263 .iter()
264 .map(|i| format!(r#""{i}""#))
265 .collect();
266 string_versions.join(", ")
267 }
268}
269
270impl core::fmt::Display for Arch {
271 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
272 write!(
273 f,
274 "{}",
275 match self {
276 Arch::Armv4T => "v4t",
277 Arch::Armv5TE => "v5te",
278 Arch::Armv6 => "v6",
279 Arch::Armv6M => "v6-m",
280 Arch::Armv7M => "v7-m",
281 Arch::Armv7EM => "v7e-m",
282 Arch::Armv7R => "v7-r",
283 Arch::Armv8R => "v8-r",
284 Arch::Armv8MBase => "v8-m.base",
285 Arch::Armv8MMain => "v8-m.main",
286 Arch::Armv7A => "v7-a",
287 Arch::Armv8A => "v8-a",
288 }
289 )
290 }
291}
292
293#[derive(Debug, Copy, Clone, PartialEq, Eq)]
295pub enum Profile {
296 M,
298 R,
300 A,
302 Legacy,
304}
305
306impl Profile {
307 pub fn get(target: &str) -> Option<Profile> {
309 let arch = Arch::get(target)?;
310 Some(arch.profile())
311 }
312
313 pub fn values() -> String {
315 let string_versions: Vec<String> = [Profile::A, Profile::R, Profile::M, Profile::Legacy]
316 .iter()
317 .map(|i| format!(r#""{i}""#))
318 .collect();
319 string_versions.join(", ")
320 }
321}
322
323impl core::fmt::Display for Profile {
324 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
325 write!(
326 f,
327 "{}",
328 match self {
329 Profile::M => "m",
330 Profile::R => "r",
331 Profile::A => "a",
332 Profile::Legacy => "legacy",
333 }
334 )
335 }
336}
337
338#[derive(Debug, Copy, Clone, PartialEq, Eq)]
340pub enum Abi {
341 Eabi,
343 EabiHf,
345}
346
347impl Abi {
348 pub fn get(target: &str) -> Option<Abi> {
350 if Arch::get(target).is_none() {
351 return None;
355 }
356 if target.ends_with("eabi") {
357 Some(Abi::Eabi)
358 } else if target.ends_with("eabihf") {
359 Some(Abi::EabiHf)
360 } else {
361 None
362 }
363 }
364
365 pub fn values() -> String {
367 let string_versions: Vec<String> = [Abi::Eabi, Abi::EabiHf]
368 .iter()
369 .map(|i| format!(r#""{i}""#))
370 .collect();
371 string_versions.join(", ")
372 }
373}
374
375impl core::fmt::Display for Abi {
376 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
377 write!(
378 f,
379 "{}",
380 match self {
381 Abi::Eabi => "eabi",
382 Abi::EabiHf => "eabihf",
383 }
384 )
385 }
386}
387
388#[cfg(test)]
389mod test {
390 use super::*;
391
392 #[test]
393 fn armv4t_none_eabi() {
394 let target = "armv4t-none-eabi";
395 let target_info = process_target(target);
396 assert_eq!(target_info.isa(), Some(Isa::A32));
397 assert_eq!(target_info.arch(), Some(Arch::Armv4T));
398 assert_eq!(target_info.profile(), Some(Profile::Legacy));
399 assert_eq!(target_info.abi(), Some(Abi::Eabi));
400 }
401
402 #[test]
403 fn armv5te_none_eabi() {
404 let target = "armv5te-none-eabi";
405 let target_info = process_target(target);
406 assert_eq!(target_info.isa(), Some(Isa::A32));
407 assert_eq!(target_info.arch(), Some(Arch::Armv5TE));
408 assert_eq!(target_info.profile(), Some(Profile::Legacy));
409 assert_eq!(target_info.abi(), Some(Abi::Eabi));
410 }
411
412 #[test]
413 fn arm_unknown_linux_gnueabi() {
414 let target = "arm-unknown-linux-gnueabi";
415 let target_info = process_target(target);
416 assert_eq!(target_info.isa(), Some(Isa::A32));
417 assert_eq!(target_info.arch(), Some(Arch::Armv6));
418 assert_eq!(target_info.profile(), Some(Profile::Legacy));
419 assert_eq!(target_info.abi(), Some(Abi::Eabi));
420 }
421
422 #[test]
423 fn thumbv6m_none_eabi() {
424 let target = "thumbv6m-none-eabi";
425 let target_info = process_target(target);
426 assert_eq!(target_info.isa(), Some(Isa::T32));
427 assert_eq!(target_info.arch(), Some(Arch::Armv6M));
428 assert_eq!(target_info.profile(), Some(Profile::M));
429 assert_eq!(target_info.abi(), Some(Abi::Eabi));
430 }
431
432 #[test]
433 fn thumbv7m_none_eabi() {
434 let target = "thumbv7m-none-eabi";
435 let target_info = process_target(target);
436 assert_eq!(target_info.isa(), Some(Isa::T32));
437 assert_eq!(target_info.arch(), Some(Arch::Armv7M));
438 assert_eq!(target_info.profile(), Some(Profile::M));
439 assert_eq!(target_info.abi(), Some(Abi::Eabi));
440 }
441
442 #[test]
443 fn thumbv7em_nuttx_eabihf() {
444 let target = "thumbv7em-nuttx-eabihf";
445 let target_info = process_target(target);
446 assert_eq!(target_info.isa(), Some(Isa::T32));
447 assert_eq!(target_info.arch(), Some(Arch::Armv7EM));
448 assert_eq!(target_info.profile(), Some(Profile::M));
449 assert_eq!(target_info.abi(), Some(Abi::EabiHf));
450 }
451
452 #[test]
453 fn thumbv8m_base_none_eabi() {
454 let target = "thumbv8m.base-none-eabi";
455 let target_info = process_target(target);
456 assert_eq!(target_info.isa(), Some(Isa::T32));
457 assert_eq!(target_info.arch(), Some(Arch::Armv8MBase));
458 assert_eq!(target_info.profile(), Some(Profile::M));
459 assert_eq!(target_info.abi(), Some(Abi::Eabi));
460 }
461
462 #[test]
463 fn thumbv8m_main_none_eabihf() {
464 let target = "thumbv8m.main-none-eabihf";
465 let target_info = process_target(target);
466 assert_eq!(target_info.isa(), Some(Isa::T32));
467 assert_eq!(target_info.arch(), Some(Arch::Armv8MMain));
468 assert_eq!(target_info.profile(), Some(Profile::M));
469 assert_eq!(target_info.abi(), Some(Abi::EabiHf));
470 }
471
472 #[test]
473 fn armv7r_none_eabi() {
474 let target = "armv7r-none-eabi";
475 let target_info = process_target(target);
476 assert_eq!(target_info.isa(), Some(Isa::A32));
477 assert_eq!(target_info.arch(), Some(Arch::Armv7R));
478 assert_eq!(target_info.profile(), Some(Profile::R));
479 assert_eq!(target_info.abi(), Some(Abi::Eabi));
480 }
481
482 #[test]
483 fn armv8r_none_eabihf() {
484 let target = "armv8r-none-eabihf";
485 let target_info = process_target(target);
486 assert_eq!(target_info.isa(), Some(Isa::A32));
487 assert_eq!(target_info.arch(), Some(Arch::Armv8R));
488 assert_eq!(target_info.profile(), Some(Profile::R));
489 assert_eq!(target_info.abi(), Some(Abi::EabiHf));
490 }
491
492 #[test]
493 fn armv7a_none_eabi() {
494 let target = "armv7a-none-eabi";
495 let target_info = process_target(target);
496 assert_eq!(target_info.isa(), Some(Isa::A32));
497 assert_eq!(target_info.arch(), Some(Arch::Armv7A));
498 assert_eq!(target_info.profile(), Some(Profile::A));
499 assert_eq!(target_info.abi(), Some(Abi::Eabi));
500 }
501
502 #[test]
503 fn aarch64_none_eabihf() {
504 let target = "aarch64-unknown-none";
505 let target_info = process_target(target);
506 assert_eq!(target_info.isa(), Some(Isa::A64));
507 assert_eq!(target_info.arch(), Some(Arch::Armv8A));
508 assert_eq!(target_info.profile(), Some(Profile::A));
509 assert_eq!(target_info.abi(), None);
510 }
511}