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