| 1 | //! Very basic parsing of `rustc` target triples. |
| 2 | //! |
| 3 | //! See the `target-lexicon` crate for a more principled approach to this. |
| 4 | |
| 5 | use std::str::FromStr; |
| 6 | |
| 7 | use crate::{Error, ErrorKind}; |
| 8 | |
| 9 | mod apple; |
| 10 | mod generated; |
| 11 | mod llvm; |
| 12 | mod parser; |
| 13 | |
| 14 | pub(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)] |
| 20 | pub(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 | |
| 53 | impl 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 | |
| 69 | NOTE: `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)] |
| 85 | mod 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 | |