cc/
target.rs

1//! Very basic parsing of `rustc` target triples.
2//!
3//! See the `target-lexicon` crate for a more principled approach to this.
4
5use std::str::FromStr;
6
7use crate::{Error, ErrorKind};
8
9mod apple;
10mod generated;
11mod llvm;
12mod parser;
13
14pub(crate) use parser::TargetInfoParser;
15
16/// Information specific to a `rustc` target.
17///
18/// See <https://doc.rust-lang.org/cargo/appendix/glossary.html#target>.
19#[derive(Debug, PartialEq, Clone)]
20pub(crate) struct TargetInfo<'a> {
21    /// The full architecture, including the subarchitecture.
22    ///
23    /// This differs from `cfg!(target_arch)`, which only specifies the
24    /// overall architecture, which is too coarse for certain cases.
25    pub full_arch: &'a str,
26    /// The overall target architecture.
27    ///
28    /// This is the same as the value of `cfg!(target_arch)`.
29    pub arch: &'a str,
30    /// The target vendor.
31    ///
32    /// This is the same as the value of `cfg!(target_vendor)`.
33    pub vendor: &'a str,
34    /// The operating system, or `none` on bare-metal targets.
35    ///
36    /// This is the same as the value of `cfg!(target_os)`.
37    pub os: &'a str,
38    /// The environment on top of the operating system.
39    ///
40    /// This is the same as the value of `cfg!(target_env)`.
41    pub env: &'a str,
42    /// The ABI on top of the operating system.
43    ///
44    /// This is the same as the value of `cfg!(target_abi)`.
45    pub abi: &'a str,
46    /// The unversioned LLVM/Clang target triple.
47    ///
48    /// NOTE: You should never need to match on this explicitly, use the other
49    /// fields on [`TargetInfo`] instead.
50    pub llvm_target: &'a str,
51}
52
53impl FromStr for TargetInfo<'_> {
54    type Err = Error;
55
56    /// This will fail when using a custom target triple unknown to `rustc`.
57    fn from_str(target_triple: &str) -> Result<Self, Error> {
58        if let Ok(index) =
59            generated::LIST.binary_search_by_key(&target_triple, |(target_triple, _)| target_triple)
60        {
61            let (_, info) = &generated::LIST[index];
62            Ok(info.clone())
63        } else {
64            Err(Error::new(
65                ErrorKind::UnknownTarget,
66                format!(
67                    "unknown target `{target_triple}`.
68
69NOTE: `cc-rs` only supports a fixed set of targets when not in a build script.
70- If adding a new target, you will need to fork of `cc-rs` until the target
71  has landed on nightly and the auto-generated list has been updated. See also
72  the `rustc` dev guide on adding a new target:
73  https://rustc-dev-guide.rust-lang.org/building/new-target.html
74- If using a custom target, prefer to upstream it to `rustc` if possible,
75  otherwise open an issue with `cc-rs`:
76  https://github.com/rust-lang/cc-rs/issues/new
77"
78                ),
79            ))
80        }
81    }
82}
83
84#[cfg(test)]
85mod tests {
86    use std::str::FromStr;
87
88    use super::TargetInfo;
89
90    // Test tier 1 targets
91    #[test]
92    fn tier1() {
93        let targets = [
94            "aarch64-unknown-linux-gnu",
95            "aarch64-apple-darwin",
96            "i686-pc-windows-gnu",
97            "i686-pc-windows-msvc",
98            "i686-unknown-linux-gnu",
99            "x86_64-apple-darwin",
100            "x86_64-pc-windows-gnu",
101            "x86_64-pc-windows-msvc",
102            "x86_64-unknown-linux-gnu",
103        ];
104
105        for target in targets {
106            // Check that it parses
107            let _ = TargetInfo::from_str(target).unwrap();
108        }
109    }
110
111    // Various custom target triples not (or no longer) known by `rustc`
112    #[test]
113    fn cannot_parse_extra() {
114        let targets = [
115            "aarch64-unknown-none-gnu",
116            "aarch64-uwp-windows-gnu",
117            "arm-frc-linux-gnueabi",
118            "arm-unknown-netbsd-eabi",
119            "armv7neon-unknown-linux-gnueabihf",
120            "armv7neon-unknown-linux-musleabihf",
121            "thumbv7-unknown-linux-gnueabihf",
122            "thumbv7-unknown-linux-musleabihf",
123            "x86_64-rumprun-netbsd",
124            "x86_64-unknown-linux",
125        ];
126
127        for target in targets {
128            // Check that it does not parse
129            let _ = TargetInfo::from_str(target).unwrap_err();
130        }
131    }
132}