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