1 //! Target detection
2 //!
3 //! This build script translates the target for which `radium` is being compiled
4 //! into a set of directives that the crate can use to control which atomic
5 //! symbols it attempts to name.
6 //!
7 //! The compiler maintains its store of target information here:
8 //! <https://github.com/rust-lang/rust/tree/be28b6235e64e0f662b96b710bf3af9de169215c/compiler/rustc_target/src/spec>
9 //!
10 //! That module is not easily extracted into something that can be loaded here,
11 //! so we are replicating it through string matching on the target name until
12 //! we are able to uniquely identify targets through `cfg` checks.
13 //!
14 //! Use `rustc --print target-list` to enumerate the full list of targets
15 //! available, and `rustc --print cfg` (optionally with `-Z unstable-options`)
16 //! to see what `cfg` values are produced for a target.
17 //!
18 //! The missing `cfg` checks required for conditional compilation, rather than a
19 //! build script, are:
20 //!
21 //! - [`accessible`](https://github.com/rust-lang/rust/issues/64797)
22 //! - [`target_feature`](https://github.com/rust-lang/rust/issues/69098)
23 //! - [`target_has_atomic`](https://github.com/rust-lang/rust/issues/32976)
24 //!
25 //! Once any of these becomes usable on the stable series, we can switch to a
26 //! set of `cfg` checks instead of a build script.
27
28 /// Collection of flags indicating whether the target processor supports atomic
29 /// instructions for a certain width.
30 #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
31 struct Atomics {
32 /// Target supports 8-bit atomics
33 has_8: bool,
34 /// Target supports 16-bit atomics
35 has_16: bool,
36 /// Target supports 32-bit atomics
37 has_32: bool,
38 /// Target supports 64-bit atomics
39 has_64: bool,
40 /// Target supports word-width atomics
41 has_ptr: bool,
42 }
43
44 impl Atomics {
45 const ALL: Self = Self {
46 has_8: true,
47 has_16: true,
48 has_32: true,
49 has_64: true,
50 has_ptr: true,
51 };
52 const NONE: Self = Self {
53 has_8: false,
54 has_16: false,
55 has_32: false,
56 has_64: false,
57 has_ptr: false,
58 };
59 }
60
main() -> Result<(), Box<dyn std::error::Error>>61 fn main() -> Result<(), Box<dyn std::error::Error>> {
62 let mut atomics = Atomics::ALL;
63
64 let target = std::env::var("TARGET")?;
65 // Add new target strings here with their atomic availability.
66 #[allow(clippy::match_single_binding, clippy::single_match)]
67 match &*target {
68 "arm-linux-androideabi" => atomics.has_64 = false,
69 _ => {}
70 }
71
72 let arch = target.split('-').next().ok_or("Invalid target triple")?;
73 // Add new architecture sections here with their atomic availability.
74 #[allow(clippy::match_single_binding, clippy::single_match)]
75 match arch {
76 // "riscv32imc-unknown-none-elf" and "riscv32imac-unknown-none-elf" are
77 // both `target_arch = "riscv32", and have no stable `cfg`-discoverable
78 // distinction. As such, the atomic RISC-V target must be discovered
79 // here.
80 "armv5te" | "mips" | "mipsel" | "powerpc" | "riscv32imac" | "thumbv7em" | "thumbv7m" => {
81 atomics.has_64 = false
82 }
83 "riscv32i" | "riscv32imc" | "thumbv6m" => atomics = Atomics::NONE,
84 _ => {}
85 }
86
87 if atomics.has_8 {
88 println!("cargo:rustc-cfg=radium_atomic_8");
89 }
90 if atomics.has_16 {
91 println!("cargo:rustc-cfg=radium_atomic_16");
92 }
93 if atomics.has_32 {
94 println!("cargo:rustc-cfg=radium_atomic_32");
95 }
96 if atomics.has_64 {
97 println!("cargo:rustc-cfg=radium_atomic_64");
98 }
99 if atomics.has_ptr {
100 println!("cargo:rustc-cfg=radium_atomic_ptr");
101 }
102
103 Ok(())
104 }
105