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}
133