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