| 1 | //! [Flexible target specification.](https://github.com/rust-lang/rfcs/pull/131) |
| 2 | //! |
| 3 | //! Rust targets a wide variety of usecases, and in the interest of flexibility, |
| 4 | //! allows new target tuples to be defined in configuration files. Most users |
| 5 | //! will not need to care about these, but this is invaluable when porting Rust |
| 6 | //! to a new platform, and allows for an unprecedented level of control over how |
| 7 | //! the compiler works. |
| 8 | //! |
| 9 | //! # Using custom targets |
| 10 | //! |
| 11 | //! A target tuple, as passed via `rustc --target=TUPLE`, will first be |
| 12 | //! compared against the list of built-in targets. This is to ease distributing |
| 13 | //! rustc (no need for configuration files) and also to hold these built-in |
| 14 | //! targets as immutable and sacred. If `TUPLE` is not one of the built-in |
| 15 | //! targets, rustc will check if a file named `TUPLE` exists. If it does, it |
| 16 | //! will be loaded as the target configuration. If the file does not exist, |
| 17 | //! rustc will search each directory in the environment variable |
| 18 | //! `RUST_TARGET_PATH` for a file named `TUPLE.json`. The first one found will |
| 19 | //! be loaded. If no file is found in any of those directories, a fatal error |
| 20 | //! will be given. |
| 21 | //! |
| 22 | //! Projects defining their own targets should use |
| 23 | //! `--target=path/to/my-awesome-platform.json` instead of adding to |
| 24 | //! `RUST_TARGET_PATH`. |
| 25 | //! |
| 26 | //! # Defining a new target |
| 27 | //! |
| 28 | //! Targets are defined using [JSON](https://json.org/). The `Target` struct in |
| 29 | //! this module defines the format the JSON file should take, though each |
| 30 | //! underscore in the field names should be replaced with a hyphen (`-`) in the |
| 31 | //! JSON file. Some fields are required in every target specification, such as |
| 32 | //! `llvm-target`, `target-endian`, `target-pointer-width`, `data-layout`, |
| 33 | //! `arch`, and `os`. In general, options passed to rustc with `-C` override |
| 34 | //! the target's settings, though `target-feature` and `link-args` will *add* |
| 35 | //! to the list specified by the target, rather than replace. |
| 36 | |
| 37 | use std::borrow::Cow; |
| 38 | use std::collections::BTreeMap; |
| 39 | use std::hash::{Hash, Hasher}; |
| 40 | use std::ops::{Deref, DerefMut}; |
| 41 | use std::path::{Path, PathBuf}; |
| 42 | use std::str::FromStr; |
| 43 | use std::{fmt, io}; |
| 44 | |
| 45 | use rustc_abi::{Endian, ExternAbi, Integer, Size, TargetDataLayout, TargetDataLayoutErrors}; |
| 46 | use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; |
| 47 | use rustc_fs_util::try_canonicalize; |
| 48 | use rustc_macros::{Decodable, Encodable, HashStable_Generic}; |
| 49 | use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; |
| 50 | use rustc_span::{Symbol, kw, sym}; |
| 51 | use serde_json::Value; |
| 52 | use tracing::debug; |
| 53 | |
| 54 | use crate::callconv::Conv; |
| 55 | use crate::json::{Json, ToJson}; |
| 56 | use crate::spec::crt_objects::CrtObjects; |
| 57 | |
| 58 | pub mod crt_objects; |
| 59 | |
| 60 | mod base; |
| 61 | mod json; |
| 62 | |
| 63 | pub use base::avr::ef_avr_arch; |
| 64 | |
| 65 | /// Linker is called through a C/C++ compiler. |
| 66 | #[derive (Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] |
| 67 | pub enum Cc { |
| 68 | Yes, |
| 69 | No, |
| 70 | } |
| 71 | |
| 72 | /// Linker is LLD. |
| 73 | #[derive (Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] |
| 74 | pub enum Lld { |
| 75 | Yes, |
| 76 | No, |
| 77 | } |
| 78 | |
| 79 | /// All linkers have some kinds of command line interfaces and rustc needs to know which commands |
| 80 | /// to use with each of them. So we cluster all such interfaces into a (somewhat arbitrary) number |
| 81 | /// of classes that we call "linker flavors". |
| 82 | /// |
| 83 | /// Technically, it's not even necessary, we can nearly always infer the flavor from linker name |
| 84 | /// and target properties like `is_like_windows`/`is_like_osx`/etc. However, the PRs originally |
| 85 | /// introducing `-Clinker-flavor` (#40018 and friends) were aiming to reduce this kind of inference |
| 86 | /// and provide something certain and explicitly specified instead, and that design goal is still |
| 87 | /// relevant now. |
| 88 | /// |
| 89 | /// The second goal is to keep the number of flavors to the minimum if possible. |
| 90 | /// LLD somewhat forces our hand here because that linker is self-sufficient only if its executable |
| 91 | /// (`argv[0]`) is named in specific way, otherwise it doesn't work and requires a |
| 92 | /// `-flavor LLD_FLAVOR` argument to choose which logic to use. Our shipped `rust-lld` in |
| 93 | /// particular is not named in such specific way, so it needs the flavor option, so we make our |
| 94 | /// linker flavors sufficiently fine-grained to satisfy LLD without inferring its flavor from other |
| 95 | /// target properties, in accordance with the first design goal. |
| 96 | /// |
| 97 | /// The first component of the flavor is tightly coupled with the compilation target, |
| 98 | /// while the `Cc` and `Lld` flags can vary within the same target. |
| 99 | #[derive (Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] |
| 100 | pub enum LinkerFlavor { |
| 101 | /// Unix-like linker with GNU extensions (both naked and compiler-wrapped forms). |
| 102 | /// Besides similar "default" Linux/BSD linkers this also includes Windows/GNU linker, |
| 103 | /// which is somewhat different because it doesn't produce ELFs. |
| 104 | Gnu(Cc, Lld), |
| 105 | /// Unix-like linker for Apple targets (both naked and compiler-wrapped forms). |
| 106 | /// Extracted from the "umbrella" `Unix` flavor due to its corresponding LLD flavor. |
| 107 | Darwin(Cc, Lld), |
| 108 | /// Unix-like linker for Wasm targets (both naked and compiler-wrapped forms). |
| 109 | /// Extracted from the "umbrella" `Unix` flavor due to its corresponding LLD flavor. |
| 110 | /// Non-LLD version does not exist, so the lld flag is currently hardcoded here. |
| 111 | WasmLld(Cc), |
| 112 | /// Basic Unix-like linker for "any other Unix" targets (Solaris/illumos, L4Re, MSP430, etc), |
| 113 | /// possibly with non-GNU extensions (both naked and compiler-wrapped forms). |
| 114 | /// LLD doesn't support any of these. |
| 115 | Unix(Cc), |
| 116 | /// MSVC-style linker for Windows and UEFI, LLD supports it. |
| 117 | Msvc(Lld), |
| 118 | /// Emscripten Compiler Frontend, a wrapper around `WasmLld(Cc::Yes)` that has a different |
| 119 | /// interface and produces some additional JavaScript output. |
| 120 | EmCc, |
| 121 | // Below: other linker-like tools with unique interfaces for exotic targets. |
| 122 | /// Linker tool for BPF. |
| 123 | Bpf, |
| 124 | /// Linker tool for Nvidia PTX. |
| 125 | Ptx, |
| 126 | /// LLVM bitcode linker that can be used as a `self-contained` linker |
| 127 | Llbc, |
| 128 | } |
| 129 | |
| 130 | /// Linker flavors available externally through command line (`-Clinker-flavor`) |
| 131 | /// or json target specifications. |
| 132 | /// This set has accumulated historically, and contains both (stable and unstable) legacy values, as |
| 133 | /// well as modern ones matching the internal linker flavors (`LinkerFlavor`). |
| 134 | #[derive (Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] |
| 135 | pub enum LinkerFlavorCli { |
| 136 | // Modern (unstable) flavors, with direct counterparts in `LinkerFlavor`. |
| 137 | Gnu(Cc, Lld), |
| 138 | Darwin(Cc, Lld), |
| 139 | WasmLld(Cc), |
| 140 | Unix(Cc), |
| 141 | // Note: `Msvc(Lld::No)` is also a stable value. |
| 142 | Msvc(Lld), |
| 143 | EmCc, |
| 144 | Bpf, |
| 145 | Ptx, |
| 146 | Llbc, |
| 147 | |
| 148 | // Legacy stable values |
| 149 | Gcc, |
| 150 | Ld, |
| 151 | Lld(LldFlavor), |
| 152 | Em, |
| 153 | } |
| 154 | |
| 155 | impl LinkerFlavorCli { |
| 156 | /// Returns whether this `-C linker-flavor` option is one of the unstable values. |
| 157 | pub fn is_unstable(&self) -> bool { |
| 158 | match self { |
| 159 | LinkerFlavorCli::Gnu(..) |
| 160 | | LinkerFlavorCli::Darwin(..) |
| 161 | | LinkerFlavorCli::WasmLld(..) |
| 162 | | LinkerFlavorCli::Unix(..) |
| 163 | | LinkerFlavorCli::Msvc(Lld::Yes) |
| 164 | | LinkerFlavorCli::EmCc |
| 165 | | LinkerFlavorCli::Bpf |
| 166 | | LinkerFlavorCli::Llbc |
| 167 | | LinkerFlavorCli::Ptx => true, |
| 168 | LinkerFlavorCli::Gcc |
| 169 | | LinkerFlavorCli::Ld |
| 170 | | LinkerFlavorCli::Lld(..) |
| 171 | | LinkerFlavorCli::Msvc(Lld::No) |
| 172 | | LinkerFlavorCli::Em => false, |
| 173 | } |
| 174 | } |
| 175 | } |
| 176 | |
| 177 | #[derive (Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] |
| 178 | pub enum LldFlavor { |
| 179 | Wasm, |
| 180 | Ld64, |
| 181 | Ld, |
| 182 | Link, |
| 183 | } |
| 184 | |
| 185 | impl LldFlavor { |
| 186 | pub fn as_str(&self) -> &'static str { |
| 187 | match self { |
| 188 | LldFlavor::Wasm => "wasm" , |
| 189 | LldFlavor::Ld64 => "darwin" , |
| 190 | LldFlavor::Ld => "gnu" , |
| 191 | LldFlavor::Link => "link" , |
| 192 | } |
| 193 | } |
| 194 | |
| 195 | fn from_str(s: &str) -> Option<Self> { |
| 196 | Some(match s { |
| 197 | "darwin" => LldFlavor::Ld64, |
| 198 | "gnu" => LldFlavor::Ld, |
| 199 | "link" => LldFlavor::Link, |
| 200 | "wasm" => LldFlavor::Wasm, |
| 201 | _ => return None, |
| 202 | }) |
| 203 | } |
| 204 | } |
| 205 | |
| 206 | impl ToJson for LldFlavor { |
| 207 | fn to_json(&self) -> Json { |
| 208 | self.as_str().to_json() |
| 209 | } |
| 210 | } |
| 211 | |
| 212 | impl LinkerFlavor { |
| 213 | /// At this point the target's reference linker flavor doesn't yet exist and we need to infer |
| 214 | /// it. The inference always succeeds and gives some result, and we don't report any flavor |
| 215 | /// incompatibility errors for json target specs. The CLI flavor is used as the main source |
| 216 | /// of truth, other flags are used in case of ambiguities. |
| 217 | fn from_cli_json(cli: LinkerFlavorCli, lld_flavor: LldFlavor, is_gnu: bool) -> LinkerFlavor { |
| 218 | match cli { |
| 219 | LinkerFlavorCli::Gnu(cc, lld) => LinkerFlavor::Gnu(cc, lld), |
| 220 | LinkerFlavorCli::Darwin(cc, lld) => LinkerFlavor::Darwin(cc, lld), |
| 221 | LinkerFlavorCli::WasmLld(cc) => LinkerFlavor::WasmLld(cc), |
| 222 | LinkerFlavorCli::Unix(cc) => LinkerFlavor::Unix(cc), |
| 223 | LinkerFlavorCli::Msvc(lld) => LinkerFlavor::Msvc(lld), |
| 224 | LinkerFlavorCli::EmCc => LinkerFlavor::EmCc, |
| 225 | LinkerFlavorCli::Bpf => LinkerFlavor::Bpf, |
| 226 | LinkerFlavorCli::Llbc => LinkerFlavor::Llbc, |
| 227 | LinkerFlavorCli::Ptx => LinkerFlavor::Ptx, |
| 228 | |
| 229 | // Below: legacy stable values |
| 230 | LinkerFlavorCli::Gcc => match lld_flavor { |
| 231 | LldFlavor::Ld if is_gnu => LinkerFlavor::Gnu(Cc::Yes, Lld::No), |
| 232 | LldFlavor::Ld64 => LinkerFlavor::Darwin(Cc::Yes, Lld::No), |
| 233 | LldFlavor::Wasm => LinkerFlavor::WasmLld(Cc::Yes), |
| 234 | LldFlavor::Ld | LldFlavor::Link => LinkerFlavor::Unix(Cc::Yes), |
| 235 | }, |
| 236 | LinkerFlavorCli::Ld => match lld_flavor { |
| 237 | LldFlavor::Ld if is_gnu => LinkerFlavor::Gnu(Cc::No, Lld::No), |
| 238 | LldFlavor::Ld64 => LinkerFlavor::Darwin(Cc::No, Lld::No), |
| 239 | LldFlavor::Ld | LldFlavor::Wasm | LldFlavor::Link => LinkerFlavor::Unix(Cc::No), |
| 240 | }, |
| 241 | LinkerFlavorCli::Lld(LldFlavor::Ld) => LinkerFlavor::Gnu(Cc::No, Lld::Yes), |
| 242 | LinkerFlavorCli::Lld(LldFlavor::Ld64) => LinkerFlavor::Darwin(Cc::No, Lld::Yes), |
| 243 | LinkerFlavorCli::Lld(LldFlavor::Wasm) => LinkerFlavor::WasmLld(Cc::No), |
| 244 | LinkerFlavorCli::Lld(LldFlavor::Link) => LinkerFlavor::Msvc(Lld::Yes), |
| 245 | LinkerFlavorCli::Em => LinkerFlavor::EmCc, |
| 246 | } |
| 247 | } |
| 248 | |
| 249 | /// Returns the corresponding backwards-compatible CLI flavor. |
| 250 | fn to_cli(self) -> LinkerFlavorCli { |
| 251 | match self { |
| 252 | LinkerFlavor::Gnu(Cc::Yes, _) |
| 253 | | LinkerFlavor::Darwin(Cc::Yes, _) |
| 254 | | LinkerFlavor::WasmLld(Cc::Yes) |
| 255 | | LinkerFlavor::Unix(Cc::Yes) => LinkerFlavorCli::Gcc, |
| 256 | LinkerFlavor::Gnu(_, Lld::Yes) => LinkerFlavorCli::Lld(LldFlavor::Ld), |
| 257 | LinkerFlavor::Darwin(_, Lld::Yes) => LinkerFlavorCli::Lld(LldFlavor::Ld64), |
| 258 | LinkerFlavor::WasmLld(..) => LinkerFlavorCli::Lld(LldFlavor::Wasm), |
| 259 | LinkerFlavor::Gnu(..) | LinkerFlavor::Darwin(..) | LinkerFlavor::Unix(..) => { |
| 260 | LinkerFlavorCli::Ld |
| 261 | } |
| 262 | LinkerFlavor::Msvc(Lld::Yes) => LinkerFlavorCli::Lld(LldFlavor::Link), |
| 263 | LinkerFlavor::Msvc(..) => LinkerFlavorCli::Msvc(Lld::No), |
| 264 | LinkerFlavor::EmCc => LinkerFlavorCli::Em, |
| 265 | LinkerFlavor::Bpf => LinkerFlavorCli::Bpf, |
| 266 | LinkerFlavor::Llbc => LinkerFlavorCli::Llbc, |
| 267 | LinkerFlavor::Ptx => LinkerFlavorCli::Ptx, |
| 268 | } |
| 269 | } |
| 270 | |
| 271 | /// Returns the modern CLI flavor that is the counterpart of this flavor. |
| 272 | fn to_cli_counterpart(self) -> LinkerFlavorCli { |
| 273 | match self { |
| 274 | LinkerFlavor::Gnu(cc, lld) => LinkerFlavorCli::Gnu(cc, lld), |
| 275 | LinkerFlavor::Darwin(cc, lld) => LinkerFlavorCli::Darwin(cc, lld), |
| 276 | LinkerFlavor::WasmLld(cc) => LinkerFlavorCli::WasmLld(cc), |
| 277 | LinkerFlavor::Unix(cc) => LinkerFlavorCli::Unix(cc), |
| 278 | LinkerFlavor::Msvc(lld) => LinkerFlavorCli::Msvc(lld), |
| 279 | LinkerFlavor::EmCc => LinkerFlavorCli::EmCc, |
| 280 | LinkerFlavor::Bpf => LinkerFlavorCli::Bpf, |
| 281 | LinkerFlavor::Llbc => LinkerFlavorCli::Llbc, |
| 282 | LinkerFlavor::Ptx => LinkerFlavorCli::Ptx, |
| 283 | } |
| 284 | } |
| 285 | |
| 286 | fn infer_cli_hints(cli: LinkerFlavorCli) -> (Option<Cc>, Option<Lld>) { |
| 287 | match cli { |
| 288 | LinkerFlavorCli::Gnu(cc, lld) | LinkerFlavorCli::Darwin(cc, lld) => { |
| 289 | (Some(cc), Some(lld)) |
| 290 | } |
| 291 | LinkerFlavorCli::WasmLld(cc) => (Some(cc), Some(Lld::Yes)), |
| 292 | LinkerFlavorCli::Unix(cc) => (Some(cc), None), |
| 293 | LinkerFlavorCli::Msvc(lld) => (Some(Cc::No), Some(lld)), |
| 294 | LinkerFlavorCli::EmCc => (Some(Cc::Yes), Some(Lld::Yes)), |
| 295 | LinkerFlavorCli::Bpf | LinkerFlavorCli::Ptx => (None, None), |
| 296 | LinkerFlavorCli::Llbc => (None, None), |
| 297 | |
| 298 | // Below: legacy stable values |
| 299 | LinkerFlavorCli::Gcc => (Some(Cc::Yes), None), |
| 300 | LinkerFlavorCli::Ld => (Some(Cc::No), Some(Lld::No)), |
| 301 | LinkerFlavorCli::Lld(_) => (Some(Cc::No), Some(Lld::Yes)), |
| 302 | LinkerFlavorCli::Em => (Some(Cc::Yes), Some(Lld::Yes)), |
| 303 | } |
| 304 | } |
| 305 | |
| 306 | fn infer_linker_hints(linker_stem: &str) -> Result<Self, (Option<Cc>, Option<Lld>)> { |
| 307 | // Remove any version postfix. |
| 308 | let stem = linker_stem |
| 309 | .rsplit_once('-' ) |
| 310 | .and_then(|(lhs, rhs)| rhs.chars().all(char::is_numeric).then_some(lhs)) |
| 311 | .unwrap_or(linker_stem); |
| 312 | |
| 313 | if stem == "llvm-bitcode-linker" { |
| 314 | Ok(Self::Llbc) |
| 315 | } else if stem == "emcc" // GCC/Clang can have an optional target prefix. |
| 316 | || stem == "gcc" |
| 317 | || stem.ends_with("-gcc" ) |
| 318 | || stem == "g++" |
| 319 | || stem.ends_with("-g++" ) |
| 320 | || stem == "clang" |
| 321 | || stem.ends_with("-clang" ) |
| 322 | || stem == "clang++" |
| 323 | || stem.ends_with("-clang++" ) |
| 324 | { |
| 325 | Err((Some(Cc::Yes), Some(Lld::No))) |
| 326 | } else if stem == "wasm-ld" |
| 327 | || stem.ends_with("-wasm-ld" ) |
| 328 | || stem == "ld.lld" |
| 329 | || stem == "lld" |
| 330 | || stem == "rust-lld" |
| 331 | || stem == "lld-link" |
| 332 | { |
| 333 | Err((Some(Cc::No), Some(Lld::Yes))) |
| 334 | } else if stem == "ld" || stem.ends_with("-ld" ) || stem == "link" { |
| 335 | Err((Some(Cc::No), Some(Lld::No))) |
| 336 | } else { |
| 337 | Err((None, None)) |
| 338 | } |
| 339 | } |
| 340 | |
| 341 | fn with_hints(self, (cc_hint, lld_hint): (Option<Cc>, Option<Lld>)) -> LinkerFlavor { |
| 342 | match self { |
| 343 | LinkerFlavor::Gnu(cc, lld) => { |
| 344 | LinkerFlavor::Gnu(cc_hint.unwrap_or(cc), lld_hint.unwrap_or(lld)) |
| 345 | } |
| 346 | LinkerFlavor::Darwin(cc, lld) => { |
| 347 | LinkerFlavor::Darwin(cc_hint.unwrap_or(cc), lld_hint.unwrap_or(lld)) |
| 348 | } |
| 349 | LinkerFlavor::WasmLld(cc) => LinkerFlavor::WasmLld(cc_hint.unwrap_or(cc)), |
| 350 | LinkerFlavor::Unix(cc) => LinkerFlavor::Unix(cc_hint.unwrap_or(cc)), |
| 351 | LinkerFlavor::Msvc(lld) => LinkerFlavor::Msvc(lld_hint.unwrap_or(lld)), |
| 352 | LinkerFlavor::EmCc | LinkerFlavor::Bpf | LinkerFlavor::Llbc | LinkerFlavor::Ptx => self, |
| 353 | } |
| 354 | } |
| 355 | |
| 356 | pub fn with_cli_hints(self, cli: LinkerFlavorCli) -> LinkerFlavor { |
| 357 | self.with_hints(LinkerFlavor::infer_cli_hints(cli)) |
| 358 | } |
| 359 | |
| 360 | pub fn with_linker_hints(self, linker_stem: &str) -> LinkerFlavor { |
| 361 | match LinkerFlavor::infer_linker_hints(linker_stem) { |
| 362 | Ok(linker_flavor) => linker_flavor, |
| 363 | Err(hints) => self.with_hints(hints), |
| 364 | } |
| 365 | } |
| 366 | |
| 367 | pub fn check_compatibility(self, cli: LinkerFlavorCli) -> Option<String> { |
| 368 | let compatible = |cli| { |
| 369 | // The CLI flavor should be compatible with the target if: |
| 370 | match (self, cli) { |
| 371 | // 1. they are counterparts: they have the same principal flavor. |
| 372 | (LinkerFlavor::Gnu(..), LinkerFlavorCli::Gnu(..)) |
| 373 | | (LinkerFlavor::Darwin(..), LinkerFlavorCli::Darwin(..)) |
| 374 | | (LinkerFlavor::WasmLld(..), LinkerFlavorCli::WasmLld(..)) |
| 375 | | (LinkerFlavor::Unix(..), LinkerFlavorCli::Unix(..)) |
| 376 | | (LinkerFlavor::Msvc(..), LinkerFlavorCli::Msvc(..)) |
| 377 | | (LinkerFlavor::EmCc, LinkerFlavorCli::EmCc) |
| 378 | | (LinkerFlavor::Bpf, LinkerFlavorCli::Bpf) |
| 379 | | (LinkerFlavor::Llbc, LinkerFlavorCli::Llbc) |
| 380 | | (LinkerFlavor::Ptx, LinkerFlavorCli::Ptx) => return true, |
| 381 | // 2. The linker flavor is independent of target and compatible |
| 382 | (LinkerFlavor::Ptx, LinkerFlavorCli::Llbc) => return true, |
| 383 | _ => {} |
| 384 | } |
| 385 | |
| 386 | // 3. or, the flavor is legacy and survives this roundtrip. |
| 387 | cli == self.with_cli_hints(cli).to_cli() |
| 388 | }; |
| 389 | (!compatible(cli)).then(|| { |
| 390 | LinkerFlavorCli::all() |
| 391 | .iter() |
| 392 | .filter(|cli| compatible(**cli)) |
| 393 | .map(|cli| cli.desc()) |
| 394 | .intersperse(", " ) |
| 395 | .collect() |
| 396 | }) |
| 397 | } |
| 398 | |
| 399 | pub fn lld_flavor(self) -> LldFlavor { |
| 400 | match self { |
| 401 | LinkerFlavor::Gnu(..) |
| 402 | | LinkerFlavor::Unix(..) |
| 403 | | LinkerFlavor::EmCc |
| 404 | | LinkerFlavor::Bpf |
| 405 | | LinkerFlavor::Llbc |
| 406 | | LinkerFlavor::Ptx => LldFlavor::Ld, |
| 407 | LinkerFlavor::Darwin(..) => LldFlavor::Ld64, |
| 408 | LinkerFlavor::WasmLld(..) => LldFlavor::Wasm, |
| 409 | LinkerFlavor::Msvc(..) => LldFlavor::Link, |
| 410 | } |
| 411 | } |
| 412 | |
| 413 | pub fn is_gnu(self) -> bool { |
| 414 | matches!(self, LinkerFlavor::Gnu(..)) |
| 415 | } |
| 416 | |
| 417 | /// Returns whether the flavor uses the `lld` linker. |
| 418 | pub fn uses_lld(self) -> bool { |
| 419 | // Exhaustive match in case new flavors are added in the future. |
| 420 | match self { |
| 421 | LinkerFlavor::Gnu(_, Lld::Yes) |
| 422 | | LinkerFlavor::Darwin(_, Lld::Yes) |
| 423 | | LinkerFlavor::WasmLld(..) |
| 424 | | LinkerFlavor::EmCc |
| 425 | | LinkerFlavor::Msvc(Lld::Yes) => true, |
| 426 | LinkerFlavor::Gnu(..) |
| 427 | | LinkerFlavor::Darwin(..) |
| 428 | | LinkerFlavor::Msvc(_) |
| 429 | | LinkerFlavor::Unix(_) |
| 430 | | LinkerFlavor::Bpf |
| 431 | | LinkerFlavor::Llbc |
| 432 | | LinkerFlavor::Ptx => false, |
| 433 | } |
| 434 | } |
| 435 | |
| 436 | /// Returns whether the flavor calls the linker via a C/C++ compiler. |
| 437 | pub fn uses_cc(self) -> bool { |
| 438 | // Exhaustive match in case new flavors are added in the future. |
| 439 | match self { |
| 440 | LinkerFlavor::Gnu(Cc::Yes, _) |
| 441 | | LinkerFlavor::Darwin(Cc::Yes, _) |
| 442 | | LinkerFlavor::WasmLld(Cc::Yes) |
| 443 | | LinkerFlavor::Unix(Cc::Yes) |
| 444 | | LinkerFlavor::EmCc => true, |
| 445 | LinkerFlavor::Gnu(..) |
| 446 | | LinkerFlavor::Darwin(..) |
| 447 | | LinkerFlavor::WasmLld(_) |
| 448 | | LinkerFlavor::Msvc(_) |
| 449 | | LinkerFlavor::Unix(_) |
| 450 | | LinkerFlavor::Bpf |
| 451 | | LinkerFlavor::Llbc |
| 452 | | LinkerFlavor::Ptx => false, |
| 453 | } |
| 454 | } |
| 455 | |
| 456 | /// For flavors with an `Lld` component, ensure it's enabled. Otherwise, returns the given |
| 457 | /// flavor unmodified. |
| 458 | pub fn with_lld_enabled(self) -> LinkerFlavor { |
| 459 | match self { |
| 460 | LinkerFlavor::Gnu(cc, Lld::No) => LinkerFlavor::Gnu(cc, Lld::Yes), |
| 461 | LinkerFlavor::Darwin(cc, Lld::No) => LinkerFlavor::Darwin(cc, Lld::Yes), |
| 462 | LinkerFlavor::Msvc(Lld::No) => LinkerFlavor::Msvc(Lld::Yes), |
| 463 | _ => self, |
| 464 | } |
| 465 | } |
| 466 | |
| 467 | /// For flavors with an `Lld` component, ensure it's disabled. Otherwise, returns the given |
| 468 | /// flavor unmodified. |
| 469 | pub fn with_lld_disabled(self) -> LinkerFlavor { |
| 470 | match self { |
| 471 | LinkerFlavor::Gnu(cc, Lld::Yes) => LinkerFlavor::Gnu(cc, Lld::No), |
| 472 | LinkerFlavor::Darwin(cc, Lld::Yes) => LinkerFlavor::Darwin(cc, Lld::No), |
| 473 | LinkerFlavor::Msvc(Lld::Yes) => LinkerFlavor::Msvc(Lld::No), |
| 474 | _ => self, |
| 475 | } |
| 476 | } |
| 477 | } |
| 478 | |
| 479 | macro_rules! linker_flavor_cli_impls { |
| 480 | ($(($($flavor:tt)*) $string:literal)*) => ( |
| 481 | impl LinkerFlavorCli { |
| 482 | const fn all() -> &'static [LinkerFlavorCli] { |
| 483 | &[$($($flavor)*,)*] |
| 484 | } |
| 485 | |
| 486 | pub const fn one_of() -> &'static str { |
| 487 | concat!("one of: " , $($string, " " ,)*) |
| 488 | } |
| 489 | |
| 490 | pub fn from_str(s: &str) -> Option<LinkerFlavorCli> { |
| 491 | Some(match s { |
| 492 | $($string => $($flavor)*,)* |
| 493 | _ => return None, |
| 494 | }) |
| 495 | } |
| 496 | |
| 497 | pub fn desc(self) -> &'static str { |
| 498 | match self { |
| 499 | $($($flavor)* => $string,)* |
| 500 | } |
| 501 | } |
| 502 | } |
| 503 | ) |
| 504 | } |
| 505 | |
| 506 | linker_flavor_cli_impls! { |
| 507 | (LinkerFlavorCli::Gnu(Cc::No, Lld::No)) "gnu" |
| 508 | (LinkerFlavorCli::Gnu(Cc::No, Lld::Yes)) "gnu-lld" |
| 509 | (LinkerFlavorCli::Gnu(Cc::Yes, Lld::No)) "gnu-cc" |
| 510 | (LinkerFlavorCli::Gnu(Cc::Yes, Lld::Yes)) "gnu-lld-cc" |
| 511 | (LinkerFlavorCli::Darwin(Cc::No, Lld::No)) "darwin" |
| 512 | (LinkerFlavorCli::Darwin(Cc::No, Lld::Yes)) "darwin-lld" |
| 513 | (LinkerFlavorCli::Darwin(Cc::Yes, Lld::No)) "darwin-cc" |
| 514 | (LinkerFlavorCli::Darwin(Cc::Yes, Lld::Yes)) "darwin-lld-cc" |
| 515 | (LinkerFlavorCli::WasmLld(Cc::No)) "wasm-lld" |
| 516 | (LinkerFlavorCli::WasmLld(Cc::Yes)) "wasm-lld-cc" |
| 517 | (LinkerFlavorCli::Unix(Cc::No)) "unix" |
| 518 | (LinkerFlavorCli::Unix(Cc::Yes)) "unix-cc" |
| 519 | (LinkerFlavorCli::Msvc(Lld::Yes)) "msvc-lld" |
| 520 | (LinkerFlavorCli::Msvc(Lld::No)) "msvc" |
| 521 | (LinkerFlavorCli::EmCc) "em-cc" |
| 522 | (LinkerFlavorCli::Bpf) "bpf" |
| 523 | (LinkerFlavorCli::Llbc) "llbc" |
| 524 | (LinkerFlavorCli::Ptx) "ptx" |
| 525 | |
| 526 | // Legacy stable flavors |
| 527 | (LinkerFlavorCli::Gcc) "gcc" |
| 528 | (LinkerFlavorCli::Ld) "ld" |
| 529 | (LinkerFlavorCli::Lld(LldFlavor::Ld)) "ld.lld" |
| 530 | (LinkerFlavorCli::Lld(LldFlavor::Ld64)) "ld64.lld" |
| 531 | (LinkerFlavorCli::Lld(LldFlavor::Link)) "lld-link" |
| 532 | (LinkerFlavorCli::Lld(LldFlavor::Wasm)) "wasm-ld" |
| 533 | (LinkerFlavorCli::Em) "em" |
| 534 | } |
| 535 | |
| 536 | impl ToJson for LinkerFlavorCli { |
| 537 | fn to_json(&self) -> Json { |
| 538 | self.desc().to_json() |
| 539 | } |
| 540 | } |
| 541 | |
| 542 | /// The different `-Clink-self-contained` options that can be specified in a target spec: |
| 543 | /// - enabling or disabling in bulk |
| 544 | /// - some target-specific pieces of inference to determine whether to use self-contained linking |
| 545 | /// if `-Clink-self-contained` is not specified explicitly (e.g. on musl/mingw) |
| 546 | /// - explicitly enabling some of the self-contained linking components, e.g. the linker component |
| 547 | /// to use `rust-lld` |
| 548 | #[derive (Clone, Copy, PartialEq, Debug)] |
| 549 | pub enum LinkSelfContainedDefault { |
| 550 | /// The target spec explicitly enables self-contained linking. |
| 551 | True, |
| 552 | |
| 553 | /// The target spec explicitly disables self-contained linking. |
| 554 | False, |
| 555 | |
| 556 | /// The target spec requests that the self-contained mode is inferred, in the context of musl. |
| 557 | InferredForMusl, |
| 558 | |
| 559 | /// The target spec requests that the self-contained mode is inferred, in the context of mingw. |
| 560 | InferredForMingw, |
| 561 | |
| 562 | /// The target spec explicitly enables a list of self-contained linking components: e.g. for |
| 563 | /// targets opting into a subset of components like the CLI's `-C link-self-contained=+linker`. |
| 564 | WithComponents(LinkSelfContainedComponents), |
| 565 | } |
| 566 | |
| 567 | /// Parses a backwards-compatible `-Clink-self-contained` option string, without components. |
| 568 | impl FromStr for LinkSelfContainedDefault { |
| 569 | type Err = (); |
| 570 | |
| 571 | fn from_str(s: &str) -> Result<LinkSelfContainedDefault, ()> { |
| 572 | Ok(match s { |
| 573 | "false" => LinkSelfContainedDefault::False, |
| 574 | "true" | "wasm" => LinkSelfContainedDefault::True, |
| 575 | "musl" => LinkSelfContainedDefault::InferredForMusl, |
| 576 | "mingw" => LinkSelfContainedDefault::InferredForMingw, |
| 577 | _ => return Err(()), |
| 578 | }) |
| 579 | } |
| 580 | } |
| 581 | |
| 582 | impl ToJson for LinkSelfContainedDefault { |
| 583 | fn to_json(&self) -> Json { |
| 584 | match *self { |
| 585 | LinkSelfContainedDefault::WithComponents(components: LinkSelfContainedComponents) => { |
| 586 | // Serialize the components in a json object's `components` field, to prepare for a |
| 587 | // future where `crt-objects-fallback` is removed from the json specs and |
| 588 | // incorporated as a field here. |
| 589 | let mut map: BTreeMap<&'static str, LinkSelfContainedComponents> = BTreeMap::new(); |
| 590 | map.insert(key:"components" , value:components); |
| 591 | map.to_json() |
| 592 | } |
| 593 | |
| 594 | // Stable backwards-compatible values |
| 595 | LinkSelfContainedDefault::True => "true" .to_json(), |
| 596 | LinkSelfContainedDefault::False => "false" .to_json(), |
| 597 | LinkSelfContainedDefault::InferredForMusl => "musl" .to_json(), |
| 598 | LinkSelfContainedDefault::InferredForMingw => "mingw" .to_json(), |
| 599 | } |
| 600 | } |
| 601 | } |
| 602 | |
| 603 | impl LinkSelfContainedDefault { |
| 604 | /// Returns whether the target spec has self-contained linking explicitly disabled. Used to emit |
| 605 | /// errors if the user then enables it on the CLI. |
| 606 | pub fn is_disabled(self) -> bool { |
| 607 | self == LinkSelfContainedDefault::False |
| 608 | } |
| 609 | |
| 610 | /// Returns the key to use when serializing the setting to json: |
| 611 | /// - individual components in a `link-self-contained` object value |
| 612 | /// - the other variants as a backwards-compatible `crt-objects-fallback` string |
| 613 | fn json_key(self) -> &'static str { |
| 614 | match self { |
| 615 | LinkSelfContainedDefault::WithComponents(_) => "link-self-contained" , |
| 616 | _ => "crt-objects-fallback" , |
| 617 | } |
| 618 | } |
| 619 | |
| 620 | /// Creates a `LinkSelfContainedDefault` enabling the self-contained linker for target specs |
| 621 | /// (the equivalent of `-Clink-self-contained=+linker` on the CLI). |
| 622 | pub fn with_linker() -> LinkSelfContainedDefault { |
| 623 | LinkSelfContainedDefault::WithComponents(LinkSelfContainedComponents::LINKER) |
| 624 | } |
| 625 | } |
| 626 | |
| 627 | bitflags::bitflags! { |
| 628 | #[derive (Clone, Copy, PartialEq, Eq, Default)] |
| 629 | /// The `-C link-self-contained` components that can individually be enabled or disabled. |
| 630 | pub struct LinkSelfContainedComponents: u8 { |
| 631 | /// CRT objects (e.g. on `windows-gnu`, `musl`, `wasi` targets) |
| 632 | const CRT_OBJECTS = 1 << 0; |
| 633 | /// libc static library (e.g. on `musl`, `wasi` targets) |
| 634 | const LIBC = 1 << 1; |
| 635 | /// libgcc/libunwind (e.g. on `windows-gnu`, `fuchsia`, `fortanix`, `gnullvm` targets) |
| 636 | const UNWIND = 1 << 2; |
| 637 | /// Linker, dlltool, and their necessary libraries (e.g. on `windows-gnu` and for `rust-lld`) |
| 638 | const LINKER = 1 << 3; |
| 639 | /// Sanitizer runtime libraries |
| 640 | const SANITIZERS = 1 << 4; |
| 641 | /// Other MinGW libs and Windows import libs |
| 642 | const MINGW = 1 << 5; |
| 643 | } |
| 644 | } |
| 645 | rustc_data_structures::external_bitflags_debug! { LinkSelfContainedComponents } |
| 646 | |
| 647 | impl LinkSelfContainedComponents { |
| 648 | /// Parses a single `-Clink-self-contained` well-known component, not a set of flags. |
| 649 | pub fn from_str(s: &str) -> Option<LinkSelfContainedComponents> { |
| 650 | Some(match s { |
| 651 | "crto" => LinkSelfContainedComponents::CRT_OBJECTS, |
| 652 | "libc" => LinkSelfContainedComponents::LIBC, |
| 653 | "unwind" => LinkSelfContainedComponents::UNWIND, |
| 654 | "linker" => LinkSelfContainedComponents::LINKER, |
| 655 | "sanitizers" => LinkSelfContainedComponents::SANITIZERS, |
| 656 | "mingw" => LinkSelfContainedComponents::MINGW, |
| 657 | _ => return None, |
| 658 | }) |
| 659 | } |
| 660 | |
| 661 | /// Return the component's name. |
| 662 | /// |
| 663 | /// Returns `None` if the bitflags aren't a singular component (but a mix of multiple flags). |
| 664 | pub fn as_str(self) -> Option<&'static str> { |
| 665 | Some(match self { |
| 666 | LinkSelfContainedComponents::CRT_OBJECTS => "crto" , |
| 667 | LinkSelfContainedComponents::LIBC => "libc" , |
| 668 | LinkSelfContainedComponents::UNWIND => "unwind" , |
| 669 | LinkSelfContainedComponents::LINKER => "linker" , |
| 670 | LinkSelfContainedComponents::SANITIZERS => "sanitizers" , |
| 671 | LinkSelfContainedComponents::MINGW => "mingw" , |
| 672 | _ => return None, |
| 673 | }) |
| 674 | } |
| 675 | |
| 676 | /// Returns an array of all the components. |
| 677 | fn all_components() -> [LinkSelfContainedComponents; 6] { |
| 678 | [ |
| 679 | LinkSelfContainedComponents::CRT_OBJECTS, |
| 680 | LinkSelfContainedComponents::LIBC, |
| 681 | LinkSelfContainedComponents::UNWIND, |
| 682 | LinkSelfContainedComponents::LINKER, |
| 683 | LinkSelfContainedComponents::SANITIZERS, |
| 684 | LinkSelfContainedComponents::MINGW, |
| 685 | ] |
| 686 | } |
| 687 | |
| 688 | /// Returns whether at least a component is enabled. |
| 689 | pub fn are_any_components_enabled(self) -> bool { |
| 690 | !self.is_empty() |
| 691 | } |
| 692 | |
| 693 | /// Returns whether `LinkSelfContainedComponents::LINKER` is enabled. |
| 694 | pub fn is_linker_enabled(self) -> bool { |
| 695 | self.contains(LinkSelfContainedComponents::LINKER) |
| 696 | } |
| 697 | |
| 698 | /// Returns whether `LinkSelfContainedComponents::CRT_OBJECTS` is enabled. |
| 699 | pub fn is_crt_objects_enabled(self) -> bool { |
| 700 | self.contains(LinkSelfContainedComponents::CRT_OBJECTS) |
| 701 | } |
| 702 | } |
| 703 | |
| 704 | impl ToJson for LinkSelfContainedComponents { |
| 705 | fn to_json(&self) -> Json { |
| 706 | let components: Vec<_> = Self::all_components() |
| 707 | .into_iter() |
| 708 | .filter(|c: &LinkSelfContainedComponents| self.contains(*c)) |
| 709 | .map(|c: LinkSelfContainedComponents| { |
| 710 | // We can unwrap because we're iterating over all the known singular components, |
| 711 | // not an actual set of flags where `as_str` can fail. |
| 712 | c.as_str().unwrap().to_owned() |
| 713 | }) |
| 714 | .collect(); |
| 715 | |
| 716 | components.to_json() |
| 717 | } |
| 718 | } |
| 719 | |
| 720 | bitflags::bitflags! { |
| 721 | /// The `-Z linker-features` components that can individually be enabled or disabled. |
| 722 | /// |
| 723 | /// They are feature flags intended to be a more flexible mechanism than linker flavors, and |
| 724 | /// also to prevent a combinatorial explosion of flavors whenever a new linker feature is |
| 725 | /// required. These flags are "generic", in the sense that they can work on multiple targets on |
| 726 | /// the CLI. Otherwise, one would have to select different linkers flavors for each target. |
| 727 | /// |
| 728 | /// Here are some examples of the advantages they offer: |
| 729 | /// - default feature sets for principal flavors, or for specific targets. |
| 730 | /// - flavor-specific features: for example, clang offers automatic cross-linking with |
| 731 | /// `--target`, which gcc-style compilers don't support. The *flavor* is still a C/C++ |
| 732 | /// compiler, and we don't need to multiply the number of flavors for this use-case. Instead, |
| 733 | /// we can have a single `+target` feature. |
| 734 | /// - umbrella features: for example if clang accumulates more features in the future than just |
| 735 | /// the `+target` above. That could be modeled as `+clang`. |
| 736 | /// - niche features for resolving specific issues: for example, on Apple targets the linker |
| 737 | /// flag implementing the `as-needed` native link modifier (#99424) is only possible on |
| 738 | /// sufficiently recent linker versions. |
| 739 | /// - still allows for discovery and automation, for example via feature detection. This can be |
| 740 | /// useful in exotic environments/build systems. |
| 741 | #[derive (Clone, Copy, PartialEq, Eq, Default)] |
| 742 | pub struct LinkerFeatures: u8 { |
| 743 | /// Invoke the linker via a C/C++ compiler (e.g. on most unix targets). |
| 744 | const CC = 1 << 0; |
| 745 | /// Use the lld linker, either the system lld or the self-contained linker `rust-lld`. |
| 746 | const LLD = 1 << 1; |
| 747 | } |
| 748 | } |
| 749 | rustc_data_structures::external_bitflags_debug! { LinkerFeatures } |
| 750 | |
| 751 | impl LinkerFeatures { |
| 752 | /// Parses a single `-Z linker-features` well-known feature, not a set of flags. |
| 753 | pub fn from_str(s: &str) -> Option<LinkerFeatures> { |
| 754 | Some(match s { |
| 755 | "cc" => LinkerFeatures::CC, |
| 756 | "lld" => LinkerFeatures::LLD, |
| 757 | _ => return None, |
| 758 | }) |
| 759 | } |
| 760 | |
| 761 | /// Returns whether the `lld` linker feature is enabled. |
| 762 | pub fn is_lld_enabled(self) -> bool { |
| 763 | self.contains(LinkerFeatures::LLD) |
| 764 | } |
| 765 | |
| 766 | /// Returns whether the `cc` linker feature is enabled. |
| 767 | pub fn is_cc_enabled(self) -> bool { |
| 768 | self.contains(LinkerFeatures::CC) |
| 769 | } |
| 770 | } |
| 771 | |
| 772 | #[derive (Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable, HashStable_Generic)] |
| 773 | pub enum PanicStrategy { |
| 774 | Unwind, |
| 775 | Abort, |
| 776 | } |
| 777 | |
| 778 | #[derive (Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable, HashStable_Generic)] |
| 779 | pub enum OnBrokenPipe { |
| 780 | Default, |
| 781 | Kill, |
| 782 | Error, |
| 783 | Inherit, |
| 784 | } |
| 785 | |
| 786 | impl PanicStrategy { |
| 787 | pub fn desc(&self) -> &str { |
| 788 | match *self { |
| 789 | PanicStrategy::Unwind => "unwind" , |
| 790 | PanicStrategy::Abort => "abort" , |
| 791 | } |
| 792 | } |
| 793 | |
| 794 | pub const fn desc_symbol(&self) -> Symbol { |
| 795 | match *self { |
| 796 | PanicStrategy::Unwind => sym::unwind, |
| 797 | PanicStrategy::Abort => sym::abort, |
| 798 | } |
| 799 | } |
| 800 | |
| 801 | pub const fn all() -> [Symbol; 2] { |
| 802 | [Self::Abort.desc_symbol(), Self::Unwind.desc_symbol()] |
| 803 | } |
| 804 | } |
| 805 | |
| 806 | impl ToJson for PanicStrategy { |
| 807 | fn to_json(&self) -> Json { |
| 808 | match *self { |
| 809 | PanicStrategy::Abort => "abort" .to_json(), |
| 810 | PanicStrategy::Unwind => "unwind" .to_json(), |
| 811 | } |
| 812 | } |
| 813 | } |
| 814 | |
| 815 | #[derive (Clone, Copy, Debug, PartialEq, Hash)] |
| 816 | pub enum RelroLevel { |
| 817 | Full, |
| 818 | Partial, |
| 819 | Off, |
| 820 | None, |
| 821 | } |
| 822 | |
| 823 | impl RelroLevel { |
| 824 | pub fn desc(&self) -> &str { |
| 825 | match *self { |
| 826 | RelroLevel::Full => "full" , |
| 827 | RelroLevel::Partial => "partial" , |
| 828 | RelroLevel::Off => "off" , |
| 829 | RelroLevel::None => "none" , |
| 830 | } |
| 831 | } |
| 832 | } |
| 833 | |
| 834 | #[derive (Clone, Copy, Debug, PartialEq, Hash)] |
| 835 | pub enum SymbolVisibility { |
| 836 | Hidden, |
| 837 | Protected, |
| 838 | Interposable, |
| 839 | } |
| 840 | |
| 841 | impl SymbolVisibility { |
| 842 | pub fn desc(&self) -> &str { |
| 843 | match *self { |
| 844 | SymbolVisibility::Hidden => "hidden" , |
| 845 | SymbolVisibility::Protected => "protected" , |
| 846 | SymbolVisibility::Interposable => "interposable" , |
| 847 | } |
| 848 | } |
| 849 | } |
| 850 | |
| 851 | impl FromStr for SymbolVisibility { |
| 852 | type Err = (); |
| 853 | |
| 854 | fn from_str(s: &str) -> Result<SymbolVisibility, ()> { |
| 855 | match s { |
| 856 | "hidden" => Ok(SymbolVisibility::Hidden), |
| 857 | "protected" => Ok(SymbolVisibility::Protected), |
| 858 | "interposable" => Ok(SymbolVisibility::Interposable), |
| 859 | _ => Err(()), |
| 860 | } |
| 861 | } |
| 862 | } |
| 863 | |
| 864 | impl ToJson for SymbolVisibility { |
| 865 | fn to_json(&self) -> Json { |
| 866 | match *self { |
| 867 | SymbolVisibility::Hidden => "hidden" .to_json(), |
| 868 | SymbolVisibility::Protected => "protected" .to_json(), |
| 869 | SymbolVisibility::Interposable => "interposable" .to_json(), |
| 870 | } |
| 871 | } |
| 872 | } |
| 873 | |
| 874 | impl FromStr for RelroLevel { |
| 875 | type Err = (); |
| 876 | |
| 877 | fn from_str(s: &str) -> Result<RelroLevel, ()> { |
| 878 | match s { |
| 879 | "full" => Ok(RelroLevel::Full), |
| 880 | "partial" => Ok(RelroLevel::Partial), |
| 881 | "off" => Ok(RelroLevel::Off), |
| 882 | "none" => Ok(RelroLevel::None), |
| 883 | _ => Err(()), |
| 884 | } |
| 885 | } |
| 886 | } |
| 887 | |
| 888 | impl ToJson for RelroLevel { |
| 889 | fn to_json(&self) -> Json { |
| 890 | match *self { |
| 891 | RelroLevel::Full => "full" .to_json(), |
| 892 | RelroLevel::Partial => "partial" .to_json(), |
| 893 | RelroLevel::Off => "off" .to_json(), |
| 894 | RelroLevel::None => "None" .to_json(), |
| 895 | } |
| 896 | } |
| 897 | } |
| 898 | |
| 899 | #[derive (Clone, Debug, PartialEq, Hash)] |
| 900 | pub enum SmallDataThresholdSupport { |
| 901 | None, |
| 902 | DefaultForArch, |
| 903 | LlvmModuleFlag(StaticCow<str>), |
| 904 | LlvmArg(StaticCow<str>), |
| 905 | } |
| 906 | |
| 907 | impl FromStr for SmallDataThresholdSupport { |
| 908 | type Err = (); |
| 909 | |
| 910 | fn from_str(s: &str) -> Result<Self, Self::Err> { |
| 911 | if s == "none" { |
| 912 | Ok(Self::None) |
| 913 | } else if s == "default-for-arch" { |
| 914 | Ok(Self::DefaultForArch) |
| 915 | } else if let Some(flag: &str) = s.strip_prefix("llvm-module-flag=" ) { |
| 916 | Ok(Self::LlvmModuleFlag(flag.to_string().into())) |
| 917 | } else if let Some(arg: &str) = s.strip_prefix("llvm-arg=" ) { |
| 918 | Ok(Self::LlvmArg(arg.to_string().into())) |
| 919 | } else { |
| 920 | Err(()) |
| 921 | } |
| 922 | } |
| 923 | } |
| 924 | |
| 925 | impl ToJson for SmallDataThresholdSupport { |
| 926 | fn to_json(&self) -> Value { |
| 927 | match self { |
| 928 | Self::None => "none" .to_json(), |
| 929 | Self::DefaultForArch => "default-for-arch" .to_json(), |
| 930 | Self::LlvmModuleFlag(flag: &Cow<'static, str>) => format!("llvm-module-flag= {flag}" ).to_json(), |
| 931 | Self::LlvmArg(arg: &Cow<'static, str>) => format!("llvm-arg= {arg}" ).to_json(), |
| 932 | } |
| 933 | } |
| 934 | } |
| 935 | |
| 936 | #[derive (Clone, Copy, Debug, PartialEq, Hash)] |
| 937 | pub enum MergeFunctions { |
| 938 | Disabled, |
| 939 | Trampolines, |
| 940 | Aliases, |
| 941 | } |
| 942 | |
| 943 | impl MergeFunctions { |
| 944 | pub fn desc(&self) -> &str { |
| 945 | match *self { |
| 946 | MergeFunctions::Disabled => "disabled" , |
| 947 | MergeFunctions::Trampolines => "trampolines" , |
| 948 | MergeFunctions::Aliases => "aliases" , |
| 949 | } |
| 950 | } |
| 951 | } |
| 952 | |
| 953 | impl FromStr for MergeFunctions { |
| 954 | type Err = (); |
| 955 | |
| 956 | fn from_str(s: &str) -> Result<MergeFunctions, ()> { |
| 957 | match s { |
| 958 | "disabled" => Ok(MergeFunctions::Disabled), |
| 959 | "trampolines" => Ok(MergeFunctions::Trampolines), |
| 960 | "aliases" => Ok(MergeFunctions::Aliases), |
| 961 | _ => Err(()), |
| 962 | } |
| 963 | } |
| 964 | } |
| 965 | |
| 966 | impl ToJson for MergeFunctions { |
| 967 | fn to_json(&self) -> Json { |
| 968 | match *self { |
| 969 | MergeFunctions::Disabled => "disabled" .to_json(), |
| 970 | MergeFunctions::Trampolines => "trampolines" .to_json(), |
| 971 | MergeFunctions::Aliases => "aliases" .to_json(), |
| 972 | } |
| 973 | } |
| 974 | } |
| 975 | |
| 976 | #[derive (Clone, Copy, PartialEq, Hash, Debug)] |
| 977 | pub enum RelocModel { |
| 978 | Static, |
| 979 | Pic, |
| 980 | Pie, |
| 981 | DynamicNoPic, |
| 982 | Ropi, |
| 983 | Rwpi, |
| 984 | RopiRwpi, |
| 985 | } |
| 986 | |
| 987 | impl RelocModel { |
| 988 | pub fn desc(&self) -> &str { |
| 989 | match *self { |
| 990 | RelocModel::Static => "static" , |
| 991 | RelocModel::Pic => "pic" , |
| 992 | RelocModel::Pie => "pie" , |
| 993 | RelocModel::DynamicNoPic => "dynamic-no-pic" , |
| 994 | RelocModel::Ropi => "ropi" , |
| 995 | RelocModel::Rwpi => "rwpi" , |
| 996 | RelocModel::RopiRwpi => "ropi-rwpi" , |
| 997 | } |
| 998 | } |
| 999 | pub const fn desc_symbol(&self) -> Symbol { |
| 1000 | match *self { |
| 1001 | RelocModel::Static => kw::Static, |
| 1002 | RelocModel::Pic => sym::pic, |
| 1003 | RelocModel::Pie => sym::pie, |
| 1004 | RelocModel::DynamicNoPic => sym::dynamic_no_pic, |
| 1005 | RelocModel::Ropi => sym::ropi, |
| 1006 | RelocModel::Rwpi => sym::rwpi, |
| 1007 | RelocModel::RopiRwpi => sym::ropi_rwpi, |
| 1008 | } |
| 1009 | } |
| 1010 | |
| 1011 | pub const fn all() -> [Symbol; 7] { |
| 1012 | [ |
| 1013 | RelocModel::Static.desc_symbol(), |
| 1014 | RelocModel::Pic.desc_symbol(), |
| 1015 | RelocModel::Pie.desc_symbol(), |
| 1016 | RelocModel::DynamicNoPic.desc_symbol(), |
| 1017 | RelocModel::Ropi.desc_symbol(), |
| 1018 | RelocModel::Rwpi.desc_symbol(), |
| 1019 | RelocModel::RopiRwpi.desc_symbol(), |
| 1020 | ] |
| 1021 | } |
| 1022 | } |
| 1023 | |
| 1024 | impl FromStr for RelocModel { |
| 1025 | type Err = (); |
| 1026 | |
| 1027 | fn from_str(s: &str) -> Result<RelocModel, ()> { |
| 1028 | Ok(match s { |
| 1029 | "static" => RelocModel::Static, |
| 1030 | "pic" => RelocModel::Pic, |
| 1031 | "pie" => RelocModel::Pie, |
| 1032 | "dynamic-no-pic" => RelocModel::DynamicNoPic, |
| 1033 | "ropi" => RelocModel::Ropi, |
| 1034 | "rwpi" => RelocModel::Rwpi, |
| 1035 | "ropi-rwpi" => RelocModel::RopiRwpi, |
| 1036 | _ => return Err(()), |
| 1037 | }) |
| 1038 | } |
| 1039 | } |
| 1040 | |
| 1041 | impl ToJson for RelocModel { |
| 1042 | fn to_json(&self) -> Json { |
| 1043 | self.desc().to_json() |
| 1044 | } |
| 1045 | } |
| 1046 | |
| 1047 | #[derive (Clone, Copy, PartialEq, Hash, Debug)] |
| 1048 | pub enum CodeModel { |
| 1049 | Tiny, |
| 1050 | Small, |
| 1051 | Kernel, |
| 1052 | Medium, |
| 1053 | Large, |
| 1054 | } |
| 1055 | |
| 1056 | impl FromStr for CodeModel { |
| 1057 | type Err = (); |
| 1058 | |
| 1059 | fn from_str(s: &str) -> Result<CodeModel, ()> { |
| 1060 | Ok(match s { |
| 1061 | "tiny" => CodeModel::Tiny, |
| 1062 | "small" => CodeModel::Small, |
| 1063 | "kernel" => CodeModel::Kernel, |
| 1064 | "medium" => CodeModel::Medium, |
| 1065 | "large" => CodeModel::Large, |
| 1066 | _ => return Err(()), |
| 1067 | }) |
| 1068 | } |
| 1069 | } |
| 1070 | |
| 1071 | impl ToJson for CodeModel { |
| 1072 | fn to_json(&self) -> Json { |
| 1073 | match&'static str *self { |
| 1074 | CodeModel::Tiny => "tiny" , |
| 1075 | CodeModel::Small => "small" , |
| 1076 | CodeModel::Kernel => "kernel" , |
| 1077 | CodeModel::Medium => "medium" , |
| 1078 | CodeModel::Large => "large" , |
| 1079 | } |
| 1080 | .to_json() |
| 1081 | } |
| 1082 | } |
| 1083 | |
| 1084 | /// The float ABI setting to be configured in the LLVM target machine. |
| 1085 | #[derive (Clone, Copy, PartialEq, Hash, Debug)] |
| 1086 | pub enum FloatAbi { |
| 1087 | Soft, |
| 1088 | Hard, |
| 1089 | } |
| 1090 | |
| 1091 | impl FromStr for FloatAbi { |
| 1092 | type Err = (); |
| 1093 | |
| 1094 | fn from_str(s: &str) -> Result<FloatAbi, ()> { |
| 1095 | Ok(match s { |
| 1096 | "soft" => FloatAbi::Soft, |
| 1097 | "hard" => FloatAbi::Hard, |
| 1098 | _ => return Err(()), |
| 1099 | }) |
| 1100 | } |
| 1101 | } |
| 1102 | |
| 1103 | impl ToJson for FloatAbi { |
| 1104 | fn to_json(&self) -> Json { |
| 1105 | match&'static str *self { |
| 1106 | FloatAbi::Soft => "soft" , |
| 1107 | FloatAbi::Hard => "hard" , |
| 1108 | } |
| 1109 | .to_json() |
| 1110 | } |
| 1111 | } |
| 1112 | |
| 1113 | /// The Rustc-specific variant of the ABI used for this target. |
| 1114 | #[derive (Clone, Copy, PartialEq, Hash, Debug)] |
| 1115 | pub enum RustcAbi { |
| 1116 | /// On x86-32 only: make use of SSE and SSE2 for ABI purposes. |
| 1117 | X86Sse2, |
| 1118 | /// On x86-32/64 only: do not use any FPU or SIMD registers for the ABI. |
| 1119 | X86Softfloat, |
| 1120 | } |
| 1121 | |
| 1122 | impl FromStr for RustcAbi { |
| 1123 | type Err = (); |
| 1124 | |
| 1125 | fn from_str(s: &str) -> Result<RustcAbi, ()> { |
| 1126 | Ok(match s { |
| 1127 | "x86-sse2" => RustcAbi::X86Sse2, |
| 1128 | "x86-softfloat" => RustcAbi::X86Softfloat, |
| 1129 | _ => return Err(()), |
| 1130 | }) |
| 1131 | } |
| 1132 | } |
| 1133 | |
| 1134 | impl ToJson for RustcAbi { |
| 1135 | fn to_json(&self) -> Json { |
| 1136 | match&'static str *self { |
| 1137 | RustcAbi::X86Sse2 => "x86-sse2" , |
| 1138 | RustcAbi::X86Softfloat => "x86-softfloat" , |
| 1139 | } |
| 1140 | .to_json() |
| 1141 | } |
| 1142 | } |
| 1143 | |
| 1144 | #[derive (Clone, Copy, PartialEq, Hash, Debug)] |
| 1145 | pub enum TlsModel { |
| 1146 | GeneralDynamic, |
| 1147 | LocalDynamic, |
| 1148 | InitialExec, |
| 1149 | LocalExec, |
| 1150 | Emulated, |
| 1151 | } |
| 1152 | |
| 1153 | impl FromStr for TlsModel { |
| 1154 | type Err = (); |
| 1155 | |
| 1156 | fn from_str(s: &str) -> Result<TlsModel, ()> { |
| 1157 | Ok(match s { |
| 1158 | // Note the difference "general" vs "global" difference. The model name is "general", |
| 1159 | // but the user-facing option name is "global" for consistency with other compilers. |
| 1160 | "global-dynamic" => TlsModel::GeneralDynamic, |
| 1161 | "local-dynamic" => TlsModel::LocalDynamic, |
| 1162 | "initial-exec" => TlsModel::InitialExec, |
| 1163 | "local-exec" => TlsModel::LocalExec, |
| 1164 | "emulated" => TlsModel::Emulated, |
| 1165 | _ => return Err(()), |
| 1166 | }) |
| 1167 | } |
| 1168 | } |
| 1169 | |
| 1170 | impl ToJson for TlsModel { |
| 1171 | fn to_json(&self) -> Json { |
| 1172 | match&'static str *self { |
| 1173 | TlsModel::GeneralDynamic => "global-dynamic" , |
| 1174 | TlsModel::LocalDynamic => "local-dynamic" , |
| 1175 | TlsModel::InitialExec => "initial-exec" , |
| 1176 | TlsModel::LocalExec => "local-exec" , |
| 1177 | TlsModel::Emulated => "emulated" , |
| 1178 | } |
| 1179 | .to_json() |
| 1180 | } |
| 1181 | } |
| 1182 | |
| 1183 | /// Everything is flattened to a single enum to make the json encoding/decoding less annoying. |
| 1184 | #[derive (Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] |
| 1185 | pub enum LinkOutputKind { |
| 1186 | /// Dynamically linked non position-independent executable. |
| 1187 | DynamicNoPicExe, |
| 1188 | /// Dynamically linked position-independent executable. |
| 1189 | DynamicPicExe, |
| 1190 | /// Statically linked non position-independent executable. |
| 1191 | StaticNoPicExe, |
| 1192 | /// Statically linked position-independent executable. |
| 1193 | StaticPicExe, |
| 1194 | /// Regular dynamic library ("dynamically linked"). |
| 1195 | DynamicDylib, |
| 1196 | /// Dynamic library with bundled libc ("statically linked"). |
| 1197 | StaticDylib, |
| 1198 | /// WASI module with a lifetime past the _initialize entry point |
| 1199 | WasiReactorExe, |
| 1200 | } |
| 1201 | |
| 1202 | impl LinkOutputKind { |
| 1203 | fn as_str(&self) -> &'static str { |
| 1204 | match self { |
| 1205 | LinkOutputKind::DynamicNoPicExe => "dynamic-nopic-exe" , |
| 1206 | LinkOutputKind::DynamicPicExe => "dynamic-pic-exe" , |
| 1207 | LinkOutputKind::StaticNoPicExe => "static-nopic-exe" , |
| 1208 | LinkOutputKind::StaticPicExe => "static-pic-exe" , |
| 1209 | LinkOutputKind::DynamicDylib => "dynamic-dylib" , |
| 1210 | LinkOutputKind::StaticDylib => "static-dylib" , |
| 1211 | LinkOutputKind::WasiReactorExe => "wasi-reactor-exe" , |
| 1212 | } |
| 1213 | } |
| 1214 | |
| 1215 | pub(super) fn from_str(s: &str) -> Option<LinkOutputKind> { |
| 1216 | Some(match s { |
| 1217 | "dynamic-nopic-exe" => LinkOutputKind::DynamicNoPicExe, |
| 1218 | "dynamic-pic-exe" => LinkOutputKind::DynamicPicExe, |
| 1219 | "static-nopic-exe" => LinkOutputKind::StaticNoPicExe, |
| 1220 | "static-pic-exe" => LinkOutputKind::StaticPicExe, |
| 1221 | "dynamic-dylib" => LinkOutputKind::DynamicDylib, |
| 1222 | "static-dylib" => LinkOutputKind::StaticDylib, |
| 1223 | "wasi-reactor-exe" => LinkOutputKind::WasiReactorExe, |
| 1224 | _ => return None, |
| 1225 | }) |
| 1226 | } |
| 1227 | |
| 1228 | pub fn can_link_dylib(self) -> bool { |
| 1229 | match self { |
| 1230 | LinkOutputKind::StaticNoPicExe | LinkOutputKind::StaticPicExe => false, |
| 1231 | LinkOutputKind::DynamicNoPicExe |
| 1232 | | LinkOutputKind::DynamicPicExe |
| 1233 | | LinkOutputKind::DynamicDylib |
| 1234 | | LinkOutputKind::StaticDylib |
| 1235 | | LinkOutputKind::WasiReactorExe => true, |
| 1236 | } |
| 1237 | } |
| 1238 | } |
| 1239 | |
| 1240 | impl fmt::Display for LinkOutputKind { |
| 1241 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 1242 | f.write_str(self.as_str()) |
| 1243 | } |
| 1244 | } |
| 1245 | |
| 1246 | pub type LinkArgs = BTreeMap<LinkerFlavor, Vec<StaticCow<str>>>; |
| 1247 | pub type LinkArgsCli = BTreeMap<LinkerFlavorCli, Vec<StaticCow<str>>>; |
| 1248 | |
| 1249 | /// Which kind of debuginfo does the target use? |
| 1250 | /// |
| 1251 | /// Useful in determining whether a target supports Split DWARF (a target with |
| 1252 | /// `DebuginfoKind::Dwarf` and supporting `SplitDebuginfo::Unpacked` for example). |
| 1253 | #[derive (Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] |
| 1254 | pub enum DebuginfoKind { |
| 1255 | /// DWARF debuginfo (such as that used on `x86_64_unknown_linux_gnu`). |
| 1256 | #[default] |
| 1257 | Dwarf, |
| 1258 | /// DWARF debuginfo in dSYM files (such as on Apple platforms). |
| 1259 | DwarfDsym, |
| 1260 | /// Program database files (such as on Windows). |
| 1261 | Pdb, |
| 1262 | } |
| 1263 | |
| 1264 | impl DebuginfoKind { |
| 1265 | fn as_str(&self) -> &'static str { |
| 1266 | match self { |
| 1267 | DebuginfoKind::Dwarf => "dwarf" , |
| 1268 | DebuginfoKind::DwarfDsym => "dwarf-dsym" , |
| 1269 | DebuginfoKind::Pdb => "pdb" , |
| 1270 | } |
| 1271 | } |
| 1272 | } |
| 1273 | |
| 1274 | impl FromStr for DebuginfoKind { |
| 1275 | type Err = (); |
| 1276 | |
| 1277 | fn from_str(s: &str) -> Result<Self, ()> { |
| 1278 | Ok(match s { |
| 1279 | "dwarf" => DebuginfoKind::Dwarf, |
| 1280 | "dwarf-dsym" => DebuginfoKind::DwarfDsym, |
| 1281 | "pdb" => DebuginfoKind::Pdb, |
| 1282 | _ => return Err(()), |
| 1283 | }) |
| 1284 | } |
| 1285 | } |
| 1286 | |
| 1287 | impl ToJson for DebuginfoKind { |
| 1288 | fn to_json(&self) -> Json { |
| 1289 | self.as_str().to_json() |
| 1290 | } |
| 1291 | } |
| 1292 | |
| 1293 | impl fmt::Display for DebuginfoKind { |
| 1294 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 1295 | f.write_str(self.as_str()) |
| 1296 | } |
| 1297 | } |
| 1298 | |
| 1299 | #[derive (Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] |
| 1300 | pub enum SplitDebuginfo { |
| 1301 | /// Split debug-information is disabled, meaning that on supported platforms |
| 1302 | /// you can find all debug information in the executable itself. This is |
| 1303 | /// only supported for ELF effectively. |
| 1304 | /// |
| 1305 | /// * Windows - not supported |
| 1306 | /// * macOS - don't run `dsymutil` |
| 1307 | /// * ELF - `.debug_*` sections |
| 1308 | #[default] |
| 1309 | Off, |
| 1310 | |
| 1311 | /// Split debug-information can be found in a "packed" location separate |
| 1312 | /// from the final artifact. This is supported on all platforms. |
| 1313 | /// |
| 1314 | /// * Windows - `*.pdb` |
| 1315 | /// * macOS - `*.dSYM` (run `dsymutil`) |
| 1316 | /// * ELF - `*.dwp` (run `thorin`) |
| 1317 | Packed, |
| 1318 | |
| 1319 | /// Split debug-information can be found in individual object files on the |
| 1320 | /// filesystem. The main executable may point to the object files. |
| 1321 | /// |
| 1322 | /// * Windows - not supported |
| 1323 | /// * macOS - supported, scattered object files |
| 1324 | /// * ELF - supported, scattered `*.dwo` or `*.o` files (see `SplitDwarfKind`) |
| 1325 | Unpacked, |
| 1326 | } |
| 1327 | |
| 1328 | impl SplitDebuginfo { |
| 1329 | fn as_str(&self) -> &'static str { |
| 1330 | match self { |
| 1331 | SplitDebuginfo::Off => "off" , |
| 1332 | SplitDebuginfo::Packed => "packed" , |
| 1333 | SplitDebuginfo::Unpacked => "unpacked" , |
| 1334 | } |
| 1335 | } |
| 1336 | } |
| 1337 | |
| 1338 | impl FromStr for SplitDebuginfo { |
| 1339 | type Err = (); |
| 1340 | |
| 1341 | fn from_str(s: &str) -> Result<Self, ()> { |
| 1342 | Ok(match s { |
| 1343 | "off" => SplitDebuginfo::Off, |
| 1344 | "unpacked" => SplitDebuginfo::Unpacked, |
| 1345 | "packed" => SplitDebuginfo::Packed, |
| 1346 | _ => return Err(()), |
| 1347 | }) |
| 1348 | } |
| 1349 | } |
| 1350 | |
| 1351 | impl ToJson for SplitDebuginfo { |
| 1352 | fn to_json(&self) -> Json { |
| 1353 | self.as_str().to_json() |
| 1354 | } |
| 1355 | } |
| 1356 | |
| 1357 | impl fmt::Display for SplitDebuginfo { |
| 1358 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 1359 | f.write_str(self.as_str()) |
| 1360 | } |
| 1361 | } |
| 1362 | |
| 1363 | #[derive (Clone, Debug, PartialEq, Eq)] |
| 1364 | pub enum StackProbeType { |
| 1365 | /// Don't emit any stack probes. |
| 1366 | None, |
| 1367 | /// It is harmless to use this option even on targets that do not have backend support for |
| 1368 | /// stack probes as the failure mode is the same as if no stack-probe option was specified in |
| 1369 | /// the first place. |
| 1370 | Inline, |
| 1371 | /// Call `__rust_probestack` whenever stack needs to be probed. |
| 1372 | Call, |
| 1373 | /// Use inline option for LLVM versions later than specified in `min_llvm_version_for_inline` |
| 1374 | /// and call `__rust_probestack` otherwise. |
| 1375 | InlineOrCall { min_llvm_version_for_inline: (u32, u32, u32) }, |
| 1376 | } |
| 1377 | |
| 1378 | impl StackProbeType { |
| 1379 | fn from_json(json: &Json) -> Result<Self, String> { |
| 1380 | let object = json.as_object().ok_or_else(|| "expected a JSON object" )?; |
| 1381 | let kind = object |
| 1382 | .get("kind" ) |
| 1383 | .and_then(|o| o.as_str()) |
| 1384 | .ok_or_else(|| "expected `kind` to be a string" )?; |
| 1385 | match kind { |
| 1386 | "none" => Ok(StackProbeType::None), |
| 1387 | "inline" => Ok(StackProbeType::Inline), |
| 1388 | "call" => Ok(StackProbeType::Call), |
| 1389 | "inline-or-call" => { |
| 1390 | let min_version = object |
| 1391 | .get("min-llvm-version-for-inline" ) |
| 1392 | .and_then(|o| o.as_array()) |
| 1393 | .ok_or_else(|| "expected `min-llvm-version-for-inline` to be an array" )?; |
| 1394 | let mut iter = min_version.into_iter().map(|v| { |
| 1395 | let int = v.as_u64().ok_or_else( |
| 1396 | || "expected `min-llvm-version-for-inline` values to be integers" , |
| 1397 | )?; |
| 1398 | u32::try_from(int) |
| 1399 | .map_err(|_| "`min-llvm-version-for-inline` values don't convert to u32" ) |
| 1400 | }); |
| 1401 | let min_llvm_version_for_inline = ( |
| 1402 | iter.next().unwrap_or(Ok(11))?, |
| 1403 | iter.next().unwrap_or(Ok(0))?, |
| 1404 | iter.next().unwrap_or(Ok(0))?, |
| 1405 | ); |
| 1406 | Ok(StackProbeType::InlineOrCall { min_llvm_version_for_inline }) |
| 1407 | } |
| 1408 | _ => Err(String::from( |
| 1409 | "`kind` expected to be one of `none`, `inline`, `call` or `inline-or-call`" , |
| 1410 | )), |
| 1411 | } |
| 1412 | } |
| 1413 | } |
| 1414 | |
| 1415 | impl ToJson for StackProbeType { |
| 1416 | fn to_json(&self) -> Json { |
| 1417 | Json::Object(match self { |
| 1418 | StackProbeType::None => { |
| 1419 | [(String::from("kind" ), "none" .to_json())].into_iter().collect() |
| 1420 | } |
| 1421 | StackProbeType::Inline => { |
| 1422 | [(String::from("kind" ), "inline" .to_json())].into_iter().collect() |
| 1423 | } |
| 1424 | StackProbeType::Call => { |
| 1425 | [(String::from("kind" ), "call" .to_json())].into_iter().collect() |
| 1426 | } |
| 1427 | StackProbeType::InlineOrCall { min_llvm_version_for_inline: (maj: &u32, min: &u32, patch: &u32) } => [ |
| 1428 | (String::from("kind" ), "inline-or-call" .to_json()), |
| 1429 | ( |
| 1430 | String::from("min-llvm-version-for-inline" ), |
| 1431 | Json::Array(vec![maj.to_json(), min.to_json(), patch.to_json()]), |
| 1432 | ), |
| 1433 | ] |
| 1434 | .into_iter() |
| 1435 | .collect(), |
| 1436 | }) |
| 1437 | } |
| 1438 | } |
| 1439 | |
| 1440 | #[derive (Default, Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)] |
| 1441 | pub struct SanitizerSet(u16); |
| 1442 | bitflags::bitflags! { |
| 1443 | impl SanitizerSet: u16 { |
| 1444 | const ADDRESS = 1 << 0; |
| 1445 | const LEAK = 1 << 1; |
| 1446 | const MEMORY = 1 << 2; |
| 1447 | const THREAD = 1 << 3; |
| 1448 | const HWADDRESS = 1 << 4; |
| 1449 | const CFI = 1 << 5; |
| 1450 | const MEMTAG = 1 << 6; |
| 1451 | const SHADOWCALLSTACK = 1 << 7; |
| 1452 | const KCFI = 1 << 8; |
| 1453 | const KERNELADDRESS = 1 << 9; |
| 1454 | const SAFESTACK = 1 << 10; |
| 1455 | const DATAFLOW = 1 << 11; |
| 1456 | } |
| 1457 | } |
| 1458 | rustc_data_structures::external_bitflags_debug! { SanitizerSet } |
| 1459 | |
| 1460 | impl SanitizerSet { |
| 1461 | // Taken from LLVM's sanitizer compatibility logic: |
| 1462 | // https://github.com/llvm/llvm-project/blob/release/18.x/clang/lib/Driver/SanitizerArgs.cpp#L512 |
| 1463 | const MUTUALLY_EXCLUSIVE: &'static [(SanitizerSet, SanitizerSet)] = &[ |
| 1464 | (SanitizerSet::ADDRESS, SanitizerSet::MEMORY), |
| 1465 | (SanitizerSet::ADDRESS, SanitizerSet::THREAD), |
| 1466 | (SanitizerSet::ADDRESS, SanitizerSet::HWADDRESS), |
| 1467 | (SanitizerSet::ADDRESS, SanitizerSet::MEMTAG), |
| 1468 | (SanitizerSet::ADDRESS, SanitizerSet::KERNELADDRESS), |
| 1469 | (SanitizerSet::ADDRESS, SanitizerSet::SAFESTACK), |
| 1470 | (SanitizerSet::LEAK, SanitizerSet::MEMORY), |
| 1471 | (SanitizerSet::LEAK, SanitizerSet::THREAD), |
| 1472 | (SanitizerSet::LEAK, SanitizerSet::KERNELADDRESS), |
| 1473 | (SanitizerSet::LEAK, SanitizerSet::SAFESTACK), |
| 1474 | (SanitizerSet::MEMORY, SanitizerSet::THREAD), |
| 1475 | (SanitizerSet::MEMORY, SanitizerSet::HWADDRESS), |
| 1476 | (SanitizerSet::MEMORY, SanitizerSet::KERNELADDRESS), |
| 1477 | (SanitizerSet::MEMORY, SanitizerSet::SAFESTACK), |
| 1478 | (SanitizerSet::THREAD, SanitizerSet::HWADDRESS), |
| 1479 | (SanitizerSet::THREAD, SanitizerSet::KERNELADDRESS), |
| 1480 | (SanitizerSet::THREAD, SanitizerSet::SAFESTACK), |
| 1481 | (SanitizerSet::HWADDRESS, SanitizerSet::MEMTAG), |
| 1482 | (SanitizerSet::HWADDRESS, SanitizerSet::KERNELADDRESS), |
| 1483 | (SanitizerSet::HWADDRESS, SanitizerSet::SAFESTACK), |
| 1484 | (SanitizerSet::CFI, SanitizerSet::KCFI), |
| 1485 | (SanitizerSet::MEMTAG, SanitizerSet::KERNELADDRESS), |
| 1486 | (SanitizerSet::KERNELADDRESS, SanitizerSet::SAFESTACK), |
| 1487 | ]; |
| 1488 | |
| 1489 | /// Return sanitizer's name |
| 1490 | /// |
| 1491 | /// Returns none if the flags is a set of sanitizers numbering not exactly one. |
| 1492 | pub fn as_str(self) -> Option<&'static str> { |
| 1493 | Some(match self { |
| 1494 | SanitizerSet::ADDRESS => "address" , |
| 1495 | SanitizerSet::CFI => "cfi" , |
| 1496 | SanitizerSet::DATAFLOW => "dataflow" , |
| 1497 | SanitizerSet::KCFI => "kcfi" , |
| 1498 | SanitizerSet::KERNELADDRESS => "kernel-address" , |
| 1499 | SanitizerSet::LEAK => "leak" , |
| 1500 | SanitizerSet::MEMORY => "memory" , |
| 1501 | SanitizerSet::MEMTAG => "memtag" , |
| 1502 | SanitizerSet::SAFESTACK => "safestack" , |
| 1503 | SanitizerSet::SHADOWCALLSTACK => "shadow-call-stack" , |
| 1504 | SanitizerSet::THREAD => "thread" , |
| 1505 | SanitizerSet::HWADDRESS => "hwaddress" , |
| 1506 | _ => return None, |
| 1507 | }) |
| 1508 | } |
| 1509 | |
| 1510 | pub fn mutually_exclusive(self) -> Option<(SanitizerSet, SanitizerSet)> { |
| 1511 | Self::MUTUALLY_EXCLUSIVE |
| 1512 | .into_iter() |
| 1513 | .find(|&(a, b)| self.contains(*a) && self.contains(*b)) |
| 1514 | .copied() |
| 1515 | } |
| 1516 | } |
| 1517 | |
| 1518 | /// Formats a sanitizer set as a comma separated list of sanitizers' names. |
| 1519 | impl fmt::Display for SanitizerSet { |
| 1520 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 1521 | let mut first: bool = true; |
| 1522 | for s: SanitizerSet in *self { |
| 1523 | let name: &'static str = s.as_str().unwrap_or_else(|| panic!("unrecognized sanitizer {s:?}" )); |
| 1524 | if !first { |
| 1525 | f.write_str(data:", " )?; |
| 1526 | } |
| 1527 | f.write_str(data:name)?; |
| 1528 | first = false; |
| 1529 | } |
| 1530 | Ok(()) |
| 1531 | } |
| 1532 | } |
| 1533 | |
| 1534 | impl ToJson for SanitizerSet { |
| 1535 | fn to_json(&self) -> Json { |
| 1536 | self.into_iter() |
| 1537 | .map(|v: SanitizerSet| Some(v.as_str()?.to_json())) |
| 1538 | .collect::<Option<Vec<_>>>() |
| 1539 | .unwrap_or_default() |
| 1540 | .to_json() |
| 1541 | } |
| 1542 | } |
| 1543 | |
| 1544 | #[derive (Clone, Copy, PartialEq, Hash, Debug)] |
| 1545 | pub enum FramePointer { |
| 1546 | /// Forces the machine code generator to always preserve the frame pointers. |
| 1547 | Always, |
| 1548 | /// Forces the machine code generator to preserve the frame pointers except for the leaf |
| 1549 | /// functions (i.e. those that don't call other functions). |
| 1550 | NonLeaf, |
| 1551 | /// Allows the machine code generator to omit the frame pointers. |
| 1552 | /// |
| 1553 | /// This option does not guarantee that the frame pointers will be omitted. |
| 1554 | MayOmit, |
| 1555 | } |
| 1556 | |
| 1557 | impl FramePointer { |
| 1558 | /// It is intended that the "force frame pointer" transition is "one way" |
| 1559 | /// so this convenience assures such if used |
| 1560 | #[inline ] |
| 1561 | pub fn ratchet(&mut self, rhs: FramePointer) -> FramePointer { |
| 1562 | *self = match (*self, rhs) { |
| 1563 | (FramePointer::Always, _) | (_, FramePointer::Always) => FramePointer::Always, |
| 1564 | (FramePointer::NonLeaf, _) | (_, FramePointer::NonLeaf) => FramePointer::NonLeaf, |
| 1565 | _ => FramePointer::MayOmit, |
| 1566 | }; |
| 1567 | *self |
| 1568 | } |
| 1569 | } |
| 1570 | |
| 1571 | impl FromStr for FramePointer { |
| 1572 | type Err = (); |
| 1573 | fn from_str(s: &str) -> Result<Self, ()> { |
| 1574 | Ok(match s { |
| 1575 | "always" => Self::Always, |
| 1576 | "non-leaf" => Self::NonLeaf, |
| 1577 | "may-omit" => Self::MayOmit, |
| 1578 | _ => return Err(()), |
| 1579 | }) |
| 1580 | } |
| 1581 | } |
| 1582 | |
| 1583 | impl ToJson for FramePointer { |
| 1584 | fn to_json(&self) -> Json { |
| 1585 | match&'static str *self { |
| 1586 | Self::Always => "always" , |
| 1587 | Self::NonLeaf => "non-leaf" , |
| 1588 | Self::MayOmit => "may-omit" , |
| 1589 | } |
| 1590 | .to_json() |
| 1591 | } |
| 1592 | } |
| 1593 | |
| 1594 | /// Controls use of stack canaries. |
| 1595 | #[derive (Clone, Copy, Debug, PartialEq, Hash, Eq)] |
| 1596 | pub enum StackProtector { |
| 1597 | /// Disable stack canary generation. |
| 1598 | None, |
| 1599 | |
| 1600 | /// On LLVM, mark all generated LLVM functions with the `ssp` attribute (see |
| 1601 | /// llvm/docs/LangRef.rst). This triggers stack canary generation in |
| 1602 | /// functions which contain an array of a byte-sized type with more than |
| 1603 | /// eight elements. |
| 1604 | Basic, |
| 1605 | |
| 1606 | /// On LLVM, mark all generated LLVM functions with the `sspstrong` |
| 1607 | /// attribute (see llvm/docs/LangRef.rst). This triggers stack canary |
| 1608 | /// generation in functions which either contain an array, or which take |
| 1609 | /// the address of a local variable. |
| 1610 | Strong, |
| 1611 | |
| 1612 | /// Generate stack canaries in all functions. |
| 1613 | All, |
| 1614 | } |
| 1615 | |
| 1616 | impl StackProtector { |
| 1617 | fn as_str(&self) -> &'static str { |
| 1618 | match self { |
| 1619 | StackProtector::None => "none" , |
| 1620 | StackProtector::Basic => "basic" , |
| 1621 | StackProtector::Strong => "strong" , |
| 1622 | StackProtector::All => "all" , |
| 1623 | } |
| 1624 | } |
| 1625 | } |
| 1626 | |
| 1627 | impl FromStr for StackProtector { |
| 1628 | type Err = (); |
| 1629 | |
| 1630 | fn from_str(s: &str) -> Result<StackProtector, ()> { |
| 1631 | Ok(match s { |
| 1632 | "none" => StackProtector::None, |
| 1633 | "basic" => StackProtector::Basic, |
| 1634 | "strong" => StackProtector::Strong, |
| 1635 | "all" => StackProtector::All, |
| 1636 | _ => return Err(()), |
| 1637 | }) |
| 1638 | } |
| 1639 | } |
| 1640 | |
| 1641 | impl fmt::Display for StackProtector { |
| 1642 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 1643 | f.write_str(self.as_str()) |
| 1644 | } |
| 1645 | } |
| 1646 | |
| 1647 | #[derive (PartialEq, Clone, Debug)] |
| 1648 | pub enum BinaryFormat { |
| 1649 | Coff, |
| 1650 | Elf, |
| 1651 | MachO, |
| 1652 | Wasm, |
| 1653 | Xcoff, |
| 1654 | } |
| 1655 | |
| 1656 | impl BinaryFormat { |
| 1657 | /// Returns [`object::BinaryFormat`] for given `BinaryFormat` |
| 1658 | pub fn to_object(&self) -> object::BinaryFormat { |
| 1659 | match self { |
| 1660 | Self::Coff => object::BinaryFormat::Coff, |
| 1661 | Self::Elf => object::BinaryFormat::Elf, |
| 1662 | Self::MachO => object::BinaryFormat::MachO, |
| 1663 | Self::Wasm => object::BinaryFormat::Wasm, |
| 1664 | Self::Xcoff => object::BinaryFormat::Xcoff, |
| 1665 | } |
| 1666 | } |
| 1667 | } |
| 1668 | |
| 1669 | impl FromStr for BinaryFormat { |
| 1670 | type Err = (); |
| 1671 | fn from_str(s: &str) -> Result<Self, Self::Err> { |
| 1672 | match s { |
| 1673 | "coff" => Ok(Self::Coff), |
| 1674 | "elf" => Ok(Self::Elf), |
| 1675 | "mach-o" => Ok(Self::MachO), |
| 1676 | "wasm" => Ok(Self::Wasm), |
| 1677 | "xcoff" => Ok(Self::Xcoff), |
| 1678 | _ => Err(()), |
| 1679 | } |
| 1680 | } |
| 1681 | } |
| 1682 | |
| 1683 | impl ToJson for BinaryFormat { |
| 1684 | fn to_json(&self) -> Json { |
| 1685 | match&'static str self { |
| 1686 | Self::Coff => "coff" , |
| 1687 | Self::Elf => "elf" , |
| 1688 | Self::MachO => "mach-o" , |
| 1689 | Self::Wasm => "wasm" , |
| 1690 | Self::Xcoff => "xcoff" , |
| 1691 | } |
| 1692 | .to_json() |
| 1693 | } |
| 1694 | } |
| 1695 | |
| 1696 | macro_rules! supported_targets { |
| 1697 | ( $(($tuple:literal, $module:ident),)+ ) => { |
| 1698 | mod targets { |
| 1699 | $(pub(crate) mod $module;)+ |
| 1700 | } |
| 1701 | |
| 1702 | /// List of supported targets |
| 1703 | pub static TARGETS: &[&str] = &[$($tuple),+]; |
| 1704 | |
| 1705 | fn load_builtin(target: &str) -> Option<Target> { |
| 1706 | let t = match target { |
| 1707 | $( $tuple => targets::$module::target(), )+ |
| 1708 | _ => return None, |
| 1709 | }; |
| 1710 | debug!("got builtin target: {:?}" , t); |
| 1711 | Some(t) |
| 1712 | } |
| 1713 | |
| 1714 | fn load_all_builtins() -> impl Iterator<Item = Target> { |
| 1715 | [ |
| 1716 | $( targets::$module::target, )+ |
| 1717 | ] |
| 1718 | .into_iter() |
| 1719 | .map(|f| f()) |
| 1720 | } |
| 1721 | |
| 1722 | #[cfg(test)] |
| 1723 | mod tests { |
| 1724 | // Cannot put this into a separate file without duplication, make an exception. |
| 1725 | $( |
| 1726 | #[test] // `#[test]` |
| 1727 | fn $module() { |
| 1728 | crate::spec::targets::$module::target().test_target() |
| 1729 | } |
| 1730 | )+ |
| 1731 | } |
| 1732 | }; |
| 1733 | } |
| 1734 | |
| 1735 | supported_targets! { |
| 1736 | ("x86_64-unknown-linux-gnu" , x86_64_unknown_linux_gnu), |
| 1737 | ("x86_64-unknown-linux-gnux32" , x86_64_unknown_linux_gnux32), |
| 1738 | ("i686-unknown-linux-gnu" , i686_unknown_linux_gnu), |
| 1739 | ("i586-unknown-linux-gnu" , i586_unknown_linux_gnu), |
| 1740 | ("loongarch64-unknown-linux-gnu" , loongarch64_unknown_linux_gnu), |
| 1741 | ("loongarch64-unknown-linux-musl" , loongarch64_unknown_linux_musl), |
| 1742 | ("m68k-unknown-linux-gnu" , m68k_unknown_linux_gnu), |
| 1743 | ("m68k-unknown-none-elf" , m68k_unknown_none_elf), |
| 1744 | ("csky-unknown-linux-gnuabiv2" , csky_unknown_linux_gnuabiv2), |
| 1745 | ("csky-unknown-linux-gnuabiv2hf" , csky_unknown_linux_gnuabiv2hf), |
| 1746 | ("mips-unknown-linux-gnu" , mips_unknown_linux_gnu), |
| 1747 | ("mips64-unknown-linux-gnuabi64" , mips64_unknown_linux_gnuabi64), |
| 1748 | ("mips64el-unknown-linux-gnuabi64" , mips64el_unknown_linux_gnuabi64), |
| 1749 | ("mipsisa32r6-unknown-linux-gnu" , mipsisa32r6_unknown_linux_gnu), |
| 1750 | ("mipsisa32r6el-unknown-linux-gnu" , mipsisa32r6el_unknown_linux_gnu), |
| 1751 | ("mipsisa64r6-unknown-linux-gnuabi64" , mipsisa64r6_unknown_linux_gnuabi64), |
| 1752 | ("mipsisa64r6el-unknown-linux-gnuabi64" , mipsisa64r6el_unknown_linux_gnuabi64), |
| 1753 | ("mipsel-unknown-linux-gnu" , mipsel_unknown_linux_gnu), |
| 1754 | ("powerpc-unknown-linux-gnu" , powerpc_unknown_linux_gnu), |
| 1755 | ("powerpc-unknown-linux-gnuspe" , powerpc_unknown_linux_gnuspe), |
| 1756 | ("powerpc-unknown-linux-musl" , powerpc_unknown_linux_musl), |
| 1757 | ("powerpc-unknown-linux-muslspe" , powerpc_unknown_linux_muslspe), |
| 1758 | ("powerpc64-ibm-aix" , powerpc64_ibm_aix), |
| 1759 | ("powerpc64-unknown-linux-gnu" , powerpc64_unknown_linux_gnu), |
| 1760 | ("powerpc64-unknown-linux-musl" , powerpc64_unknown_linux_musl), |
| 1761 | ("powerpc64le-unknown-linux-gnu" , powerpc64le_unknown_linux_gnu), |
| 1762 | ("powerpc64le-unknown-linux-musl" , powerpc64le_unknown_linux_musl), |
| 1763 | ("s390x-unknown-linux-gnu" , s390x_unknown_linux_gnu), |
| 1764 | ("s390x-unknown-linux-musl" , s390x_unknown_linux_musl), |
| 1765 | ("sparc-unknown-linux-gnu" , sparc_unknown_linux_gnu), |
| 1766 | ("sparc64-unknown-linux-gnu" , sparc64_unknown_linux_gnu), |
| 1767 | ("arm-unknown-linux-gnueabi" , arm_unknown_linux_gnueabi), |
| 1768 | ("arm-unknown-linux-gnueabihf" , arm_unknown_linux_gnueabihf), |
| 1769 | ("armeb-unknown-linux-gnueabi" , armeb_unknown_linux_gnueabi), |
| 1770 | ("arm-unknown-linux-musleabi" , arm_unknown_linux_musleabi), |
| 1771 | ("arm-unknown-linux-musleabihf" , arm_unknown_linux_musleabihf), |
| 1772 | ("armv4t-unknown-linux-gnueabi" , armv4t_unknown_linux_gnueabi), |
| 1773 | ("armv5te-unknown-linux-gnueabi" , armv5te_unknown_linux_gnueabi), |
| 1774 | ("armv5te-unknown-linux-musleabi" , armv5te_unknown_linux_musleabi), |
| 1775 | ("armv5te-unknown-linux-uclibceabi" , armv5te_unknown_linux_uclibceabi), |
| 1776 | ("armv7-unknown-linux-gnueabi" , armv7_unknown_linux_gnueabi), |
| 1777 | ("armv7-unknown-linux-gnueabihf" , armv7_unknown_linux_gnueabihf), |
| 1778 | ("thumbv7neon-unknown-linux-gnueabihf" , thumbv7neon_unknown_linux_gnueabihf), |
| 1779 | ("thumbv7neon-unknown-linux-musleabihf" , thumbv7neon_unknown_linux_musleabihf), |
| 1780 | ("armv7-unknown-linux-musleabi" , armv7_unknown_linux_musleabi), |
| 1781 | ("armv7-unknown-linux-musleabihf" , armv7_unknown_linux_musleabihf), |
| 1782 | ("aarch64-unknown-linux-gnu" , aarch64_unknown_linux_gnu), |
| 1783 | ("aarch64-unknown-linux-musl" , aarch64_unknown_linux_musl), |
| 1784 | ("x86_64-unknown-linux-musl" , x86_64_unknown_linux_musl), |
| 1785 | ("i686-unknown-linux-musl" , i686_unknown_linux_musl), |
| 1786 | ("i586-unknown-linux-musl" , i586_unknown_linux_musl), |
| 1787 | ("mips-unknown-linux-musl" , mips_unknown_linux_musl), |
| 1788 | ("mipsel-unknown-linux-musl" , mipsel_unknown_linux_musl), |
| 1789 | ("mips64-unknown-linux-muslabi64" , mips64_unknown_linux_muslabi64), |
| 1790 | ("mips64el-unknown-linux-muslabi64" , mips64el_unknown_linux_muslabi64), |
| 1791 | ("hexagon-unknown-linux-musl" , hexagon_unknown_linux_musl), |
| 1792 | ("hexagon-unknown-none-elf" , hexagon_unknown_none_elf), |
| 1793 | |
| 1794 | ("mips-unknown-linux-uclibc" , mips_unknown_linux_uclibc), |
| 1795 | ("mipsel-unknown-linux-uclibc" , mipsel_unknown_linux_uclibc), |
| 1796 | |
| 1797 | ("i686-linux-android" , i686_linux_android), |
| 1798 | ("x86_64-linux-android" , x86_64_linux_android), |
| 1799 | ("arm-linux-androideabi" , arm_linux_androideabi), |
| 1800 | ("armv7-linux-androideabi" , armv7_linux_androideabi), |
| 1801 | ("thumbv7neon-linux-androideabi" , thumbv7neon_linux_androideabi), |
| 1802 | ("aarch64-linux-android" , aarch64_linux_android), |
| 1803 | ("riscv64-linux-android" , riscv64_linux_android), |
| 1804 | |
| 1805 | ("aarch64-unknown-freebsd" , aarch64_unknown_freebsd), |
| 1806 | ("armv6-unknown-freebsd" , armv6_unknown_freebsd), |
| 1807 | ("armv7-unknown-freebsd" , armv7_unknown_freebsd), |
| 1808 | ("i686-unknown-freebsd" , i686_unknown_freebsd), |
| 1809 | ("powerpc-unknown-freebsd" , powerpc_unknown_freebsd), |
| 1810 | ("powerpc64-unknown-freebsd" , powerpc64_unknown_freebsd), |
| 1811 | ("powerpc64le-unknown-freebsd" , powerpc64le_unknown_freebsd), |
| 1812 | ("riscv64gc-unknown-freebsd" , riscv64gc_unknown_freebsd), |
| 1813 | ("x86_64-unknown-freebsd" , x86_64_unknown_freebsd), |
| 1814 | |
| 1815 | ("x86_64-unknown-dragonfly" , x86_64_unknown_dragonfly), |
| 1816 | |
| 1817 | ("aarch64-unknown-openbsd" , aarch64_unknown_openbsd), |
| 1818 | ("i686-unknown-openbsd" , i686_unknown_openbsd), |
| 1819 | ("powerpc-unknown-openbsd" , powerpc_unknown_openbsd), |
| 1820 | ("powerpc64-unknown-openbsd" , powerpc64_unknown_openbsd), |
| 1821 | ("riscv64gc-unknown-openbsd" , riscv64gc_unknown_openbsd), |
| 1822 | ("sparc64-unknown-openbsd" , sparc64_unknown_openbsd), |
| 1823 | ("x86_64-unknown-openbsd" , x86_64_unknown_openbsd), |
| 1824 | |
| 1825 | ("aarch64-unknown-netbsd" , aarch64_unknown_netbsd), |
| 1826 | ("aarch64_be-unknown-netbsd" , aarch64_be_unknown_netbsd), |
| 1827 | ("armv6-unknown-netbsd-eabihf" , armv6_unknown_netbsd_eabihf), |
| 1828 | ("armv7-unknown-netbsd-eabihf" , armv7_unknown_netbsd_eabihf), |
| 1829 | ("i586-unknown-netbsd" , i586_unknown_netbsd), |
| 1830 | ("i686-unknown-netbsd" , i686_unknown_netbsd), |
| 1831 | ("mipsel-unknown-netbsd" , mipsel_unknown_netbsd), |
| 1832 | ("powerpc-unknown-netbsd" , powerpc_unknown_netbsd), |
| 1833 | ("riscv64gc-unknown-netbsd" , riscv64gc_unknown_netbsd), |
| 1834 | ("sparc64-unknown-netbsd" , sparc64_unknown_netbsd), |
| 1835 | ("x86_64-unknown-netbsd" , x86_64_unknown_netbsd), |
| 1836 | |
| 1837 | ("i686-unknown-haiku" , i686_unknown_haiku), |
| 1838 | ("x86_64-unknown-haiku" , x86_64_unknown_haiku), |
| 1839 | |
| 1840 | ("i686-unknown-hurd-gnu" , i686_unknown_hurd_gnu), |
| 1841 | ("x86_64-unknown-hurd-gnu" , x86_64_unknown_hurd_gnu), |
| 1842 | |
| 1843 | ("aarch64-apple-darwin" , aarch64_apple_darwin), |
| 1844 | ("arm64e-apple-darwin" , arm64e_apple_darwin), |
| 1845 | ("x86_64-apple-darwin" , x86_64_apple_darwin), |
| 1846 | ("x86_64h-apple-darwin" , x86_64h_apple_darwin), |
| 1847 | ("i686-apple-darwin" , i686_apple_darwin), |
| 1848 | |
| 1849 | ("aarch64-unknown-fuchsia" , aarch64_unknown_fuchsia), |
| 1850 | ("riscv64gc-unknown-fuchsia" , riscv64gc_unknown_fuchsia), |
| 1851 | ("x86_64-unknown-fuchsia" , x86_64_unknown_fuchsia), |
| 1852 | |
| 1853 | ("avr-none" , avr_none), |
| 1854 | |
| 1855 | ("x86_64-unknown-l4re-uclibc" , x86_64_unknown_l4re_uclibc), |
| 1856 | |
| 1857 | ("aarch64-unknown-redox" , aarch64_unknown_redox), |
| 1858 | ("i586-unknown-redox" , i586_unknown_redox), |
| 1859 | ("x86_64-unknown-redox" , x86_64_unknown_redox), |
| 1860 | |
| 1861 | ("i386-apple-ios" , i386_apple_ios), |
| 1862 | ("x86_64-apple-ios" , x86_64_apple_ios), |
| 1863 | ("aarch64-apple-ios" , aarch64_apple_ios), |
| 1864 | ("arm64e-apple-ios" , arm64e_apple_ios), |
| 1865 | ("armv7s-apple-ios" , armv7s_apple_ios), |
| 1866 | ("x86_64-apple-ios-macabi" , x86_64_apple_ios_macabi), |
| 1867 | ("aarch64-apple-ios-macabi" , aarch64_apple_ios_macabi), |
| 1868 | ("aarch64-apple-ios-sim" , aarch64_apple_ios_sim), |
| 1869 | |
| 1870 | ("aarch64-apple-tvos" , aarch64_apple_tvos), |
| 1871 | ("aarch64-apple-tvos-sim" , aarch64_apple_tvos_sim), |
| 1872 | ("arm64e-apple-tvos" , arm64e_apple_tvos), |
| 1873 | ("x86_64-apple-tvos" , x86_64_apple_tvos), |
| 1874 | |
| 1875 | ("armv7k-apple-watchos" , armv7k_apple_watchos), |
| 1876 | ("arm64_32-apple-watchos" , arm64_32_apple_watchos), |
| 1877 | ("x86_64-apple-watchos-sim" , x86_64_apple_watchos_sim), |
| 1878 | ("aarch64-apple-watchos" , aarch64_apple_watchos), |
| 1879 | ("aarch64-apple-watchos-sim" , aarch64_apple_watchos_sim), |
| 1880 | |
| 1881 | ("aarch64-apple-visionos" , aarch64_apple_visionos), |
| 1882 | ("aarch64-apple-visionos-sim" , aarch64_apple_visionos_sim), |
| 1883 | |
| 1884 | ("armebv7r-none-eabi" , armebv7r_none_eabi), |
| 1885 | ("armebv7r-none-eabihf" , armebv7r_none_eabihf), |
| 1886 | ("armv7r-none-eabi" , armv7r_none_eabi), |
| 1887 | ("armv7r-none-eabihf" , armv7r_none_eabihf), |
| 1888 | ("armv8r-none-eabihf" , armv8r_none_eabihf), |
| 1889 | |
| 1890 | ("armv7-rtems-eabihf" , armv7_rtems_eabihf), |
| 1891 | |
| 1892 | ("x86_64-pc-solaris" , x86_64_pc_solaris), |
| 1893 | ("sparcv9-sun-solaris" , sparcv9_sun_solaris), |
| 1894 | |
| 1895 | ("x86_64-unknown-illumos" , x86_64_unknown_illumos), |
| 1896 | ("aarch64-unknown-illumos" , aarch64_unknown_illumos), |
| 1897 | |
| 1898 | ("x86_64-pc-windows-gnu" , x86_64_pc_windows_gnu), |
| 1899 | ("x86_64-uwp-windows-gnu" , x86_64_uwp_windows_gnu), |
| 1900 | ("x86_64-win7-windows-gnu" , x86_64_win7_windows_gnu), |
| 1901 | ("i686-pc-windows-gnu" , i686_pc_windows_gnu), |
| 1902 | ("i686-uwp-windows-gnu" , i686_uwp_windows_gnu), |
| 1903 | ("i686-win7-windows-gnu" , i686_win7_windows_gnu), |
| 1904 | |
| 1905 | ("aarch64-pc-windows-gnullvm" , aarch64_pc_windows_gnullvm), |
| 1906 | ("i686-pc-windows-gnullvm" , i686_pc_windows_gnullvm), |
| 1907 | ("x86_64-pc-windows-gnullvm" , x86_64_pc_windows_gnullvm), |
| 1908 | |
| 1909 | ("aarch64-pc-windows-msvc" , aarch64_pc_windows_msvc), |
| 1910 | ("aarch64-uwp-windows-msvc" , aarch64_uwp_windows_msvc), |
| 1911 | ("arm64ec-pc-windows-msvc" , arm64ec_pc_windows_msvc), |
| 1912 | ("x86_64-pc-windows-msvc" , x86_64_pc_windows_msvc), |
| 1913 | ("x86_64-uwp-windows-msvc" , x86_64_uwp_windows_msvc), |
| 1914 | ("x86_64-win7-windows-msvc" , x86_64_win7_windows_msvc), |
| 1915 | ("i686-pc-windows-msvc" , i686_pc_windows_msvc), |
| 1916 | ("i686-uwp-windows-msvc" , i686_uwp_windows_msvc), |
| 1917 | ("i686-win7-windows-msvc" , i686_win7_windows_msvc), |
| 1918 | ("thumbv7a-pc-windows-msvc" , thumbv7a_pc_windows_msvc), |
| 1919 | ("thumbv7a-uwp-windows-msvc" , thumbv7a_uwp_windows_msvc), |
| 1920 | |
| 1921 | ("wasm32-unknown-emscripten" , wasm32_unknown_emscripten), |
| 1922 | ("wasm32-unknown-unknown" , wasm32_unknown_unknown), |
| 1923 | ("wasm32v1-none" , wasm32v1_none), |
| 1924 | ("wasm32-wasip1" , wasm32_wasip1), |
| 1925 | ("wasm32-wasip2" , wasm32_wasip2), |
| 1926 | ("wasm32-wasip1-threads" , wasm32_wasip1_threads), |
| 1927 | ("wasm32-wali-linux-musl" , wasm32_wali_linux_musl), |
| 1928 | ("wasm64-unknown-unknown" , wasm64_unknown_unknown), |
| 1929 | |
| 1930 | ("thumbv6m-none-eabi" , thumbv6m_none_eabi), |
| 1931 | ("thumbv7m-none-eabi" , thumbv7m_none_eabi), |
| 1932 | ("thumbv7em-none-eabi" , thumbv7em_none_eabi), |
| 1933 | ("thumbv7em-none-eabihf" , thumbv7em_none_eabihf), |
| 1934 | ("thumbv8m.base-none-eabi" , thumbv8m_base_none_eabi), |
| 1935 | ("thumbv8m.main-none-eabi" , thumbv8m_main_none_eabi), |
| 1936 | ("thumbv8m.main-none-eabihf" , thumbv8m_main_none_eabihf), |
| 1937 | |
| 1938 | ("armv7a-none-eabi" , armv7a_none_eabi), |
| 1939 | ("armv7a-none-eabihf" , armv7a_none_eabihf), |
| 1940 | ("armv7a-nuttx-eabi" , armv7a_nuttx_eabi), |
| 1941 | ("armv7a-nuttx-eabihf" , armv7a_nuttx_eabihf), |
| 1942 | |
| 1943 | ("msp430-none-elf" , msp430_none_elf), |
| 1944 | |
| 1945 | ("aarch64-unknown-hermit" , aarch64_unknown_hermit), |
| 1946 | ("riscv64gc-unknown-hermit" , riscv64gc_unknown_hermit), |
| 1947 | ("x86_64-unknown-hermit" , x86_64_unknown_hermit), |
| 1948 | |
| 1949 | ("x86_64-unikraft-linux-musl" , x86_64_unikraft_linux_musl), |
| 1950 | |
| 1951 | ("armv7-unknown-trusty" , armv7_unknown_trusty), |
| 1952 | ("aarch64-unknown-trusty" , aarch64_unknown_trusty), |
| 1953 | ("x86_64-unknown-trusty" , x86_64_unknown_trusty), |
| 1954 | |
| 1955 | ("riscv32i-unknown-none-elf" , riscv32i_unknown_none_elf), |
| 1956 | ("riscv32im-risc0-zkvm-elf" , riscv32im_risc0_zkvm_elf), |
| 1957 | ("riscv32im-unknown-none-elf" , riscv32im_unknown_none_elf), |
| 1958 | ("riscv32ima-unknown-none-elf" , riscv32ima_unknown_none_elf), |
| 1959 | ("riscv32imc-unknown-none-elf" , riscv32imc_unknown_none_elf), |
| 1960 | ("riscv32imc-esp-espidf" , riscv32imc_esp_espidf), |
| 1961 | ("riscv32imac-esp-espidf" , riscv32imac_esp_espidf), |
| 1962 | ("riscv32imafc-esp-espidf" , riscv32imafc_esp_espidf), |
| 1963 | |
| 1964 | ("riscv32e-unknown-none-elf" , riscv32e_unknown_none_elf), |
| 1965 | ("riscv32em-unknown-none-elf" , riscv32em_unknown_none_elf), |
| 1966 | ("riscv32emc-unknown-none-elf" , riscv32emc_unknown_none_elf), |
| 1967 | |
| 1968 | ("riscv32imac-unknown-none-elf" , riscv32imac_unknown_none_elf), |
| 1969 | ("riscv32imafc-unknown-none-elf" , riscv32imafc_unknown_none_elf), |
| 1970 | ("riscv32imac-unknown-xous-elf" , riscv32imac_unknown_xous_elf), |
| 1971 | ("riscv32gc-unknown-linux-gnu" , riscv32gc_unknown_linux_gnu), |
| 1972 | ("riscv32gc-unknown-linux-musl" , riscv32gc_unknown_linux_musl), |
| 1973 | ("riscv64imac-unknown-none-elf" , riscv64imac_unknown_none_elf), |
| 1974 | ("riscv64gc-unknown-none-elf" , riscv64gc_unknown_none_elf), |
| 1975 | ("riscv64gc-unknown-linux-gnu" , riscv64gc_unknown_linux_gnu), |
| 1976 | ("riscv64gc-unknown-linux-musl" , riscv64gc_unknown_linux_musl), |
| 1977 | |
| 1978 | ("sparc-unknown-none-elf" , sparc_unknown_none_elf), |
| 1979 | |
| 1980 | ("loongarch64-unknown-none" , loongarch64_unknown_none), |
| 1981 | ("loongarch64-unknown-none-softfloat" , loongarch64_unknown_none_softfloat), |
| 1982 | |
| 1983 | ("aarch64-unknown-none" , aarch64_unknown_none), |
| 1984 | ("aarch64-unknown-none-softfloat" , aarch64_unknown_none_softfloat), |
| 1985 | ("aarch64-unknown-nuttx" , aarch64_unknown_nuttx), |
| 1986 | |
| 1987 | ("x86_64-fortanix-unknown-sgx" , x86_64_fortanix_unknown_sgx), |
| 1988 | |
| 1989 | ("x86_64-unknown-uefi" , x86_64_unknown_uefi), |
| 1990 | ("i686-unknown-uefi" , i686_unknown_uefi), |
| 1991 | ("aarch64-unknown-uefi" , aarch64_unknown_uefi), |
| 1992 | |
| 1993 | ("nvptx64-nvidia-cuda" , nvptx64_nvidia_cuda), |
| 1994 | |
| 1995 | ("amdgcn-amd-amdhsa" , amdgcn_amd_amdhsa), |
| 1996 | |
| 1997 | ("xtensa-esp32-none-elf" , xtensa_esp32_none_elf), |
| 1998 | ("xtensa-esp32-espidf" , xtensa_esp32_espidf), |
| 1999 | ("xtensa-esp32s2-none-elf" , xtensa_esp32s2_none_elf), |
| 2000 | ("xtensa-esp32s2-espidf" , xtensa_esp32s2_espidf), |
| 2001 | ("xtensa-esp32s3-none-elf" , xtensa_esp32s3_none_elf), |
| 2002 | ("xtensa-esp32s3-espidf" , xtensa_esp32s3_espidf), |
| 2003 | |
| 2004 | ("i686-wrs-vxworks" , i686_wrs_vxworks), |
| 2005 | ("x86_64-wrs-vxworks" , x86_64_wrs_vxworks), |
| 2006 | ("armv7-wrs-vxworks-eabihf" , armv7_wrs_vxworks_eabihf), |
| 2007 | ("aarch64-wrs-vxworks" , aarch64_wrs_vxworks), |
| 2008 | ("powerpc-wrs-vxworks" , powerpc_wrs_vxworks), |
| 2009 | ("powerpc-wrs-vxworks-spe" , powerpc_wrs_vxworks_spe), |
| 2010 | ("powerpc64-wrs-vxworks" , powerpc64_wrs_vxworks), |
| 2011 | ("riscv32-wrs-vxworks" , riscv32_wrs_vxworks), |
| 2012 | ("riscv64-wrs-vxworks" , riscv64_wrs_vxworks), |
| 2013 | |
| 2014 | ("aarch64-kmc-solid_asp3" , aarch64_kmc_solid_asp3), |
| 2015 | ("armv7a-kmc-solid_asp3-eabi" , armv7a_kmc_solid_asp3_eabi), |
| 2016 | ("armv7a-kmc-solid_asp3-eabihf" , armv7a_kmc_solid_asp3_eabihf), |
| 2017 | |
| 2018 | ("mipsel-sony-psp" , mipsel_sony_psp), |
| 2019 | ("mipsel-sony-psx" , mipsel_sony_psx), |
| 2020 | ("mipsel-unknown-none" , mipsel_unknown_none), |
| 2021 | ("mips-mti-none-elf" , mips_mti_none_elf), |
| 2022 | ("mipsel-mti-none-elf" , mipsel_mti_none_elf), |
| 2023 | ("thumbv4t-none-eabi" , thumbv4t_none_eabi), |
| 2024 | ("armv4t-none-eabi" , armv4t_none_eabi), |
| 2025 | ("thumbv5te-none-eabi" , thumbv5te_none_eabi), |
| 2026 | ("armv5te-none-eabi" , armv5te_none_eabi), |
| 2027 | |
| 2028 | ("aarch64_be-unknown-linux-gnu" , aarch64_be_unknown_linux_gnu), |
| 2029 | ("aarch64-unknown-linux-gnu_ilp32" , aarch64_unknown_linux_gnu_ilp32), |
| 2030 | ("aarch64_be-unknown-linux-gnu_ilp32" , aarch64_be_unknown_linux_gnu_ilp32), |
| 2031 | |
| 2032 | ("bpfeb-unknown-none" , bpfeb_unknown_none), |
| 2033 | ("bpfel-unknown-none" , bpfel_unknown_none), |
| 2034 | |
| 2035 | ("armv6k-nintendo-3ds" , armv6k_nintendo_3ds), |
| 2036 | |
| 2037 | ("aarch64-nintendo-switch-freestanding" , aarch64_nintendo_switch_freestanding), |
| 2038 | |
| 2039 | ("armv7-sony-vita-newlibeabihf" , armv7_sony_vita_newlibeabihf), |
| 2040 | |
| 2041 | ("armv7-unknown-linux-uclibceabi" , armv7_unknown_linux_uclibceabi), |
| 2042 | ("armv7-unknown-linux-uclibceabihf" , armv7_unknown_linux_uclibceabihf), |
| 2043 | |
| 2044 | ("x86_64-unknown-none" , x86_64_unknown_none), |
| 2045 | |
| 2046 | ("aarch64-unknown-teeos" , aarch64_unknown_teeos), |
| 2047 | |
| 2048 | ("mips64-openwrt-linux-musl" , mips64_openwrt_linux_musl), |
| 2049 | |
| 2050 | ("aarch64-unknown-nto-qnx700" , aarch64_unknown_nto_qnx700), |
| 2051 | ("aarch64-unknown-nto-qnx710" , aarch64_unknown_nto_qnx710), |
| 2052 | ("aarch64-unknown-nto-qnx710_iosock" , aarch64_unknown_nto_qnx710_iosock), |
| 2053 | ("aarch64-unknown-nto-qnx800" , aarch64_unknown_nto_qnx800), |
| 2054 | ("x86_64-pc-nto-qnx710" , x86_64_pc_nto_qnx710), |
| 2055 | ("x86_64-pc-nto-qnx710_iosock" , x86_64_pc_nto_qnx710_iosock), |
| 2056 | ("x86_64-pc-nto-qnx800" , x86_64_pc_nto_qnx800), |
| 2057 | ("i686-pc-nto-qnx700" , i686_pc_nto_qnx700), |
| 2058 | |
| 2059 | ("aarch64-unknown-linux-ohos" , aarch64_unknown_linux_ohos), |
| 2060 | ("armv7-unknown-linux-ohos" , armv7_unknown_linux_ohos), |
| 2061 | ("loongarch64-unknown-linux-ohos" , loongarch64_unknown_linux_ohos), |
| 2062 | ("x86_64-unknown-linux-ohos" , x86_64_unknown_linux_ohos), |
| 2063 | |
| 2064 | ("x86_64-unknown-linux-none" , x86_64_unknown_linux_none), |
| 2065 | |
| 2066 | ("thumbv6m-nuttx-eabi" , thumbv6m_nuttx_eabi), |
| 2067 | ("thumbv7a-nuttx-eabi" , thumbv7a_nuttx_eabi), |
| 2068 | ("thumbv7a-nuttx-eabihf" , thumbv7a_nuttx_eabihf), |
| 2069 | ("thumbv7m-nuttx-eabi" , thumbv7m_nuttx_eabi), |
| 2070 | ("thumbv7em-nuttx-eabi" , thumbv7em_nuttx_eabi), |
| 2071 | ("thumbv7em-nuttx-eabihf" , thumbv7em_nuttx_eabihf), |
| 2072 | ("thumbv8m.base-nuttx-eabi" , thumbv8m_base_nuttx_eabi), |
| 2073 | ("thumbv8m.main-nuttx-eabi" , thumbv8m_main_nuttx_eabi), |
| 2074 | ("thumbv8m.main-nuttx-eabihf" , thumbv8m_main_nuttx_eabihf), |
| 2075 | ("riscv32imc-unknown-nuttx-elf" , riscv32imc_unknown_nuttx_elf), |
| 2076 | ("riscv32imac-unknown-nuttx-elf" , riscv32imac_unknown_nuttx_elf), |
| 2077 | ("riscv32imafc-unknown-nuttx-elf" , riscv32imafc_unknown_nuttx_elf), |
| 2078 | ("riscv64imac-unknown-nuttx-elf" , riscv64imac_unknown_nuttx_elf), |
| 2079 | ("riscv64gc-unknown-nuttx-elf" , riscv64gc_unknown_nuttx_elf), |
| 2080 | |
| 2081 | ("x86_64-pc-cygwin" , x86_64_pc_cygwin), |
| 2082 | } |
| 2083 | |
| 2084 | /// Cow-Vec-Str: Cow<'static, [Cow<'static, str>]> |
| 2085 | macro_rules! cvs { |
| 2086 | () => { |
| 2087 | ::std::borrow::Cow::Borrowed(&[]) |
| 2088 | }; |
| 2089 | ($($x:expr),+ $(,)?) => { |
| 2090 | ::std::borrow::Cow::Borrowed(&[ |
| 2091 | $( |
| 2092 | ::std::borrow::Cow::Borrowed($x), |
| 2093 | )* |
| 2094 | ]) |
| 2095 | }; |
| 2096 | } |
| 2097 | |
| 2098 | pub(crate) use cvs; |
| 2099 | |
| 2100 | /// Warnings encountered when parsing the target `json`. |
| 2101 | /// |
| 2102 | /// Includes fields that weren't recognized and fields that don't have the expected type. |
| 2103 | #[derive (Debug, PartialEq)] |
| 2104 | pub struct TargetWarnings { |
| 2105 | unused_fields: Vec<String>, |
| 2106 | incorrect_type: Vec<String>, |
| 2107 | } |
| 2108 | |
| 2109 | impl TargetWarnings { |
| 2110 | pub fn empty() -> Self { |
| 2111 | Self { unused_fields: Vec::new(), incorrect_type: Vec::new() } |
| 2112 | } |
| 2113 | |
| 2114 | pub fn warning_messages(&self) -> Vec<String> { |
| 2115 | let mut warnings: Vec = vec![]; |
| 2116 | if !self.unused_fields.is_empty() { |
| 2117 | warnings.push(format!( |
| 2118 | "target json file contains unused fields: {}" , |
| 2119 | self.unused_fields.join(", " ) |
| 2120 | )); |
| 2121 | } |
| 2122 | if !self.incorrect_type.is_empty() { |
| 2123 | warnings.push(format!( |
| 2124 | "target json file contains fields whose value doesn't have the correct json type: {}" , |
| 2125 | self.incorrect_type.join(", " ) |
| 2126 | )); |
| 2127 | } |
| 2128 | warnings |
| 2129 | } |
| 2130 | } |
| 2131 | |
| 2132 | /// For the [`Target::check_consistency`] function, determines whether the given target is a builtin or a JSON |
| 2133 | /// target. |
| 2134 | #[derive (Copy, Clone, Debug, PartialEq)] |
| 2135 | enum TargetKind { |
| 2136 | Json, |
| 2137 | Builtin, |
| 2138 | } |
| 2139 | |
| 2140 | /// Everything `rustc` knows about how to compile for a specific target. |
| 2141 | /// |
| 2142 | /// Every field here must be specified, and has no default value. |
| 2143 | #[derive (PartialEq, Clone, Debug)] |
| 2144 | pub struct Target { |
| 2145 | /// Unversioned target tuple to pass to LLVM. |
| 2146 | /// |
| 2147 | /// Target tuples can optionally contain an OS version (notably Apple targets), which rustc |
| 2148 | /// cannot know without querying the environment. |
| 2149 | /// |
| 2150 | /// Use `rustc_codegen_ssa::back::versioned_llvm_target` if you need the full LLVM target. |
| 2151 | pub llvm_target: StaticCow<str>, |
| 2152 | /// Metadata about a target, for example the description or tier. |
| 2153 | /// Used for generating target documentation. |
| 2154 | pub metadata: TargetMetadata, |
| 2155 | /// Number of bits in a pointer. Influences the `target_pointer_width` `cfg` variable. |
| 2156 | pub pointer_width: u32, |
| 2157 | /// Architecture to use for ABI considerations. Valid options include: "x86", |
| 2158 | /// "x86_64", "arm", "aarch64", "mips", "powerpc", "powerpc64", and others. |
| 2159 | pub arch: StaticCow<str>, |
| 2160 | /// [Data layout](https://llvm.org/docs/LangRef.html#data-layout) to pass to LLVM. |
| 2161 | pub data_layout: StaticCow<str>, |
| 2162 | /// Optional settings with defaults. |
| 2163 | pub options: TargetOptions, |
| 2164 | } |
| 2165 | |
| 2166 | /// Metadata about a target like the description or tier. |
| 2167 | /// Part of #120745. |
| 2168 | /// All fields are optional for now, but intended to be required in the future. |
| 2169 | #[derive (Default, PartialEq, Clone, Debug)] |
| 2170 | pub struct TargetMetadata { |
| 2171 | /// A short description of the target including platform requirements, |
| 2172 | /// for example "64-bit Linux (kernel 3.2+, glibc 2.17+)". |
| 2173 | pub description: Option<StaticCow<str>>, |
| 2174 | /// The tier of the target. 1, 2 or 3. |
| 2175 | pub tier: Option<u64>, |
| 2176 | /// Whether the Rust project ships host tools for a target. |
| 2177 | pub host_tools: Option<bool>, |
| 2178 | /// Whether a target has the `std` library. This is usually true for targets running |
| 2179 | /// on an operating system. |
| 2180 | pub std: Option<bool>, |
| 2181 | } |
| 2182 | |
| 2183 | impl Target { |
| 2184 | pub fn parse_data_layout(&self) -> Result<TargetDataLayout, TargetDataLayoutErrors<'_>> { |
| 2185 | let mut dl = TargetDataLayout::parse_from_llvm_datalayout_string(&self.data_layout)?; |
| 2186 | |
| 2187 | // Perform consistency checks against the Target information. |
| 2188 | if dl.endian != self.endian { |
| 2189 | return Err(TargetDataLayoutErrors::InconsistentTargetArchitecture { |
| 2190 | dl: dl.endian.as_str(), |
| 2191 | target: self.endian.as_str(), |
| 2192 | }); |
| 2193 | } |
| 2194 | |
| 2195 | let target_pointer_width: u64 = self.pointer_width.into(); |
| 2196 | if dl.pointer_size.bits() != target_pointer_width { |
| 2197 | return Err(TargetDataLayoutErrors::InconsistentTargetPointerWidth { |
| 2198 | pointer_size: dl.pointer_size.bits(), |
| 2199 | target: self.pointer_width, |
| 2200 | }); |
| 2201 | } |
| 2202 | |
| 2203 | dl.c_enum_min_size = self |
| 2204 | .c_enum_min_bits |
| 2205 | .map_or_else( |
| 2206 | || { |
| 2207 | self.c_int_width |
| 2208 | .parse() |
| 2209 | .map_err(|_| String::from("failed to parse c_int_width" )) |
| 2210 | }, |
| 2211 | Ok, |
| 2212 | ) |
| 2213 | .and_then(|i| Integer::from_size(Size::from_bits(i))) |
| 2214 | .map_err(|err| TargetDataLayoutErrors::InvalidBitsSize { err })?; |
| 2215 | |
| 2216 | Ok(dl) |
| 2217 | } |
| 2218 | } |
| 2219 | |
| 2220 | pub trait HasTargetSpec { |
| 2221 | fn target_spec(&self) -> &Target; |
| 2222 | } |
| 2223 | |
| 2224 | impl HasTargetSpec for Target { |
| 2225 | #[inline ] |
| 2226 | fn target_spec(&self) -> &Target { |
| 2227 | self |
| 2228 | } |
| 2229 | } |
| 2230 | |
| 2231 | /// Which C ABI to use for `wasm32-unknown-unknown`. |
| 2232 | #[derive (Debug, Copy, Clone, Hash, PartialEq, Eq)] |
| 2233 | pub enum WasmCAbi { |
| 2234 | /// Spec-compliant C ABI. |
| 2235 | Spec, |
| 2236 | /// Legacy ABI. Which is non-spec-compliant. |
| 2237 | Legacy { |
| 2238 | /// Indicates whether the `wasm_c_abi` lint should be emitted. |
| 2239 | with_lint: bool, |
| 2240 | }, |
| 2241 | } |
| 2242 | |
| 2243 | pub trait HasWasmCAbiOpt { |
| 2244 | fn wasm_c_abi_opt(&self) -> WasmCAbi; |
| 2245 | } |
| 2246 | |
| 2247 | /// x86 (32-bit) abi options. |
| 2248 | #[derive (Debug, Copy, Clone, Hash, PartialEq, Eq)] |
| 2249 | pub struct X86Abi { |
| 2250 | /// On x86-32 targets, the regparm N causes the compiler to pass arguments |
| 2251 | /// in registers EAX, EDX, and ECX instead of on the stack. |
| 2252 | pub regparm: Option<u32>, |
| 2253 | /// Override the default ABI to return small structs in registers |
| 2254 | pub reg_struct_return: bool, |
| 2255 | } |
| 2256 | |
| 2257 | pub trait HasX86AbiOpt { |
| 2258 | fn x86_abi_opt(&self) -> X86Abi; |
| 2259 | } |
| 2260 | |
| 2261 | type StaticCow<T> = Cow<'static, T>; |
| 2262 | |
| 2263 | /// Optional aspects of a target specification. |
| 2264 | /// |
| 2265 | /// This has an implementation of `Default`, see each field for what the default is. In general, |
| 2266 | /// these try to take "minimal defaults" that don't assume anything about the runtime they run in. |
| 2267 | /// |
| 2268 | /// `TargetOptions` as a separate structure is mostly an implementation detail of `Target` |
| 2269 | /// construction, all its fields logically belong to `Target` and available from `Target` |
| 2270 | /// through `Deref` impls. |
| 2271 | #[derive (PartialEq, Clone, Debug)] |
| 2272 | pub struct TargetOptions { |
| 2273 | /// Used as the `target_endian` `cfg` variable. Defaults to little endian. |
| 2274 | pub endian: Endian, |
| 2275 | /// Width of c_int type. Defaults to "32". |
| 2276 | pub c_int_width: StaticCow<str>, |
| 2277 | /// OS name to use for conditional compilation (`target_os`). Defaults to "none". |
| 2278 | /// "none" implies a bare metal target without `std` library. |
| 2279 | /// A couple of targets having `std` also use "unknown" as an `os` value, |
| 2280 | /// but they are exceptions. |
| 2281 | pub os: StaticCow<str>, |
| 2282 | /// Environment name to use for conditional compilation (`target_env`). Defaults to "". |
| 2283 | pub env: StaticCow<str>, |
| 2284 | /// ABI name to distinguish multiple ABIs on the same OS and architecture. For instance, `"eabi"` |
| 2285 | /// or `"eabihf"`. Defaults to "". |
| 2286 | /// This field is *not* forwarded directly to LLVM; its primary purpose is `cfg(target_abi)`. |
| 2287 | /// However, parts of the backend do check this field for specific values to enable special behavior. |
| 2288 | pub abi: StaticCow<str>, |
| 2289 | /// Vendor name to use for conditional compilation (`target_vendor`). Defaults to "unknown". |
| 2290 | pub vendor: StaticCow<str>, |
| 2291 | |
| 2292 | /// Linker to invoke |
| 2293 | pub linker: Option<StaticCow<str>>, |
| 2294 | /// Default linker flavor used if `-C linker-flavor` or `-C linker` are not passed |
| 2295 | /// on the command line. Defaults to `LinkerFlavor::Gnu(Cc::Yes, Lld::No)`. |
| 2296 | pub linker_flavor: LinkerFlavor, |
| 2297 | linker_flavor_json: LinkerFlavorCli, |
| 2298 | lld_flavor_json: LldFlavor, |
| 2299 | linker_is_gnu_json: bool, |
| 2300 | |
| 2301 | /// Objects to link before and after all other object code. |
| 2302 | pub pre_link_objects: CrtObjects, |
| 2303 | pub post_link_objects: CrtObjects, |
| 2304 | /// Same as `(pre|post)_link_objects`, but when self-contained linking mode is enabled. |
| 2305 | pub pre_link_objects_self_contained: CrtObjects, |
| 2306 | pub post_link_objects_self_contained: CrtObjects, |
| 2307 | /// Behavior for the self-contained linking mode: inferred for some targets, or explicitly |
| 2308 | /// enabled (in bulk, or with individual components). |
| 2309 | pub link_self_contained: LinkSelfContainedDefault, |
| 2310 | |
| 2311 | /// Linker arguments that are passed *before* any user-defined libraries. |
| 2312 | pub pre_link_args: LinkArgs, |
| 2313 | pre_link_args_json: LinkArgsCli, |
| 2314 | /// Linker arguments that are unconditionally passed after any |
| 2315 | /// user-defined but before post-link objects. Standard platform |
| 2316 | /// libraries that should be always be linked to, usually go here. |
| 2317 | pub late_link_args: LinkArgs, |
| 2318 | late_link_args_json: LinkArgsCli, |
| 2319 | /// Linker arguments used in addition to `late_link_args` if at least one |
| 2320 | /// Rust dependency is dynamically linked. |
| 2321 | pub late_link_args_dynamic: LinkArgs, |
| 2322 | late_link_args_dynamic_json: LinkArgsCli, |
| 2323 | /// Linker arguments used in addition to `late_link_args` if all Rust |
| 2324 | /// dependencies are statically linked. |
| 2325 | pub late_link_args_static: LinkArgs, |
| 2326 | late_link_args_static_json: LinkArgsCli, |
| 2327 | /// Linker arguments that are unconditionally passed *after* any |
| 2328 | /// user-defined libraries. |
| 2329 | pub post_link_args: LinkArgs, |
| 2330 | post_link_args_json: LinkArgsCli, |
| 2331 | |
| 2332 | /// Optional link script applied to `dylib` and `executable` crate types. |
| 2333 | /// This is a string containing the script, not a path. Can only be applied |
| 2334 | /// to linkers where linker flavor matches `LinkerFlavor::Gnu(..)`. |
| 2335 | pub link_script: Option<StaticCow<str>>, |
| 2336 | /// Environment variables to be set for the linker invocation. |
| 2337 | pub link_env: StaticCow<[(StaticCow<str>, StaticCow<str>)]>, |
| 2338 | /// Environment variables to be removed for the linker invocation. |
| 2339 | pub link_env_remove: StaticCow<[StaticCow<str>]>, |
| 2340 | |
| 2341 | /// Extra arguments to pass to the external assembler (when used) |
| 2342 | pub asm_args: StaticCow<[StaticCow<str>]>, |
| 2343 | |
| 2344 | /// Default CPU to pass to LLVM. Corresponds to `llc -mcpu=$cpu`. Defaults |
| 2345 | /// to "generic". |
| 2346 | pub cpu: StaticCow<str>, |
| 2347 | /// Whether a cpu needs to be explicitly set. |
| 2348 | /// Set to true if there is no default cpu. Defaults to false. |
| 2349 | pub need_explicit_cpu: bool, |
| 2350 | /// Default target features to pass to LLVM. These features overwrite |
| 2351 | /// `-Ctarget-cpu` but can be overwritten with `-Ctarget-features`. |
| 2352 | /// Corresponds to `llc -mattr=$features`. |
| 2353 | /// Note that these are LLVM feature names, not Rust feature names! |
| 2354 | /// |
| 2355 | /// Generally it is a bad idea to use negative target features because they often interact very |
| 2356 | /// poorly with how `-Ctarget-cpu` works. Instead, try to use a lower "base CPU" and enable the |
| 2357 | /// features you want to use. |
| 2358 | pub features: StaticCow<str>, |
| 2359 | /// Direct or use GOT indirect to reference external data symbols |
| 2360 | pub direct_access_external_data: Option<bool>, |
| 2361 | /// Whether dynamic linking is available on this target. Defaults to false. |
| 2362 | pub dynamic_linking: bool, |
| 2363 | /// Whether dynamic linking can export TLS globals. Defaults to true. |
| 2364 | pub dll_tls_export: bool, |
| 2365 | /// If dynamic linking is available, whether only cdylibs are supported. |
| 2366 | pub only_cdylib: bool, |
| 2367 | /// Whether executables are available on this target. Defaults to true. |
| 2368 | pub executables: bool, |
| 2369 | /// Relocation model to use in object file. Corresponds to `llc |
| 2370 | /// -relocation-model=$relocation_model`. Defaults to `Pic`. |
| 2371 | pub relocation_model: RelocModel, |
| 2372 | /// Code model to use. Corresponds to `llc -code-model=$code_model`. |
| 2373 | /// Defaults to `None` which means "inherited from the base LLVM target". |
| 2374 | pub code_model: Option<CodeModel>, |
| 2375 | /// TLS model to use. Options are "global-dynamic" (default), "local-dynamic", "initial-exec" |
| 2376 | /// and "local-exec". This is similar to the -ftls-model option in GCC/Clang. |
| 2377 | pub tls_model: TlsModel, |
| 2378 | /// Do not emit code that uses the "red zone", if the ABI has one. Defaults to false. |
| 2379 | pub disable_redzone: bool, |
| 2380 | /// Frame pointer mode for this target. Defaults to `MayOmit`. |
| 2381 | pub frame_pointer: FramePointer, |
| 2382 | /// Emit each function in its own section. Defaults to true. |
| 2383 | pub function_sections: bool, |
| 2384 | /// String to prepend to the name of every dynamic library. Defaults to "lib". |
| 2385 | pub dll_prefix: StaticCow<str>, |
| 2386 | /// String to append to the name of every dynamic library. Defaults to ".so". |
| 2387 | pub dll_suffix: StaticCow<str>, |
| 2388 | /// String to append to the name of every executable. |
| 2389 | pub exe_suffix: StaticCow<str>, |
| 2390 | /// String to prepend to the name of every static library. Defaults to "lib". |
| 2391 | pub staticlib_prefix: StaticCow<str>, |
| 2392 | /// String to append to the name of every static library. Defaults to ".a". |
| 2393 | pub staticlib_suffix: StaticCow<str>, |
| 2394 | /// Values of the `target_family` cfg set for this target. |
| 2395 | /// |
| 2396 | /// Common options are: "unix", "windows". Defaults to no families. |
| 2397 | /// |
| 2398 | /// See <https://doc.rust-lang.org/reference/conditional-compilation.html#target_family>. |
| 2399 | pub families: StaticCow<[StaticCow<str>]>, |
| 2400 | /// Whether the target toolchain's ABI supports returning small structs as an integer. |
| 2401 | pub abi_return_struct_as_int: bool, |
| 2402 | /// Whether the target toolchain is like AIX's. Linker options on AIX are special and it uses |
| 2403 | /// XCOFF as binary format. Defaults to false. |
| 2404 | pub is_like_aix: bool, |
| 2405 | /// Whether the target toolchain is like macOS's. Only useful for compiling against iOS/macOS, |
| 2406 | /// in particular running dsymutil and some other stuff like `-dead_strip`. Defaults to false. |
| 2407 | /// Also indicates whether to use Apple-specific ABI changes, such as extending function |
| 2408 | /// parameters to 32-bits. |
| 2409 | pub is_like_osx: bool, |
| 2410 | /// Whether the target toolchain is like Solaris's. |
| 2411 | /// Only useful for compiling against Illumos/Solaris, |
| 2412 | /// as they have a different set of linker flags. Defaults to false. |
| 2413 | pub is_like_solaris: bool, |
| 2414 | /// Whether the target is like Windows. |
| 2415 | /// This is a combination of several more specific properties represented as a single flag: |
| 2416 | /// - The target uses a Windows ABI, |
| 2417 | /// - uses PE/COFF as a format for object code, |
| 2418 | /// - uses Windows-style dllexport/dllimport for shared libraries, |
| 2419 | /// - uses import libraries and .def files for symbol exports, |
| 2420 | /// - executables support setting a subsystem. |
| 2421 | pub is_like_windows: bool, |
| 2422 | /// Whether the target is like MSVC. |
| 2423 | /// This is a combination of several more specific properties represented as a single flag: |
| 2424 | /// - The target has all the properties from `is_like_windows` |
| 2425 | /// (for in-tree targets "is_like_msvc ⇒ is_like_windows" is ensured by a unit test), |
| 2426 | /// - has some MSVC-specific Windows ABI properties, |
| 2427 | /// - uses a link.exe-like linker, |
| 2428 | /// - uses CodeView/PDB for debuginfo and natvis for its visualization, |
| 2429 | /// - uses SEH-based unwinding, |
| 2430 | /// - supports control flow guard mechanism. |
| 2431 | pub is_like_msvc: bool, |
| 2432 | /// Whether a target toolchain is like WASM. |
| 2433 | pub is_like_wasm: bool, |
| 2434 | /// Whether a target toolchain is like Android, implying a Linux kernel and a Bionic libc |
| 2435 | pub is_like_android: bool, |
| 2436 | /// Target's binary file format. Defaults to BinaryFormat::Elf |
| 2437 | pub binary_format: BinaryFormat, |
| 2438 | /// Default supported version of DWARF on this platform. |
| 2439 | /// Useful because some platforms (osx, bsd) only want up to DWARF2. |
| 2440 | pub default_dwarf_version: u32, |
| 2441 | /// The MinGW toolchain has a known issue that prevents it from correctly |
| 2442 | /// handling COFF object files with more than 2<sup>15</sup> sections. Since each weak |
| 2443 | /// symbol needs its own COMDAT section, weak linkage implies a large |
| 2444 | /// number sections that easily exceeds the given limit for larger |
| 2445 | /// codebases. Consequently we want a way to disallow weak linkage on some |
| 2446 | /// platforms. |
| 2447 | pub allows_weak_linkage: bool, |
| 2448 | /// Whether the linker support rpaths or not. Defaults to false. |
| 2449 | pub has_rpath: bool, |
| 2450 | /// Whether to disable linking to the default libraries, typically corresponds |
| 2451 | /// to `-nodefaultlibs`. Defaults to true. |
| 2452 | pub no_default_libraries: bool, |
| 2453 | /// Dynamically linked executables can be compiled as position independent |
| 2454 | /// if the default relocation model of position independent code is not |
| 2455 | /// changed. This is a requirement to take advantage of ASLR, as otherwise |
| 2456 | /// the functions in the executable are not randomized and can be used |
| 2457 | /// during an exploit of a vulnerability in any code. |
| 2458 | pub position_independent_executables: bool, |
| 2459 | /// Executables that are both statically linked and position-independent are supported. |
| 2460 | pub static_position_independent_executables: bool, |
| 2461 | /// Determines if the target always requires using the PLT for indirect |
| 2462 | /// library calls or not. This controls the default value of the `-Z plt` flag. |
| 2463 | pub plt_by_default: bool, |
| 2464 | /// Either partial, full, or off. Full RELRO makes the dynamic linker |
| 2465 | /// resolve all symbols at startup and marks the GOT read-only before |
| 2466 | /// starting the program, preventing overwriting the GOT. |
| 2467 | pub relro_level: RelroLevel, |
| 2468 | /// Format that archives should be emitted in. This affects whether we use |
| 2469 | /// LLVM to assemble an archive or fall back to the system linker, and |
| 2470 | /// currently only "gnu" is used to fall into LLVM. Unknown strings cause |
| 2471 | /// the system linker to be used. |
| 2472 | pub archive_format: StaticCow<str>, |
| 2473 | /// Is asm!() allowed? Defaults to true. |
| 2474 | pub allow_asm: bool, |
| 2475 | /// Whether the runtime startup code requires the `main` function be passed |
| 2476 | /// `argc` and `argv` values. |
| 2477 | pub main_needs_argc_argv: bool, |
| 2478 | |
| 2479 | /// Flag indicating whether #[thread_local] is available for this target. |
| 2480 | pub has_thread_local: bool, |
| 2481 | /// This is mainly for easy compatibility with emscripten. |
| 2482 | /// If we give emcc .o files that are actually .bc files it |
| 2483 | /// will 'just work'. |
| 2484 | pub obj_is_bitcode: bool, |
| 2485 | /// Content of the LLVM cmdline section associated with embedded bitcode. |
| 2486 | pub bitcode_llvm_cmdline: StaticCow<str>, |
| 2487 | |
| 2488 | /// Don't use this field; instead use the `.min_atomic_width()` method. |
| 2489 | pub min_atomic_width: Option<u64>, |
| 2490 | |
| 2491 | /// Don't use this field; instead use the `.max_atomic_width()` method. |
| 2492 | pub max_atomic_width: Option<u64>, |
| 2493 | |
| 2494 | /// Whether the target supports atomic CAS operations natively |
| 2495 | pub atomic_cas: bool, |
| 2496 | |
| 2497 | /// Panic strategy: "unwind" or "abort" |
| 2498 | pub panic_strategy: PanicStrategy, |
| 2499 | |
| 2500 | /// Whether or not linking dylibs to a static CRT is allowed. |
| 2501 | pub crt_static_allows_dylibs: bool, |
| 2502 | /// Whether or not the CRT is statically linked by default. |
| 2503 | pub crt_static_default: bool, |
| 2504 | /// Whether or not crt-static is respected by the compiler (or is a no-op). |
| 2505 | pub crt_static_respected: bool, |
| 2506 | |
| 2507 | /// The implementation of stack probes to use. |
| 2508 | pub stack_probes: StackProbeType, |
| 2509 | |
| 2510 | /// The minimum alignment for global symbols. |
| 2511 | pub min_global_align: Option<u64>, |
| 2512 | |
| 2513 | /// Default number of codegen units to use in debug mode |
| 2514 | pub default_codegen_units: Option<u64>, |
| 2515 | |
| 2516 | /// Default codegen backend used for this target. Defaults to `None`. |
| 2517 | /// |
| 2518 | /// If `None`, then `CFG_DEFAULT_CODEGEN_BACKEND` environmental variable captured when |
| 2519 | /// compiling `rustc` will be used instead (or llvm if it is not set). |
| 2520 | /// |
| 2521 | /// N.B. when *using* the compiler, backend can always be overridden with `-Zcodegen-backend`. |
| 2522 | /// |
| 2523 | /// This was added by WaffleLapkin in #116793. The motivation is a rustc fork that requires a |
| 2524 | /// custom codegen backend for a particular target. |
| 2525 | pub default_codegen_backend: Option<StaticCow<str>>, |
| 2526 | |
| 2527 | /// Whether to generate trap instructions in places where optimization would |
| 2528 | /// otherwise produce control flow that falls through into unrelated memory. |
| 2529 | pub trap_unreachable: bool, |
| 2530 | |
| 2531 | /// This target requires everything to be compiled with LTO to emit a final |
| 2532 | /// executable, aka there is no native linker for this target. |
| 2533 | pub requires_lto: bool, |
| 2534 | |
| 2535 | /// This target has no support for threads. |
| 2536 | pub singlethread: bool, |
| 2537 | |
| 2538 | /// Whether library functions call lowering/optimization is disabled in LLVM |
| 2539 | /// for this target unconditionally. |
| 2540 | pub no_builtins: bool, |
| 2541 | |
| 2542 | /// The default visibility for symbols in this target. |
| 2543 | /// |
| 2544 | /// This value typically shouldn't be accessed directly, but through the |
| 2545 | /// `rustc_session::Session::default_visibility` method, which allows `rustc` users to override |
| 2546 | /// this setting using cmdline flags. |
| 2547 | pub default_visibility: Option<SymbolVisibility>, |
| 2548 | |
| 2549 | /// Whether a .debug_gdb_scripts section will be added to the output object file |
| 2550 | pub emit_debug_gdb_scripts: bool, |
| 2551 | |
| 2552 | /// Whether or not to unconditionally `uwtable` attributes on functions, |
| 2553 | /// typically because the platform needs to unwind for things like stack |
| 2554 | /// unwinders. |
| 2555 | pub requires_uwtable: bool, |
| 2556 | |
| 2557 | /// Whether or not to emit `uwtable` attributes on functions if `-C force-unwind-tables` |
| 2558 | /// is not specified and `uwtable` is not required on this target. |
| 2559 | pub default_uwtable: bool, |
| 2560 | |
| 2561 | /// Whether or not SIMD types are passed by reference in the Rust ABI, |
| 2562 | /// typically required if a target can be compiled with a mixed set of |
| 2563 | /// target features. This is `true` by default, and `false` for targets like |
| 2564 | /// wasm32 where the whole program either has simd or not. |
| 2565 | pub simd_types_indirect: bool, |
| 2566 | |
| 2567 | /// Pass a list of symbol which should be exported in the dylib to the linker. |
| 2568 | pub limit_rdylib_exports: bool, |
| 2569 | |
| 2570 | /// If set, have the linker export exactly these symbols, instead of using |
| 2571 | /// the usual logic to figure this out from the crate itself. |
| 2572 | pub override_export_symbols: Option<StaticCow<[StaticCow<str>]>>, |
| 2573 | |
| 2574 | /// Determines how or whether the MergeFunctions LLVM pass should run for |
| 2575 | /// this target. Either "disabled", "trampolines", or "aliases". |
| 2576 | /// The MergeFunctions pass is generally useful, but some targets may need |
| 2577 | /// to opt out. The default is "aliases". |
| 2578 | /// |
| 2579 | /// Workaround for: <https://github.com/rust-lang/rust/issues/57356> |
| 2580 | pub merge_functions: MergeFunctions, |
| 2581 | |
| 2582 | /// Use platform dependent mcount function |
| 2583 | pub mcount: StaticCow<str>, |
| 2584 | |
| 2585 | /// Use LLVM intrinsic for mcount function name |
| 2586 | pub llvm_mcount_intrinsic: Option<StaticCow<str>>, |
| 2587 | |
| 2588 | /// LLVM ABI name, corresponds to the '-mabi' parameter available in multilib C compilers |
| 2589 | /// and the `-target-abi` flag in llc. In the LLVM API this is `MCOptions.ABIName`. |
| 2590 | pub llvm_abiname: StaticCow<str>, |
| 2591 | |
| 2592 | /// Control the float ABI to use, for architectures that support it. The only architecture we |
| 2593 | /// currently use this for is ARM. Corresponds to the `-float-abi` flag in llc. In the LLVM API |
| 2594 | /// this is `FloatABIType`. (clang's `-mfloat-abi` is similar but more complicated since it |
| 2595 | /// can also affect the `soft-float` target feature.) |
| 2596 | /// |
| 2597 | /// If not provided, LLVM will infer the float ABI from the target triple (`llvm_target`). |
| 2598 | pub llvm_floatabi: Option<FloatAbi>, |
| 2599 | |
| 2600 | /// Picks a specific ABI for this target. This is *not* just for "Rust" ABI functions, |
| 2601 | /// it can also affect "C" ABI functions; the point is that this flag is interpreted by |
| 2602 | /// rustc and not forwarded to LLVM. |
| 2603 | /// So far, this is only used on x86. |
| 2604 | pub rustc_abi: Option<RustcAbi>, |
| 2605 | |
| 2606 | /// Whether or not RelaxElfRelocation flag will be passed to the linker |
| 2607 | pub relax_elf_relocations: bool, |
| 2608 | |
| 2609 | /// Additional arguments to pass to LLVM, similar to the `-C llvm-args` codegen option. |
| 2610 | pub llvm_args: StaticCow<[StaticCow<str>]>, |
| 2611 | |
| 2612 | /// Whether to use legacy .ctors initialization hooks rather than .init_array. Defaults |
| 2613 | /// to false (uses .init_array). |
| 2614 | pub use_ctors_section: bool, |
| 2615 | |
| 2616 | /// Whether the linker is instructed to add a `GNU_EH_FRAME` ELF header |
| 2617 | /// used to locate unwinding information is passed |
| 2618 | /// (only has effect if the linker is `ld`-like). |
| 2619 | pub eh_frame_header: bool, |
| 2620 | |
| 2621 | /// Is true if the target is an ARM architecture using thumb v1 which allows for |
| 2622 | /// thumb and arm interworking. |
| 2623 | pub has_thumb_interworking: bool, |
| 2624 | |
| 2625 | /// Which kind of debuginfo is used by this target? |
| 2626 | pub debuginfo_kind: DebuginfoKind, |
| 2627 | /// How to handle split debug information, if at all. Specifying `None` has |
| 2628 | /// target-specific meaning. |
| 2629 | pub split_debuginfo: SplitDebuginfo, |
| 2630 | /// Which kinds of split debuginfo are supported by the target? |
| 2631 | pub supported_split_debuginfo: StaticCow<[SplitDebuginfo]>, |
| 2632 | |
| 2633 | /// The sanitizers supported by this target |
| 2634 | /// |
| 2635 | /// Note that the support here is at a codegen level. If the machine code with sanitizer |
| 2636 | /// enabled can generated on this target, but the necessary supporting libraries are not |
| 2637 | /// distributed with the target, the sanitizer should still appear in this list for the target. |
| 2638 | pub supported_sanitizers: SanitizerSet, |
| 2639 | |
| 2640 | /// Minimum number of bits in #[repr(C)] enum. Defaults to the size of c_int |
| 2641 | pub c_enum_min_bits: Option<u64>, |
| 2642 | |
| 2643 | /// Whether or not the DWARF `.debug_aranges` section should be generated. |
| 2644 | pub generate_arange_section: bool, |
| 2645 | |
| 2646 | /// Whether the target supports stack canary checks. `true` by default, |
| 2647 | /// since this is most common among tier 1 and tier 2 targets. |
| 2648 | pub supports_stack_protector: bool, |
| 2649 | |
| 2650 | /// The name of entry function. |
| 2651 | /// Default value is "main" |
| 2652 | pub entry_name: StaticCow<str>, |
| 2653 | |
| 2654 | /// The ABI of entry function. |
| 2655 | /// Default value is `Conv::C`, i.e. C call convention |
| 2656 | pub entry_abi: Conv, |
| 2657 | |
| 2658 | /// Whether the target supports XRay instrumentation. |
| 2659 | pub supports_xray: bool, |
| 2660 | |
| 2661 | /// Whether the targets supports -Z small-data-threshold |
| 2662 | small_data_threshold_support: SmallDataThresholdSupport, |
| 2663 | } |
| 2664 | |
| 2665 | /// Add arguments for the given flavor and also for its "twin" flavors |
| 2666 | /// that have a compatible command line interface. |
| 2667 | fn add_link_args_iter( |
| 2668 | link_args: &mut LinkArgs, |
| 2669 | flavor: LinkerFlavor, |
| 2670 | args: impl Iterator<Item = StaticCow<str>> + Clone, |
| 2671 | ) { |
| 2672 | let mut insert: impl FnMut(LinkerFlavor) = |flavor: LinkerFlavor| link_args.entry(flavor).or_default().extend(iter:args.clone()); |
| 2673 | insert(flavor); |
| 2674 | match flavor { |
| 2675 | LinkerFlavor::Gnu(cc: Cc, lld: Lld) => { |
| 2676 | assert_eq!(lld, Lld::No); |
| 2677 | insert(flavor:LinkerFlavor::Gnu(cc, Lld::Yes)); |
| 2678 | } |
| 2679 | LinkerFlavor::Darwin(cc: Cc, lld: Lld) => { |
| 2680 | assert_eq!(lld, Lld::No); |
| 2681 | insert(flavor:LinkerFlavor::Darwin(cc, Lld::Yes)); |
| 2682 | } |
| 2683 | LinkerFlavor::Msvc(lld: Lld) => { |
| 2684 | assert_eq!(lld, Lld::No); |
| 2685 | insert(flavor:LinkerFlavor::Msvc(Lld::Yes)); |
| 2686 | } |
| 2687 | LinkerFlavor::WasmLld(..) |
| 2688 | | LinkerFlavor::Unix(..) |
| 2689 | | LinkerFlavor::EmCc |
| 2690 | | LinkerFlavor::Bpf |
| 2691 | | LinkerFlavor::Llbc |
| 2692 | | LinkerFlavor::Ptx => {} |
| 2693 | } |
| 2694 | } |
| 2695 | |
| 2696 | fn add_link_args(link_args: &mut LinkArgs, flavor: LinkerFlavor, args: &[&'static str]) { |
| 2697 | add_link_args_iter(link_args, flavor, args.iter().copied().map(Cow::Borrowed)) |
| 2698 | } |
| 2699 | |
| 2700 | impl TargetOptions { |
| 2701 | pub fn supports_comdat(&self) -> bool { |
| 2702 | // XCOFF and MachO don't support COMDAT. |
| 2703 | !self.is_like_aix && !self.is_like_osx |
| 2704 | } |
| 2705 | } |
| 2706 | |
| 2707 | impl TargetOptions { |
| 2708 | fn link_args(flavor: LinkerFlavor, args: &[&'static str]) -> LinkArgs { |
| 2709 | let mut link_args = LinkArgs::new(); |
| 2710 | add_link_args(&mut link_args, flavor, args); |
| 2711 | link_args |
| 2712 | } |
| 2713 | |
| 2714 | fn add_pre_link_args(&mut self, flavor: LinkerFlavor, args: &[&'static str]) { |
| 2715 | add_link_args(&mut self.pre_link_args, flavor, args); |
| 2716 | } |
| 2717 | |
| 2718 | fn update_from_cli(&mut self) { |
| 2719 | self.linker_flavor = LinkerFlavor::from_cli_json( |
| 2720 | self.linker_flavor_json, |
| 2721 | self.lld_flavor_json, |
| 2722 | self.linker_is_gnu_json, |
| 2723 | ); |
| 2724 | for (args, args_json) in [ |
| 2725 | (&mut self.pre_link_args, &self.pre_link_args_json), |
| 2726 | (&mut self.late_link_args, &self.late_link_args_json), |
| 2727 | (&mut self.late_link_args_dynamic, &self.late_link_args_dynamic_json), |
| 2728 | (&mut self.late_link_args_static, &self.late_link_args_static_json), |
| 2729 | (&mut self.post_link_args, &self.post_link_args_json), |
| 2730 | ] { |
| 2731 | args.clear(); |
| 2732 | for (flavor, args_json) in args_json { |
| 2733 | let linker_flavor = self.linker_flavor.with_cli_hints(*flavor); |
| 2734 | // Normalize to no lld to avoid asserts. |
| 2735 | let linker_flavor = match linker_flavor { |
| 2736 | LinkerFlavor::Gnu(cc, _) => LinkerFlavor::Gnu(cc, Lld::No), |
| 2737 | LinkerFlavor::Darwin(cc, _) => LinkerFlavor::Darwin(cc, Lld::No), |
| 2738 | LinkerFlavor::Msvc(_) => LinkerFlavor::Msvc(Lld::No), |
| 2739 | _ => linker_flavor, |
| 2740 | }; |
| 2741 | if !args.contains_key(&linker_flavor) { |
| 2742 | add_link_args_iter(args, linker_flavor, args_json.iter().cloned()); |
| 2743 | } |
| 2744 | } |
| 2745 | } |
| 2746 | } |
| 2747 | |
| 2748 | fn update_to_cli(&mut self) { |
| 2749 | self.linker_flavor_json = self.linker_flavor.to_cli_counterpart(); |
| 2750 | self.lld_flavor_json = self.linker_flavor.lld_flavor(); |
| 2751 | self.linker_is_gnu_json = self.linker_flavor.is_gnu(); |
| 2752 | for (args, args_json) in [ |
| 2753 | (&self.pre_link_args, &mut self.pre_link_args_json), |
| 2754 | (&self.late_link_args, &mut self.late_link_args_json), |
| 2755 | (&self.late_link_args_dynamic, &mut self.late_link_args_dynamic_json), |
| 2756 | (&self.late_link_args_static, &mut self.late_link_args_static_json), |
| 2757 | (&self.post_link_args, &mut self.post_link_args_json), |
| 2758 | ] { |
| 2759 | *args_json = args |
| 2760 | .iter() |
| 2761 | .map(|(flavor, args)| (flavor.to_cli_counterpart(), args.clone())) |
| 2762 | .collect(); |
| 2763 | } |
| 2764 | } |
| 2765 | } |
| 2766 | |
| 2767 | impl Default for TargetOptions { |
| 2768 | /// Creates a set of "sane defaults" for any target. This is still |
| 2769 | /// incomplete, and if used for compilation, will certainly not work. |
| 2770 | fn default() -> TargetOptions { |
| 2771 | TargetOptions { |
| 2772 | endian: Endian::Little, |
| 2773 | c_int_width: "32" .into(), |
| 2774 | os: "none" .into(), |
| 2775 | env: "" .into(), |
| 2776 | abi: "" .into(), |
| 2777 | vendor: "unknown" .into(), |
| 2778 | linker: option_env!("CFG_DEFAULT_LINKER" ).map(|s| s.into()), |
| 2779 | linker_flavor: LinkerFlavor::Gnu(Cc::Yes, Lld::No), |
| 2780 | linker_flavor_json: LinkerFlavorCli::Gcc, |
| 2781 | lld_flavor_json: LldFlavor::Ld, |
| 2782 | linker_is_gnu_json: true, |
| 2783 | link_script: None, |
| 2784 | asm_args: cvs![], |
| 2785 | cpu: "generic" .into(), |
| 2786 | need_explicit_cpu: false, |
| 2787 | features: "" .into(), |
| 2788 | direct_access_external_data: None, |
| 2789 | dynamic_linking: false, |
| 2790 | dll_tls_export: true, |
| 2791 | only_cdylib: false, |
| 2792 | executables: true, |
| 2793 | relocation_model: RelocModel::Pic, |
| 2794 | code_model: None, |
| 2795 | tls_model: TlsModel::GeneralDynamic, |
| 2796 | disable_redzone: false, |
| 2797 | frame_pointer: FramePointer::MayOmit, |
| 2798 | function_sections: true, |
| 2799 | dll_prefix: "lib" .into(), |
| 2800 | dll_suffix: ".so" .into(), |
| 2801 | exe_suffix: "" .into(), |
| 2802 | staticlib_prefix: "lib" .into(), |
| 2803 | staticlib_suffix: ".a" .into(), |
| 2804 | families: cvs![], |
| 2805 | abi_return_struct_as_int: false, |
| 2806 | is_like_aix: false, |
| 2807 | is_like_osx: false, |
| 2808 | is_like_solaris: false, |
| 2809 | is_like_windows: false, |
| 2810 | is_like_msvc: false, |
| 2811 | is_like_wasm: false, |
| 2812 | is_like_android: false, |
| 2813 | binary_format: BinaryFormat::Elf, |
| 2814 | default_dwarf_version: 4, |
| 2815 | allows_weak_linkage: true, |
| 2816 | has_rpath: false, |
| 2817 | no_default_libraries: true, |
| 2818 | position_independent_executables: false, |
| 2819 | static_position_independent_executables: false, |
| 2820 | plt_by_default: true, |
| 2821 | relro_level: RelroLevel::None, |
| 2822 | pre_link_objects: Default::default(), |
| 2823 | post_link_objects: Default::default(), |
| 2824 | pre_link_objects_self_contained: Default::default(), |
| 2825 | post_link_objects_self_contained: Default::default(), |
| 2826 | link_self_contained: LinkSelfContainedDefault::False, |
| 2827 | pre_link_args: LinkArgs::new(), |
| 2828 | pre_link_args_json: LinkArgsCli::new(), |
| 2829 | late_link_args: LinkArgs::new(), |
| 2830 | late_link_args_json: LinkArgsCli::new(), |
| 2831 | late_link_args_dynamic: LinkArgs::new(), |
| 2832 | late_link_args_dynamic_json: LinkArgsCli::new(), |
| 2833 | late_link_args_static: LinkArgs::new(), |
| 2834 | late_link_args_static_json: LinkArgsCli::new(), |
| 2835 | post_link_args: LinkArgs::new(), |
| 2836 | post_link_args_json: LinkArgsCli::new(), |
| 2837 | link_env: cvs![], |
| 2838 | link_env_remove: cvs![], |
| 2839 | archive_format: "gnu" .into(), |
| 2840 | main_needs_argc_argv: true, |
| 2841 | allow_asm: true, |
| 2842 | has_thread_local: false, |
| 2843 | obj_is_bitcode: false, |
| 2844 | bitcode_llvm_cmdline: "" .into(), |
| 2845 | min_atomic_width: None, |
| 2846 | max_atomic_width: None, |
| 2847 | atomic_cas: true, |
| 2848 | panic_strategy: PanicStrategy::Unwind, |
| 2849 | crt_static_allows_dylibs: false, |
| 2850 | crt_static_default: false, |
| 2851 | crt_static_respected: false, |
| 2852 | stack_probes: StackProbeType::None, |
| 2853 | min_global_align: None, |
| 2854 | default_codegen_units: None, |
| 2855 | default_codegen_backend: None, |
| 2856 | trap_unreachable: true, |
| 2857 | requires_lto: false, |
| 2858 | singlethread: false, |
| 2859 | no_builtins: false, |
| 2860 | default_visibility: None, |
| 2861 | emit_debug_gdb_scripts: true, |
| 2862 | requires_uwtable: false, |
| 2863 | default_uwtable: false, |
| 2864 | simd_types_indirect: true, |
| 2865 | limit_rdylib_exports: true, |
| 2866 | override_export_symbols: None, |
| 2867 | merge_functions: MergeFunctions::Aliases, |
| 2868 | mcount: "mcount" .into(), |
| 2869 | llvm_mcount_intrinsic: None, |
| 2870 | llvm_abiname: "" .into(), |
| 2871 | llvm_floatabi: None, |
| 2872 | rustc_abi: None, |
| 2873 | relax_elf_relocations: false, |
| 2874 | llvm_args: cvs![], |
| 2875 | use_ctors_section: false, |
| 2876 | eh_frame_header: true, |
| 2877 | has_thumb_interworking: false, |
| 2878 | debuginfo_kind: Default::default(), |
| 2879 | split_debuginfo: Default::default(), |
| 2880 | // `Off` is supported by default, but targets can remove this manually, e.g. Windows. |
| 2881 | supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), |
| 2882 | supported_sanitizers: SanitizerSet::empty(), |
| 2883 | c_enum_min_bits: None, |
| 2884 | generate_arange_section: true, |
| 2885 | supports_stack_protector: true, |
| 2886 | entry_name: "main" .into(), |
| 2887 | entry_abi: Conv::C, |
| 2888 | supports_xray: false, |
| 2889 | small_data_threshold_support: SmallDataThresholdSupport::DefaultForArch, |
| 2890 | } |
| 2891 | } |
| 2892 | } |
| 2893 | |
| 2894 | /// `TargetOptions` being a separate type is basically an implementation detail of `Target` that is |
| 2895 | /// used for providing defaults. Perhaps there's a way to merge `TargetOptions` into `Target` so |
| 2896 | /// this `Deref` implementation is no longer necessary. |
| 2897 | impl Deref for Target { |
| 2898 | type Target = TargetOptions; |
| 2899 | |
| 2900 | #[inline ] |
| 2901 | fn deref(&self) -> &Self::Target { |
| 2902 | &self.options |
| 2903 | } |
| 2904 | } |
| 2905 | impl DerefMut for Target { |
| 2906 | #[inline ] |
| 2907 | fn deref_mut(&mut self) -> &mut Self::Target { |
| 2908 | &mut self.options |
| 2909 | } |
| 2910 | } |
| 2911 | |
| 2912 | impl Target { |
| 2913 | /// Given a function ABI, turn it into the correct ABI for this target. |
| 2914 | pub fn adjust_abi(&self, abi: ExternAbi, c_variadic: bool) -> ExternAbi { |
| 2915 | use ExternAbi::*; |
| 2916 | match abi { |
| 2917 | // On Windows, `extern "system"` behaves like msvc's `__stdcall`. |
| 2918 | // `__stdcall` only applies on x86 and on non-variadic functions: |
| 2919 | // https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170 |
| 2920 | System { unwind } => { |
| 2921 | if self.is_like_windows && self.arch == "x86" && !c_variadic { |
| 2922 | Stdcall { unwind } |
| 2923 | } else { |
| 2924 | C { unwind } |
| 2925 | } |
| 2926 | } |
| 2927 | |
| 2928 | EfiApi => { |
| 2929 | if self.arch == "arm" { |
| 2930 | Aapcs { unwind: false } |
| 2931 | } else if self.arch == "x86_64" { |
| 2932 | Win64 { unwind: false } |
| 2933 | } else { |
| 2934 | C { unwind: false } |
| 2935 | } |
| 2936 | } |
| 2937 | |
| 2938 | // See commentary in `is_abi_supported`. |
| 2939 | Stdcall { unwind } | Thiscall { unwind } | Fastcall { unwind } => { |
| 2940 | if self.arch == "x86" { abi } else { C { unwind } } |
| 2941 | } |
| 2942 | Vectorcall { unwind } => { |
| 2943 | if ["x86" , "x86_64" ].contains(&&*self.arch) { |
| 2944 | abi |
| 2945 | } else { |
| 2946 | C { unwind } |
| 2947 | } |
| 2948 | } |
| 2949 | |
| 2950 | // The Windows x64 calling convention we use for `extern "Rust"` |
| 2951 | // <https://learn.microsoft.com/en-us/cpp/build/x64-software-conventions#register-volatility-and-preservation> |
| 2952 | // expects the callee to save `xmm6` through `xmm15`, but `PreserveMost` |
| 2953 | // (that we use by default for `extern "rust-cold"`) doesn't save any of those. |
| 2954 | // So to avoid bloating callers, just use the Rust convention here. |
| 2955 | RustCold if self.is_like_windows && self.arch == "x86_64" => Rust, |
| 2956 | |
| 2957 | abi => abi, |
| 2958 | } |
| 2959 | } |
| 2960 | |
| 2961 | pub fn is_abi_supported(&self, abi: ExternAbi) -> bool { |
| 2962 | use ExternAbi::*; |
| 2963 | match abi { |
| 2964 | Rust |
| 2965 | | C { .. } |
| 2966 | | System { .. } |
| 2967 | | RustIntrinsic |
| 2968 | | RustCall |
| 2969 | | Unadjusted |
| 2970 | | Cdecl { .. } |
| 2971 | | RustCold => true, |
| 2972 | EfiApi => { |
| 2973 | ["arm" , "aarch64" , "riscv32" , "riscv64" , "x86" , "x86_64" ].contains(&&self.arch[..]) |
| 2974 | } |
| 2975 | X86Interrupt => ["x86" , "x86_64" ].contains(&&self.arch[..]), |
| 2976 | Aapcs { .. } => "arm" == self.arch, |
| 2977 | CCmseNonSecureCall | CCmseNonSecureEntry => { |
| 2978 | ["thumbv8m.main-none-eabi" , "thumbv8m.main-none-eabihf" , "thumbv8m.base-none-eabi" ] |
| 2979 | .contains(&&self.llvm_target[..]) |
| 2980 | } |
| 2981 | Win64 { .. } | SysV64 { .. } => self.arch == "x86_64" , |
| 2982 | PtxKernel => self.arch == "nvptx64" , |
| 2983 | GpuKernel => ["amdgpu" , "nvptx64" ].contains(&&self.arch[..]), |
| 2984 | Msp430Interrupt => self.arch == "msp430" , |
| 2985 | RiscvInterruptM | RiscvInterruptS => ["riscv32" , "riscv64" ].contains(&&self.arch[..]), |
| 2986 | AvrInterrupt | AvrNonBlockingInterrupt => self.arch == "avr" , |
| 2987 | Thiscall { .. } => self.arch == "x86" , |
| 2988 | // On windows these fall-back to platform native calling convention (C) when the |
| 2989 | // architecture is not supported. |
| 2990 | // |
| 2991 | // This is I believe a historical accident that has occurred as part of Microsoft |
| 2992 | // striving to allow most of the code to "just" compile when support for 64-bit x86 |
| 2993 | // was added and then later again, when support for ARM architectures was added. |
| 2994 | // |
| 2995 | // This is well documented across MSDN. Support for this in Rust has been added in |
| 2996 | // #54576. This makes much more sense in context of Microsoft's C++ than it does in |
| 2997 | // Rust, but there isn't much leeway remaining here to change it back at the time this |
| 2998 | // comment has been written. |
| 2999 | // |
| 3000 | // Following are the relevant excerpts from the MSDN documentation. |
| 3001 | // |
| 3002 | // > The __vectorcall calling convention is only supported in native code on x86 and |
| 3003 | // x64 processors that include Streaming SIMD Extensions 2 (SSE2) and above. |
| 3004 | // > ... |
| 3005 | // > On ARM machines, __vectorcall is accepted and ignored by the compiler. |
| 3006 | // |
| 3007 | // -- https://docs.microsoft.com/en-us/cpp/cpp/vectorcall?view=msvc-160 |
| 3008 | // |
| 3009 | // > On ARM and x64 processors, __stdcall is accepted and ignored by the compiler; |
| 3010 | // |
| 3011 | // -- https://docs.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-160 |
| 3012 | // |
| 3013 | // > In most cases, keywords or compiler switches that specify an unsupported |
| 3014 | // > convention on a particular platform are ignored, and the platform default |
| 3015 | // > convention is used. |
| 3016 | // |
| 3017 | // -- https://docs.microsoft.com/en-us/cpp/cpp/argument-passing-and-naming-conventions |
| 3018 | Stdcall { .. } | Fastcall { .. } | Vectorcall { .. } if self.is_like_windows => true, |
| 3019 | // Outside of Windows we want to only support these calling conventions for the |
| 3020 | // architectures for which these calling conventions are actually well defined. |
| 3021 | Stdcall { .. } | Fastcall { .. } if self.arch == "x86" => true, |
| 3022 | Vectorcall { .. } if ["x86" , "x86_64" ].contains(&&self.arch[..]) => true, |
| 3023 | // Reject these calling conventions everywhere else. |
| 3024 | Stdcall { .. } | Fastcall { .. } | Vectorcall { .. } => false, |
| 3025 | } |
| 3026 | } |
| 3027 | |
| 3028 | /// Minimum integer size in bits that this target can perform atomic |
| 3029 | /// operations on. |
| 3030 | pub fn min_atomic_width(&self) -> u64 { |
| 3031 | self.min_atomic_width.unwrap_or(8) |
| 3032 | } |
| 3033 | |
| 3034 | /// Maximum integer size in bits that this target can perform atomic |
| 3035 | /// operations on. |
| 3036 | pub fn max_atomic_width(&self) -> u64 { |
| 3037 | self.max_atomic_width.unwrap_or_else(|| self.pointer_width.into()) |
| 3038 | } |
| 3039 | |
| 3040 | /// Check some basic consistency of the current target. For JSON targets we are less strict; |
| 3041 | /// some of these checks are more guidelines than strict rules. |
| 3042 | fn check_consistency(&self, kind: TargetKind) -> Result<(), String> { |
| 3043 | macro_rules! check { |
| 3044 | ($b:expr, $($msg:tt)*) => { |
| 3045 | if !$b { |
| 3046 | return Err(format!($($msg)*)); |
| 3047 | } |
| 3048 | } |
| 3049 | } |
| 3050 | macro_rules! check_eq { |
| 3051 | ($left:expr, $right:expr, $($msg:tt)*) => { |
| 3052 | if ($left) != ($right) { |
| 3053 | return Err(format!($($msg)*)); |
| 3054 | } |
| 3055 | } |
| 3056 | } |
| 3057 | macro_rules! check_ne { |
| 3058 | ($left:expr, $right:expr, $($msg:tt)*) => { |
| 3059 | if ($left) == ($right) { |
| 3060 | return Err(format!($($msg)*)); |
| 3061 | } |
| 3062 | } |
| 3063 | } |
| 3064 | macro_rules! check_matches { |
| 3065 | ($left:expr, $right:pat, $($msg:tt)*) => { |
| 3066 | if !matches!($left, $right) { |
| 3067 | return Err(format!($($msg)*)); |
| 3068 | } |
| 3069 | } |
| 3070 | } |
| 3071 | |
| 3072 | check_eq!( |
| 3073 | self.is_like_osx, |
| 3074 | self.vendor == "apple" , |
| 3075 | "`is_like_osx` must be set if and only if `vendor` is `apple`" |
| 3076 | ); |
| 3077 | check_eq!( |
| 3078 | self.is_like_solaris, |
| 3079 | self.os == "solaris" || self.os == "illumos" , |
| 3080 | "`is_like_solaris` must be set if and only if `os` is `solaris` or `illumos`" |
| 3081 | ); |
| 3082 | check_eq!( |
| 3083 | self.is_like_windows, |
| 3084 | self.os == "windows" || self.os == "uefi" || self.os == "cygwin" , |
| 3085 | "`is_like_windows` must be set if and only if `os` is `windows`, `uefi` or `cygwin`" |
| 3086 | ); |
| 3087 | check_eq!( |
| 3088 | self.is_like_wasm, |
| 3089 | self.arch == "wasm32" || self.arch == "wasm64" , |
| 3090 | "`is_like_wasm` must be set if and only if `arch` is `wasm32` or `wasm64`" |
| 3091 | ); |
| 3092 | if self.is_like_msvc { |
| 3093 | check!(self.is_like_windows, "if `is_like_msvc` is set, `is_like_windows` must be set" ); |
| 3094 | } |
| 3095 | if self.os == "emscripten" { |
| 3096 | check!(self.is_like_wasm, "the `emcscripten` os only makes sense on wasm-like targets" ); |
| 3097 | } |
| 3098 | |
| 3099 | // Check that default linker flavor is compatible with some other key properties. |
| 3100 | check_eq!( |
| 3101 | self.is_like_osx, |
| 3102 | matches!(self.linker_flavor, LinkerFlavor::Darwin(..)), |
| 3103 | "`linker_flavor` must be `darwin` if and only if `is_like_osx` is set" |
| 3104 | ); |
| 3105 | check_eq!( |
| 3106 | self.is_like_msvc, |
| 3107 | matches!(self.linker_flavor, LinkerFlavor::Msvc(..)), |
| 3108 | "`linker_flavor` must be `msvc` if and only if `is_like_msvc` is set" |
| 3109 | ); |
| 3110 | check_eq!( |
| 3111 | self.is_like_wasm && self.os != "emscripten" , |
| 3112 | matches!(self.linker_flavor, LinkerFlavor::WasmLld(..)), |
| 3113 | "`linker_flavor` must be `wasm-lld` if and only if `is_like_wasm` is set and the `os` is not `emscripten`" , |
| 3114 | ); |
| 3115 | check_eq!( |
| 3116 | self.os == "emscripten" , |
| 3117 | matches!(self.linker_flavor, LinkerFlavor::EmCc), |
| 3118 | "`linker_flavor` must be `em-cc` if and only if `os` is `emscripten`" |
| 3119 | ); |
| 3120 | check_eq!( |
| 3121 | self.arch == "bpf" , |
| 3122 | matches!(self.linker_flavor, LinkerFlavor::Bpf), |
| 3123 | "`linker_flavor` must be `bpf` if and only if `arch` is `bpf`" |
| 3124 | ); |
| 3125 | check_eq!( |
| 3126 | self.arch == "nvptx64" , |
| 3127 | matches!(self.linker_flavor, LinkerFlavor::Ptx), |
| 3128 | "`linker_flavor` must be `ptc` if and only if `arch` is `nvptx64`" |
| 3129 | ); |
| 3130 | |
| 3131 | for args in [ |
| 3132 | &self.pre_link_args, |
| 3133 | &self.late_link_args, |
| 3134 | &self.late_link_args_dynamic, |
| 3135 | &self.late_link_args_static, |
| 3136 | &self.post_link_args, |
| 3137 | ] { |
| 3138 | for (&flavor, flavor_args) in args { |
| 3139 | check!( |
| 3140 | !flavor_args.is_empty() || self.arch == "avr" , |
| 3141 | "linker flavor args must not be empty" |
| 3142 | ); |
| 3143 | // Check that flavors mentioned in link args are compatible with the default flavor. |
| 3144 | match self.linker_flavor { |
| 3145 | LinkerFlavor::Gnu(..) => { |
| 3146 | check_matches!( |
| 3147 | flavor, |
| 3148 | LinkerFlavor::Gnu(..), |
| 3149 | "mixing GNU and non-GNU linker flavors" |
| 3150 | ); |
| 3151 | } |
| 3152 | LinkerFlavor::Darwin(..) => { |
| 3153 | check_matches!( |
| 3154 | flavor, |
| 3155 | LinkerFlavor::Darwin(..), |
| 3156 | "mixing Darwin and non-Darwin linker flavors" |
| 3157 | ) |
| 3158 | } |
| 3159 | LinkerFlavor::WasmLld(..) => { |
| 3160 | check_matches!( |
| 3161 | flavor, |
| 3162 | LinkerFlavor::WasmLld(..), |
| 3163 | "mixing wasm and non-wasm linker flavors" |
| 3164 | ) |
| 3165 | } |
| 3166 | LinkerFlavor::Unix(..) => { |
| 3167 | check_matches!( |
| 3168 | flavor, |
| 3169 | LinkerFlavor::Unix(..), |
| 3170 | "mixing unix and non-unix linker flavors" |
| 3171 | ); |
| 3172 | } |
| 3173 | LinkerFlavor::Msvc(..) => { |
| 3174 | check_matches!( |
| 3175 | flavor, |
| 3176 | LinkerFlavor::Msvc(..), |
| 3177 | "mixing MSVC and non-MSVC linker flavors" |
| 3178 | ); |
| 3179 | } |
| 3180 | LinkerFlavor::EmCc |
| 3181 | | LinkerFlavor::Bpf |
| 3182 | | LinkerFlavor::Ptx |
| 3183 | | LinkerFlavor::Llbc => { |
| 3184 | check_eq!(flavor, self.linker_flavor, "mixing different linker flavors" ) |
| 3185 | } |
| 3186 | } |
| 3187 | |
| 3188 | // Check that link args for cc and non-cc versions of flavors are consistent. |
| 3189 | let check_noncc = |noncc_flavor| -> Result<(), String> { |
| 3190 | if let Some(noncc_args) = args.get(&noncc_flavor) { |
| 3191 | for arg in flavor_args { |
| 3192 | if let Some(suffix) = arg.strip_prefix("-Wl," ) { |
| 3193 | check!( |
| 3194 | noncc_args.iter().any(|a| a == suffix), |
| 3195 | " link args for cc and non-cc versions of flavors are not consistent" |
| 3196 | ); |
| 3197 | } |
| 3198 | } |
| 3199 | } |
| 3200 | Ok(()) |
| 3201 | }; |
| 3202 | |
| 3203 | match self.linker_flavor { |
| 3204 | LinkerFlavor::Gnu(Cc::Yes, lld) => check_noncc(LinkerFlavor::Gnu(Cc::No, lld))?, |
| 3205 | LinkerFlavor::WasmLld(Cc::Yes) => check_noncc(LinkerFlavor::WasmLld(Cc::No))?, |
| 3206 | LinkerFlavor::Unix(Cc::Yes) => check_noncc(LinkerFlavor::Unix(Cc::No))?, |
| 3207 | _ => {} |
| 3208 | } |
| 3209 | } |
| 3210 | |
| 3211 | // Check that link args for lld and non-lld versions of flavors are consistent. |
| 3212 | for cc in [Cc::No, Cc::Yes] { |
| 3213 | check_eq!( |
| 3214 | args.get(&LinkerFlavor::Gnu(cc, Lld::No)), |
| 3215 | args.get(&LinkerFlavor::Gnu(cc, Lld::Yes)), |
| 3216 | "link args for lld and non-lld versions of flavors are not consistent" , |
| 3217 | ); |
| 3218 | check_eq!( |
| 3219 | args.get(&LinkerFlavor::Darwin(cc, Lld::No)), |
| 3220 | args.get(&LinkerFlavor::Darwin(cc, Lld::Yes)), |
| 3221 | "link args for lld and non-lld versions of flavors are not consistent" , |
| 3222 | ); |
| 3223 | } |
| 3224 | check_eq!( |
| 3225 | args.get(&LinkerFlavor::Msvc(Lld::No)), |
| 3226 | args.get(&LinkerFlavor::Msvc(Lld::Yes)), |
| 3227 | "link args for lld and non-lld versions of flavors are not consistent" , |
| 3228 | ); |
| 3229 | } |
| 3230 | |
| 3231 | if self.link_self_contained.is_disabled() { |
| 3232 | check!( |
| 3233 | self.pre_link_objects_self_contained.is_empty() |
| 3234 | && self.post_link_objects_self_contained.is_empty(), |
| 3235 | "if `link_self_contained` is disabled, then `pre_link_objects_self_contained` and `post_link_objects_self_contained` must be empty" , |
| 3236 | ); |
| 3237 | } |
| 3238 | |
| 3239 | // If your target really needs to deviate from the rules below, |
| 3240 | // except it and document the reasons. |
| 3241 | // Keep the default "unknown" vendor instead. |
| 3242 | check_ne!(self.vendor, "" , "`vendor` cannot be empty" ); |
| 3243 | check_ne!(self.os, "" , "`os` cannot be empty" ); |
| 3244 | if !self.can_use_os_unknown() { |
| 3245 | // Keep the default "none" for bare metal targets instead. |
| 3246 | check_ne!( |
| 3247 | self.os, |
| 3248 | "unknown" , |
| 3249 | "`unknown` os can only be used on particular targets; use `none` for bare-metal targets" |
| 3250 | ); |
| 3251 | } |
| 3252 | |
| 3253 | // Check dynamic linking stuff. |
| 3254 | // We skip this for JSON targets since otherwise, our default values would fail this test. |
| 3255 | // These checks are not critical for correctness, but more like default guidelines. |
| 3256 | // FIXME (https://github.com/rust-lang/rust/issues/133459): do we want to change the JSON |
| 3257 | // target defaults so that they pass these checks? |
| 3258 | if kind == TargetKind::Builtin { |
| 3259 | // BPF: when targeting user space vms (like rbpf), those can load dynamic libraries. |
| 3260 | // hexagon: when targeting QuRT, that OS can load dynamic libraries. |
| 3261 | // wasm{32,64}: dynamic linking is inherent in the definition of the VM. |
| 3262 | if self.os == "none" |
| 3263 | && (self.arch != "bpf" |
| 3264 | && self.arch != "hexagon" |
| 3265 | && self.arch != "wasm32" |
| 3266 | && self.arch != "wasm64" ) |
| 3267 | { |
| 3268 | check!( |
| 3269 | !self.dynamic_linking, |
| 3270 | "dynamic linking is not supported on this OS/architecture" |
| 3271 | ); |
| 3272 | } |
| 3273 | if self.only_cdylib |
| 3274 | || self.crt_static_allows_dylibs |
| 3275 | || !self.late_link_args_dynamic.is_empty() |
| 3276 | { |
| 3277 | check!( |
| 3278 | self.dynamic_linking, |
| 3279 | "dynamic linking must be allowed when `only_cdylib` or `crt_static_allows_dylibs` or `late_link_args_dynamic` are set" |
| 3280 | ); |
| 3281 | } |
| 3282 | // Apparently PIC was slow on wasm at some point, see comments in wasm_base.rs |
| 3283 | if self.dynamic_linking && !self.is_like_wasm { |
| 3284 | check_eq!( |
| 3285 | self.relocation_model, |
| 3286 | RelocModel::Pic, |
| 3287 | "targets that support dynamic linking must use the `pic` relocation model" |
| 3288 | ); |
| 3289 | } |
| 3290 | if self.position_independent_executables { |
| 3291 | check_eq!( |
| 3292 | self.relocation_model, |
| 3293 | RelocModel::Pic, |
| 3294 | "targets that support position-independent executables must use the `pic` relocation model" |
| 3295 | ); |
| 3296 | } |
| 3297 | // The UEFI targets do not support dynamic linking but still require PIC (#101377). |
| 3298 | if self.relocation_model == RelocModel::Pic && (self.os != "uefi" ) { |
| 3299 | check!( |
| 3300 | self.dynamic_linking || self.position_independent_executables, |
| 3301 | "when the relocation model is `pic`, the target must support dynamic linking or use position-independent executables. \ |
| 3302 | Set the relocation model to `static` to avoid this requirement" |
| 3303 | ); |
| 3304 | } |
| 3305 | if self.static_position_independent_executables { |
| 3306 | check!( |
| 3307 | self.position_independent_executables, |
| 3308 | "if `static_position_independent_executables` is set, then `position_independent_executables` must be set" |
| 3309 | ); |
| 3310 | } |
| 3311 | if self.position_independent_executables { |
| 3312 | check!( |
| 3313 | self.executables, |
| 3314 | "if `position_independent_executables` is set then `executables` must be set" |
| 3315 | ); |
| 3316 | } |
| 3317 | } |
| 3318 | |
| 3319 | // Check crt static stuff |
| 3320 | if self.crt_static_default || self.crt_static_allows_dylibs { |
| 3321 | check!( |
| 3322 | self.crt_static_respected, |
| 3323 | "static CRT can be enabled but `crt_static_respected` is not set" |
| 3324 | ); |
| 3325 | } |
| 3326 | |
| 3327 | // Check that RISC-V targets always specify which ABI they use, |
| 3328 | // and that ARM targets specify their float ABI. |
| 3329 | match &*self.arch { |
| 3330 | "riscv32" => { |
| 3331 | check_matches!( |
| 3332 | &*self.llvm_abiname, |
| 3333 | "ilp32" | "ilp32f" | "ilp32d" | "ilp32e" , |
| 3334 | "invalid RISC-V ABI name: {}" , |
| 3335 | self.llvm_abiname, |
| 3336 | ); |
| 3337 | } |
| 3338 | "riscv64" => { |
| 3339 | // Note that the `lp64e` is still unstable as it's not (yet) part of the ELF psABI. |
| 3340 | check_matches!( |
| 3341 | &*self.llvm_abiname, |
| 3342 | "lp64" | "lp64f" | "lp64d" | "lp64e" , |
| 3343 | "invalid RISC-V ABI name: {}" , |
| 3344 | self.llvm_abiname, |
| 3345 | ); |
| 3346 | } |
| 3347 | "arm" => { |
| 3348 | check!( |
| 3349 | self.llvm_floatabi.is_some(), |
| 3350 | "ARM targets must set `llvm-floatabi` to `hard` or `soft`" , |
| 3351 | ) |
| 3352 | } |
| 3353 | _ => {} |
| 3354 | } |
| 3355 | |
| 3356 | // Check consistency of Rust ABI declaration. |
| 3357 | if let Some(rust_abi) = self.rustc_abi { |
| 3358 | match rust_abi { |
| 3359 | RustcAbi::X86Sse2 => check_matches!( |
| 3360 | &*self.arch, |
| 3361 | "x86" , |
| 3362 | "`x86-sse2` ABI is only valid for x86-32 targets" |
| 3363 | ), |
| 3364 | RustcAbi::X86Softfloat => check_matches!( |
| 3365 | &*self.arch, |
| 3366 | "x86" | "x86_64" , |
| 3367 | "`x86-softfloat` ABI is only valid for x86 targets" |
| 3368 | ), |
| 3369 | } |
| 3370 | } |
| 3371 | |
| 3372 | // Check that the given target-features string makes some basic sense. |
| 3373 | if !self.features.is_empty() { |
| 3374 | let mut features_enabled = FxHashSet::default(); |
| 3375 | let mut features_disabled = FxHashSet::default(); |
| 3376 | for feat in self.features.split(',' ) { |
| 3377 | if let Some(feat) = feat.strip_prefix("+" ) { |
| 3378 | features_enabled.insert(feat); |
| 3379 | if features_disabled.contains(feat) { |
| 3380 | return Err(format!( |
| 3381 | "target feature ` {feat}` is both enabled and disabled" |
| 3382 | )); |
| 3383 | } |
| 3384 | } else if let Some(feat) = feat.strip_prefix("-" ) { |
| 3385 | features_disabled.insert(feat); |
| 3386 | if features_enabled.contains(feat) { |
| 3387 | return Err(format!( |
| 3388 | "target feature ` {feat}` is both enabled and disabled" |
| 3389 | )); |
| 3390 | } |
| 3391 | } else { |
| 3392 | return Err(format!( |
| 3393 | "target feature ` {feat}` is invalid, must start with `+` or `-`" |
| 3394 | )); |
| 3395 | } |
| 3396 | } |
| 3397 | // Check that we don't mis-set any of the ABI-relevant features. |
| 3398 | let abi_feature_constraints = self.abi_required_features(); |
| 3399 | for feat in abi_feature_constraints.required { |
| 3400 | // The feature might be enabled by default so we can't *require* it to show up. |
| 3401 | // But it must not be *disabled*. |
| 3402 | if features_disabled.contains(feat) { |
| 3403 | return Err(format!( |
| 3404 | "target feature ` {feat}` is required by the ABI but gets disabled in target spec" |
| 3405 | )); |
| 3406 | } |
| 3407 | } |
| 3408 | for feat in abi_feature_constraints.incompatible { |
| 3409 | // The feature might be disabled by default so we can't *require* it to show up. |
| 3410 | // But it must not be *enabled*. |
| 3411 | if features_enabled.contains(feat) { |
| 3412 | return Err(format!( |
| 3413 | "target feature ` {feat}` is incompatible with the ABI but gets enabled in target spec" |
| 3414 | )); |
| 3415 | } |
| 3416 | } |
| 3417 | } |
| 3418 | |
| 3419 | Ok(()) |
| 3420 | } |
| 3421 | |
| 3422 | /// Test target self-consistency and JSON encoding/decoding roundtrip. |
| 3423 | #[cfg (test)] |
| 3424 | fn test_target(mut self) { |
| 3425 | let recycled_target = Target::from_json(self.to_json()).map(|(j, _)| j); |
| 3426 | self.update_to_cli(); |
| 3427 | self.check_consistency(TargetKind::Builtin).unwrap(); |
| 3428 | assert_eq!(recycled_target, Ok(self)); |
| 3429 | } |
| 3430 | |
| 3431 | // Add your target to the whitelist if it has `std` library |
| 3432 | // and you certainly want "unknown" for the OS name. |
| 3433 | fn can_use_os_unknown(&self) -> bool { |
| 3434 | self.llvm_target == "wasm32-unknown-unknown" |
| 3435 | || self.llvm_target == "wasm64-unknown-unknown" |
| 3436 | || (self.env == "sgx" && self.vendor == "fortanix" ) |
| 3437 | } |
| 3438 | |
| 3439 | /// Load a built-in target |
| 3440 | pub fn expect_builtin(target_tuple: &TargetTuple) -> Target { |
| 3441 | match *target_tuple { |
| 3442 | TargetTuple::TargetTuple(ref target_tuple) => { |
| 3443 | load_builtin(target_tuple).expect("built-in target" ) |
| 3444 | } |
| 3445 | TargetTuple::TargetJson { .. } => { |
| 3446 | panic!("built-in targets doesn't support target-paths" ) |
| 3447 | } |
| 3448 | } |
| 3449 | } |
| 3450 | |
| 3451 | /// Load all built-in targets |
| 3452 | pub fn builtins() -> impl Iterator<Item = Target> { |
| 3453 | load_all_builtins() |
| 3454 | } |
| 3455 | |
| 3456 | /// Search for a JSON file specifying the given target tuple. |
| 3457 | /// |
| 3458 | /// If none is found in `$RUST_TARGET_PATH`, look for a file called `target.json` inside the |
| 3459 | /// sysroot under the target-tuple's `rustlib` directory. Note that it could also just be a |
| 3460 | /// bare filename already, so also check for that. If one of the hardcoded targets we know |
| 3461 | /// about, just return it directly. |
| 3462 | /// |
| 3463 | /// The error string could come from any of the APIs called, including filesystem access and |
| 3464 | /// JSON decoding. |
| 3465 | pub fn search( |
| 3466 | target_tuple: &TargetTuple, |
| 3467 | sysroot: &Path, |
| 3468 | ) -> Result<(Target, TargetWarnings), String> { |
| 3469 | use std::{env, fs}; |
| 3470 | |
| 3471 | fn load_file(path: &Path) -> Result<(Target, TargetWarnings), String> { |
| 3472 | let contents = fs::read_to_string(path).map_err(|e| e.to_string())?; |
| 3473 | let obj = serde_json::from_str(&contents).map_err(|e| e.to_string())?; |
| 3474 | Target::from_json(obj) |
| 3475 | } |
| 3476 | |
| 3477 | match *target_tuple { |
| 3478 | TargetTuple::TargetTuple(ref target_tuple) => { |
| 3479 | // check if tuple is in list of built-in targets |
| 3480 | if let Some(t) = load_builtin(target_tuple) { |
| 3481 | return Ok((t, TargetWarnings::empty())); |
| 3482 | } |
| 3483 | |
| 3484 | // search for a file named `target_tuple`.json in RUST_TARGET_PATH |
| 3485 | let path = { |
| 3486 | let mut target = target_tuple.to_string(); |
| 3487 | target.push_str(".json" ); |
| 3488 | PathBuf::from(target) |
| 3489 | }; |
| 3490 | |
| 3491 | let target_path = env::var_os("RUST_TARGET_PATH" ).unwrap_or_default(); |
| 3492 | |
| 3493 | for dir in env::split_paths(&target_path) { |
| 3494 | let p = dir.join(&path); |
| 3495 | if p.is_file() { |
| 3496 | return load_file(&p); |
| 3497 | } |
| 3498 | } |
| 3499 | |
| 3500 | // Additionally look in the sysroot under `lib/rustlib/<tuple>/target.json` |
| 3501 | // as a fallback. |
| 3502 | let rustlib_path = crate::relative_target_rustlib_path(sysroot, target_tuple); |
| 3503 | let p = PathBuf::from_iter([ |
| 3504 | Path::new(sysroot), |
| 3505 | Path::new(&rustlib_path), |
| 3506 | Path::new("target.json" ), |
| 3507 | ]); |
| 3508 | if p.is_file() { |
| 3509 | return load_file(&p); |
| 3510 | } |
| 3511 | |
| 3512 | // Leave in a specialized error message for the removed target. |
| 3513 | // FIXME: If you see this and it's been a few months after this has been released, |
| 3514 | // you can probably remove it. |
| 3515 | if target_tuple == "i586-pc-windows-msvc" { |
| 3516 | Err("the `i586-pc-windows-msvc` target has been removed. Use the `i686-pc-windows-msvc` target instead. \n\ |
| 3517 | Windows 10 (the minimum required OS version) requires a CPU baseline of at least i686 so you can safely switch" .into()) |
| 3518 | } else { |
| 3519 | Err(format!("Could not find specification for target {target_tuple:?}" )) |
| 3520 | } |
| 3521 | } |
| 3522 | TargetTuple::TargetJson { ref contents, .. } => { |
| 3523 | let obj = serde_json::from_str(contents).map_err(|e| e.to_string())?; |
| 3524 | Target::from_json(obj) |
| 3525 | } |
| 3526 | } |
| 3527 | } |
| 3528 | |
| 3529 | /// Return the target's small data threshold support, converting |
| 3530 | /// `DefaultForArch` into a concrete value. |
| 3531 | pub fn small_data_threshold_support(&self) -> SmallDataThresholdSupport { |
| 3532 | match &self.options.small_data_threshold_support { |
| 3533 | // Avoid having to duplicate the small data support in every |
| 3534 | // target file by supporting a default value for each |
| 3535 | // architecture. |
| 3536 | SmallDataThresholdSupport::DefaultForArch => match self.arch.as_ref() { |
| 3537 | "mips" | "mips64" | "mips32r6" => { |
| 3538 | SmallDataThresholdSupport::LlvmArg("mips-ssection-threshold" .into()) |
| 3539 | } |
| 3540 | "hexagon" => { |
| 3541 | SmallDataThresholdSupport::LlvmArg("hexagon-small-data-threshold" .into()) |
| 3542 | } |
| 3543 | "m68k" => SmallDataThresholdSupport::LlvmArg("m68k-ssection-threshold" .into()), |
| 3544 | "riscv32" | "riscv64" => { |
| 3545 | SmallDataThresholdSupport::LlvmModuleFlag("SmallDataLimit" .into()) |
| 3546 | } |
| 3547 | _ => SmallDataThresholdSupport::None, |
| 3548 | }, |
| 3549 | s => s.clone(), |
| 3550 | } |
| 3551 | } |
| 3552 | |
| 3553 | pub fn object_architecture( |
| 3554 | &self, |
| 3555 | unstable_target_features: &FxIndexSet<Symbol>, |
| 3556 | ) -> Option<(object::Architecture, Option<object::SubArchitecture>)> { |
| 3557 | use object::Architecture; |
| 3558 | Some(match self.arch.as_ref() { |
| 3559 | "arm" => (Architecture::Arm, None), |
| 3560 | "aarch64" => ( |
| 3561 | if self.pointer_width == 32 { |
| 3562 | Architecture::Aarch64_Ilp32 |
| 3563 | } else { |
| 3564 | Architecture::Aarch64 |
| 3565 | }, |
| 3566 | None, |
| 3567 | ), |
| 3568 | "x86" => (Architecture::I386, None), |
| 3569 | "s390x" => (Architecture::S390x, None), |
| 3570 | "mips" | "mips32r6" => (Architecture::Mips, None), |
| 3571 | "mips64" | "mips64r6" => (Architecture::Mips64, None), |
| 3572 | "x86_64" => ( |
| 3573 | if self.pointer_width == 32 { |
| 3574 | Architecture::X86_64_X32 |
| 3575 | } else { |
| 3576 | Architecture::X86_64 |
| 3577 | }, |
| 3578 | None, |
| 3579 | ), |
| 3580 | "powerpc" => (Architecture::PowerPc, None), |
| 3581 | "powerpc64" => (Architecture::PowerPc64, None), |
| 3582 | "riscv32" => (Architecture::Riscv32, None), |
| 3583 | "riscv64" => (Architecture::Riscv64, None), |
| 3584 | "sparc" => { |
| 3585 | if unstable_target_features.contains(&sym::v8plus) { |
| 3586 | // Target uses V8+, aka EM_SPARC32PLUS, aka 64-bit V9 but in 32-bit mode |
| 3587 | (Architecture::Sparc32Plus, None) |
| 3588 | } else { |
| 3589 | // Target uses V7 or V8, aka EM_SPARC |
| 3590 | (Architecture::Sparc, None) |
| 3591 | } |
| 3592 | } |
| 3593 | "sparc64" => (Architecture::Sparc64, None), |
| 3594 | "avr" => (Architecture::Avr, None), |
| 3595 | "msp430" => (Architecture::Msp430, None), |
| 3596 | "hexagon" => (Architecture::Hexagon, None), |
| 3597 | "bpf" => (Architecture::Bpf, None), |
| 3598 | "loongarch64" => (Architecture::LoongArch64, None), |
| 3599 | "csky" => (Architecture::Csky, None), |
| 3600 | "arm64ec" => (Architecture::Aarch64, Some(object::SubArchitecture::Arm64EC)), |
| 3601 | // Unsupported architecture. |
| 3602 | _ => return None, |
| 3603 | }) |
| 3604 | } |
| 3605 | } |
| 3606 | |
| 3607 | /// Either a target tuple string or a path to a JSON file. |
| 3608 | #[derive (Clone, Debug)] |
| 3609 | pub enum TargetTuple { |
| 3610 | TargetTuple(String), |
| 3611 | TargetJson { |
| 3612 | /// Warning: This field may only be used by rustdoc. Using it anywhere else will lead to |
| 3613 | /// inconsistencies as it is discarded during serialization. |
| 3614 | path_for_rustdoc: PathBuf, |
| 3615 | tuple: String, |
| 3616 | contents: String, |
| 3617 | }, |
| 3618 | } |
| 3619 | |
| 3620 | // Use a manual implementation to ignore the path field |
| 3621 | impl PartialEq for TargetTuple { |
| 3622 | fn eq(&self, other: &Self) -> bool { |
| 3623 | match (self, other) { |
| 3624 | (Self::TargetTuple(l0: &String), Self::TargetTuple(r0: &String)) => l0 == r0, |
| 3625 | ( |
| 3626 | Self::TargetJson { path_for_rustdoc: _, tuple: l_tuple: &String, contents: l_contents: &String }, |
| 3627 | Self::TargetJson { path_for_rustdoc: _, tuple: r_tuple: &String, contents: r_contents: &String }, |
| 3628 | ) => l_tuple == r_tuple && l_contents == r_contents, |
| 3629 | _ => false, |
| 3630 | } |
| 3631 | } |
| 3632 | } |
| 3633 | |
| 3634 | // Use a manual implementation to ignore the path field |
| 3635 | impl Hash for TargetTuple { |
| 3636 | fn hash<H: Hasher>(&self, state: &mut H) -> () { |
| 3637 | match self { |
| 3638 | TargetTuple::TargetTuple(tuple: &String) => { |
| 3639 | 0u8.hash(state); |
| 3640 | tuple.hash(state) |
| 3641 | } |
| 3642 | TargetTuple::TargetJson { path_for_rustdoc: _, tuple: &String, contents: &String } => { |
| 3643 | 1u8.hash(state); |
| 3644 | tuple.hash(state); |
| 3645 | contents.hash(state) |
| 3646 | } |
| 3647 | } |
| 3648 | } |
| 3649 | } |
| 3650 | |
| 3651 | // Use a manual implementation to prevent encoding the target json file path in the crate metadata |
| 3652 | impl<S: Encoder> Encodable<S> for TargetTuple { |
| 3653 | fn encode(&self, s: &mut S) { |
| 3654 | match self { |
| 3655 | TargetTuple::TargetTuple(tuple: &String) => { |
| 3656 | s.emit_u8(0); |
| 3657 | s.emit_str(tuple); |
| 3658 | } |
| 3659 | TargetTuple::TargetJson { path_for_rustdoc: _, tuple: &String, contents: &String } => { |
| 3660 | s.emit_u8(1); |
| 3661 | s.emit_str(tuple); |
| 3662 | s.emit_str(contents); |
| 3663 | } |
| 3664 | } |
| 3665 | } |
| 3666 | } |
| 3667 | |
| 3668 | impl<D: Decoder> Decodable<D> for TargetTuple { |
| 3669 | fn decode(d: &mut D) -> Self { |
| 3670 | match d.read_u8() { |
| 3671 | 0 => TargetTuple::TargetTuple(d.read_str().to_owned()), |
| 3672 | 1 => TargetTuple::TargetJson { |
| 3673 | path_for_rustdoc: PathBuf::new(), |
| 3674 | tuple: d.read_str().to_owned(), |
| 3675 | contents: d.read_str().to_owned(), |
| 3676 | }, |
| 3677 | _ => { |
| 3678 | panic!("invalid enum variant tag while decoding `TargetTuple`, expected 0..2" ); |
| 3679 | } |
| 3680 | } |
| 3681 | } |
| 3682 | } |
| 3683 | |
| 3684 | impl TargetTuple { |
| 3685 | /// Creates a target tuple from the passed target tuple string. |
| 3686 | pub fn from_tuple(tuple: &str) -> Self { |
| 3687 | TargetTuple::TargetTuple(tuple.into()) |
| 3688 | } |
| 3689 | |
| 3690 | /// Creates a target tuple from the passed target path. |
| 3691 | pub fn from_path(path: &Path) -> Result<Self, io::Error> { |
| 3692 | let canonicalized_path = try_canonicalize(path)?; |
| 3693 | let contents = std::fs::read_to_string(&canonicalized_path).map_err(|err| { |
| 3694 | io::Error::new( |
| 3695 | io::ErrorKind::InvalidInput, |
| 3696 | format!("target path {canonicalized_path:?} is not a valid file: {err}" ), |
| 3697 | ) |
| 3698 | })?; |
| 3699 | let tuple = canonicalized_path |
| 3700 | .file_stem() |
| 3701 | .expect("target path must not be empty" ) |
| 3702 | .to_str() |
| 3703 | .expect("target path must be valid unicode" ) |
| 3704 | .to_owned(); |
| 3705 | Ok(TargetTuple::TargetJson { path_for_rustdoc: canonicalized_path, tuple, contents }) |
| 3706 | } |
| 3707 | |
| 3708 | /// Returns a string tuple for this target. |
| 3709 | /// |
| 3710 | /// If this target is a path, the file name (without extension) is returned. |
| 3711 | pub fn tuple(&self) -> &str { |
| 3712 | match *self { |
| 3713 | TargetTuple::TargetTuple(ref tuple) | TargetTuple::TargetJson { ref tuple, .. } => { |
| 3714 | tuple |
| 3715 | } |
| 3716 | } |
| 3717 | } |
| 3718 | |
| 3719 | /// Returns an extended string tuple for this target. |
| 3720 | /// |
| 3721 | /// If this target is a path, a hash of the path is appended to the tuple returned |
| 3722 | /// by `tuple()`. |
| 3723 | pub fn debug_tuple(&self) -> String { |
| 3724 | use std::hash::DefaultHasher; |
| 3725 | |
| 3726 | match self { |
| 3727 | TargetTuple::TargetTuple(tuple) => tuple.to_owned(), |
| 3728 | TargetTuple::TargetJson { path_for_rustdoc: _, tuple, contents: content } => { |
| 3729 | let mut hasher = DefaultHasher::new(); |
| 3730 | content.hash(&mut hasher); |
| 3731 | let hash = hasher.finish(); |
| 3732 | format!(" {tuple}- {hash}" ) |
| 3733 | } |
| 3734 | } |
| 3735 | } |
| 3736 | } |
| 3737 | |
| 3738 | impl fmt::Display for TargetTuple { |
| 3739 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 3740 | write!(f, " {}" , self.debug_tuple()) |
| 3741 | } |
| 3742 | } |
| 3743 | |