Skip to content

Commit a16d125

Browse files
authored
Merge pull request #66 from thejpster/arm-targets-updates
arm targets updates
2 parents f1d8ad3 + 369e22f commit a16d125

File tree

3 files changed

+247
-9
lines changed

3 files changed

+247
-9
lines changed

.github/workflows/build.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ jobs:
9999
run: |
100100
cd arm-targets
101101
cargo build
102+
cargo test
102103
103104
# Build the workspace for the target architecture but using nightly to compile libcore
104105
# Technically it doesn't need 'setup' but it makes the graph look nicer
@@ -198,6 +199,7 @@ jobs:
198199
run: |
199200
rustup install stable
200201
rustup default stable
202+
rustup component add rustfmt
201203
- name: Format
202204
run: |
203205
cargo fmt --check
@@ -212,6 +214,7 @@ jobs:
212214
run: |
213215
rustup install stable
214216
rustup default stable
217+
rustup component add rustfmt
215218
- name: Format
216219
run: |
217220
cd arm-targets

arm-targets/src/lib.rs

Lines changed: 232 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,75 @@
1-
//! Useful helpers when building Arm code
1+
//! Useful cfg helpers for when you are building Arm code
22
//!
3-
//! Hopefully Rust will stabilise these kinds of target features, and this won't
4-
//! be required.
3+
//! Hopefully Rust will stabilise these kinds of target features in the
4+
//! future, and this won't be required. But until this, arm-targets is here to
5+
//! help you conditionally compile your code based on the specific Arm
6+
//! platform you are compiling for.
7+
//!
8+
//! In your application, do something like this:
9+
//!
10+
//! ```console
11+
//! $ cargo add --build arm-targets
12+
//! $ cat > build.rs << EOF
13+
//! fn main() {
14+
//! arm_targets::process();
15+
//! }
16+
//! EOF
17+
//! ```
18+
//!
19+
//! This will then let you write application code like:
20+
//!
21+
//! ```rust
22+
//! #[cfg(arm_architecture = "armv7m")]
23+
//! fn only_for_cortex_m3() { }
24+
//!
25+
//! #[cfg(arm_isa = "a32")]
26+
//! fn can_use_arm_32bit_asm_here() { }
27+
//! ```
28+
//!
29+
//! Without this crate, you are limited to `cfg(target_arch = "arm")`, which
30+
//! isn't all that useful given how many 'Arm' targets there are.
31+
//!
32+
//! To see a full list of the features created by this crate, run the CLI tool:
33+
//!
34+
//! ```console
35+
//! $ cargo install arm-targets
36+
//! $ arm-targets
37+
//! cargo:rustc-check-cfg=cfg(arm_isa, values("a64", "a32", "t32"))
38+
//! cargo:rustc-check-cfg=cfg(arm_architecture, values("v4t", "v5te", "v6-m", "v7-m", "v7e-m", "v8-m.base", "v8-m.main", "v7-r", "v8-r", "v7-a", "v8-a"))
39+
//! cargo:rustc-check-cfg=cfg(arm_profile, values("a", "r", "m", "legacy"))
40+
//! cargo:rustc-check-cfg=cfg(arm_abi, values("eabi", "eabihf"))
41+
//! ```
42+
543
#[derive(Default)]
644
pub struct TargetInfo {
7-
profile: Option<Profile>,
8-
arch: Option<Arch>,
945
isa: Option<Isa>,
46+
arch: Option<Arch>,
47+
profile: Option<Profile>,
48+
abi: Option<Abi>,
1049
}
1150

