rustc_target/spec/
mod.rs

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