1251
impl TargetInfo {
13-
pub fn profile(&self) -> Option<Profile> {
14-
self.profile
52+
/// Get the Arm Instruction Set Architecture of the target
53+
pub fn isa(&self) -> Option<Isa> {
54+
self.isa
1555
}
1656

57+
/// Get the Arm Architecture version of the target
1758
pub fn arch(&self) -> Option<Arch> {
1859
self.arch
1960
}
2061

21-
pub fn isa(&self) -> Option<Isa> {
22-
self.isa
62+
/// Get the Arm Architecture Profile of the target
63+
pub fn profile(&self) -> Option<Profile> {
64+
self.profile
65+
}
66+
67+
/// Get the ABI of the target
68+
pub fn abi(&self) -> Option<Abi> {
69+
self.abi
2370
}
2471
}
72+
2573
/// Process the ${TARGET} environment variable, and emit cargo configuration to
2674
/// standard out.
2775
pub fn process() -> TargetInfo {
@@ -58,6 +106,16 @@ pub fn process_target(target: &str) -> TargetInfo {
58106
r#"cargo:rustc-check-cfg=cfg(arm_profile, values({}))"#,
59107
Profile::values()
60108
);
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+
61119
target_info
62120
}
63121

@@ -273,3 +331,168 @@ impl core::fmt::Display for Profile {
273331
)
274332
}
275333
}
334+
335+
/// The ABI
336+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
337+
pub enum Abi {
338+
/// Arm Embedded ABI
339+
Eabi,
340+
/// Arm Embedded ABI with Hard Float
341+
EabiHf,
342+
}
343+
344+
impl Abi {
345+
/// Decode a target string
346+
pub fn get(target: &str) -> Option<Abi> {
347+
if Arch::get(target).is_none() {
348+
// Don't give an ABI for non-Arm targets
349+
//
350+
// e.g. PowerPC also has an ABI called EABI, but it's not the same
351+
return None;
352+
}
353+
if target.ends_with("-eabi") {
354+
Some(Abi::Eabi)
355+
} else if target.ends_with("-eabihf") {
356+
Some(Abi::EabiHf)
357+
} else {
358+
None
359+
}
360+
}
361+
362+
/// Get a comma-separated list of values, suitable for cfg-check
363+
pub fn values() -> String {
364+
let string_versions: Vec<String> = [Abi::Eabi, Abi::EabiHf]
365+
.iter()
366+
.map(|i| format!(r#""{i}""#))
367+
.collect();
368+
string_versions.join(", ")
369+
}
370+
}
371+
372+
impl core::fmt::Display for Abi {
373+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
374+
write!(
375+
f,
376+
"{}",
377+
match self {
378+
Abi::Eabi => "eabi",
379+
Abi::EabiHf => "eabihf",
380+
}
381+
)
382+
}
383+
}
384+
385+
#[cfg(test)]
386+
mod test {
387+
use super::*;
388+
389+
#[test]
390+
fn armv4t_none_eabi() {
391+
let target = "armv4t-none-eabi";
392+
let target_info = process_target(target);
393+
assert_eq!(target_info.isa(), Some(Isa::A32));
394+
assert_eq!(target_info.arch(), Some(Arch::Armv4T));
395+
assert_eq!(target_info.profile(), Some(Profile::Legacy));
396+
assert_eq!(target_info.abi(), Some(Abi::Eabi));
397+
}
398+
399+
#[test]
400+
fn armv5te_none_eabi() {
401+
let target = "armv5te-none-eabi";
402+
let target_info = process_target(target);
403+
assert_eq!(target_info.isa(), Some(Isa::A32));
404+
assert_eq!(target_info.arch(), Some(Arch::Armv5TE));
405+
assert_eq!(target_info.profile(), Some(Profile::Legacy));
406+
assert_eq!(target_info.abi(), Some(Abi::Eabi));
407+
}
408+
409+
#[test]
410+
fn thumbv6m_none_eabi() {
411+
let target = "thumbv6m-none-eabi";
412+
let target_info = process_target(target);
413+
assert_eq!(target_info.isa(), Some(Isa::T32));
414+
assert_eq!(target_info.arch(), Some(Arch::Armv6M));
415+
assert_eq!(target_info.profile(), Some(Profile::M));
416+
assert_eq!(target_info.abi(), Some(Abi::Eabi));
417+
}
418+
419+
#[test]
420+
fn thumbv7m_none_eabi() {
421+
let target = "thumbv7m-none-eabi";
422+
let target_info = process_target(target);
423+
assert_eq!(target_info.isa(), Some(Isa::T32));
424+
assert_eq!(target_info.arch(), Some(Arch::Armv7M));
425+
assert_eq!(target_info.profile(), Some(Profile::M));
426+
assert_eq!(target_info.abi(), Some(Abi::Eabi));
427+
}
428+
429+
#[test]
430+
fn thumbv7em_nuttx_eabihf() {
431+
let target = "thumbv7em-nuttx-eabihf";
432+
let target_info = process_target(target);
433+
assert_eq!(target_info.isa(), Some(Isa::T32));
434+
assert_eq!(target_info.arch(), Some(Arch::Armv7EM));
435+
assert_eq!(target_info.profile(), Some(Profile::M));
436+
assert_eq!(target_info.abi(), Some(Abi::EabiHf));
437+
}
438+
439+
#[test]
440+
fn thumbv8m_base_none_eabi() {
441+
let target = "thumbv8m.base-none-eabi";
442+
let target_info = process_target(target);
443+
assert_eq!(target_info.isa(), Some(Isa::T32));
444+
assert_eq!(target_info.arch(), Some(Arch::Armv8MBase));
445+
assert_eq!(target_info.profile(), Some(Profile::M));
446+
assert_eq!(target_info.abi(), Some(Abi::Eabi));
447+
}
448+
449+
#[test]
450+
fn thumbv8m_main_none_eabihf() {
451+
let target = "thumbv8m.main-none-eabihf";
452+
let target_info = process_target(target);
453+
assert_eq!(target_info.isa(), Some(Isa::T32));
454+
assert_eq!(target_info.arch(), Some(Arch::Armv8MMain));
455+
assert_eq!(target_info.profile(), Some(Profile::M));
456+
assert_eq!(target_info.abi(), Some(Abi::EabiHf));
457+
}
458+
459+
#[test]
460+
fn armv7r_none_eabi() {
461+
let target = "armv7r-none-eabi";
462+
let target_info = process_target(target);
463+
assert_eq!(target_info.isa(), Some(Isa::A32));
464+
assert_eq!(target_info.arch(), Some(Arch::Armv7R));
465+
assert_eq!(target_info.profile(), Some(Profile::R));
466+
assert_eq!(target_info.abi(), Some(Abi::Eabi));
467+
}
468+
469+
#[test]
470+
fn armv8r_none_eabihf() {
471+
let target = "armv8r-none-eabihf";
472+
let target_info = process_target(target);
473+
assert_eq!(target_info.isa(), Some(Isa::A32));
474+
assert_eq!(target_info.arch(), Some(Arch::Armv8R));
475+
assert_eq!(target_info.profile(), Some(Profile::R));
476+
assert_eq!(target_info.abi(), Some(Abi::EabiHf));
477+
}
478+
479+
#[test]
480+
fn armv7a_none_eabi() {
481+
let target = "armv7a-none-eabi";
482+
let target_info = process_target(target);
483+
assert_eq!(target_info.isa(), Some(Isa::A32));
484+
assert_eq!(target_info.arch(), Some(Arch::Armv7A));
485+
assert_eq!(target_info.profile(), Some(Profile::A));
486+
assert_eq!(target_info.abi(), Some(Abi::Eabi));
487+
}
488+
489+
#[test]
490+
fn aarch64_none_eabihf() {
491+
let target = "aarch64-unknown-none";
492+
let target_info = process_target(target);
493+
assert_eq!(target_info.isa(), Some(Isa::A64));
494+
assert_eq!(target_info.arch(), Some(Arch::Armv8A));
495+
assert_eq!(target_info.profile(), Some(Profile::A));
496+
assert_eq!(target_info.abi(), None);
497+
}
498+
}

arm-targets/src/main.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//! CLI tool for arm-targets
2+
3+
/// Entry point to the program
4+
fn main() {
5+
if let Some(target) = std::env::args().skip(1).next() {
6+
println!("// These are the features for the target '{}'", target);
7+
arm_targets::process_target(&target);
8+
} else {
9+
println!("// These are the features this crate enables:");
10+
arm_targets::process_target("");
11+
}
12+
}

0 commit comments

Comments
 (0)