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 triples 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 triple, as passed via `rustc --target=TRIPLE`, 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 `TRIPLE` is not one of the built-in
15 //! targets, rustc will check if a file named `TRIPLE` 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 `TRIPLE.json`. The first one found will
19 //! be loaded. If no file is found in any of those directories, a fatal error
20 //! will be given.
21 //!
22 //! Projects defining their own targets should use
23 //! `--target=path/to/my-awesome-platform.json` instead of adding to
24 //! `RUST_TARGET_PATH`.
25 //!
26 //! # Defining a new target
27 //!
28 //! Targets are defined using [JSON](https://json.org/). The `Target` struct in
29 //! this module defines the format the JSON file should take, though each
30 //! underscore in the field names should be replaced with a hyphen (`-`) in the
31 //! JSON file. Some fields are required in every target specification, such as
32 //! `llvm-target`, `target-endian`, `target-pointer-width`, `data-layout`,
33 //! `arch`, and `os`. In general, options passed to rustc with `-C` override
34 //! the target's settings, though `target-feature` and `link-args` will *add*
35 //! to the list specified by the target, rather than replace.
36
37 use crate::abi::call::Conv;
38 use crate::abi::{Endian, Integer, Size, TargetDataLayout, TargetDataLayoutErrors};
39 use crate::json::{Json, ToJson};
40 use crate::spec::abi::{lookup as lookup_abi, Abi};
41 use crate::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault};
42 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
43 use rustc_fs_util::try_canonicalize;
44 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
45 use rustc_span::symbol::{sym, Symbol};
46 use serde_json::Value;
47 use std::borrow::Cow;
48 use std::collections::BTreeMap;
49 use std::hash::{Hash, Hasher};
50 use std::ops::{Deref, DerefMut};
51 use std::path::{Path, PathBuf};
52 use std::str::FromStr;
53 use std::{fmt, io};
54
55 use rustc_macros::HashStable_Generic;
56
57 pub mod abi;
58 pub mod crt_objects;
59
60 mod aix_base;
61 mod android_base;
62 mod apple_base;
63 pub use apple_base::deployment_target as current_apple_deployment_target;
64 mod avr_gnu_base;
65 pub use avr_gnu_base::ef_avr_arch;
66 mod bpf_base;
67 mod dragonfly_base;
68 mod freebsd_base;
69 mod fuchsia_base;
70 mod haiku_base;
71 mod hermit_base;
72 mod illumos_base;
73 mod l4re_base;
74 mod linux_base;
75 mod linux_gnu_base;
76 mod linux_musl_base;
77 mod linux_uclibc_base;
78 mod msvc_base;
79 mod netbsd_base;
80 mod nto_qnx_base;
81 mod openbsd_base;
82 mod redox_base;
83 mod solaris_base;
84 mod solid_base;
85 mod thumb_base;
86 mod uefi_msvc_base;
87 mod vxworks_base;
88 mod wasm_base;
89 mod windows_gnu_base;
90 mod windows_gnullvm_base;
91 mod windows_msvc_base;
92 mod windows_uwp_gnu_base;
93 mod windows_uwp_msvc_base;
94
95 /// Linker is called through a C/C++ compiler.
96 #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
97 pub enum Cc {
98 Yes,
99 No,
100 }
101
102 /// Linker is LLD.
103 #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
104 pub enum Lld {
105 Yes,
106 No,
107 }
108
109 /// All linkers have some kinds of command line interfaces and rustc needs to know which commands
110 /// to use with each of them. So we cluster all such interfaces into a (somewhat arbitrary) number
111 /// of classes that we call "linker flavors".
112 ///
113 /// Technically, it's not even necessary, we can nearly always infer the flavor from linker name
114 /// and target properties like `is_like_windows`/`is_like_osx`/etc. However, the PRs originally
115 /// introducing `-Clinker-flavor` (#40018 and friends) were aiming to reduce this kind of inference
116 /// and provide something certain and explicitly specified instead, and that design goal is still
117 /// relevant now.
118 ///
119 /// The second goal is to keep the number of flavors to the minimum if possible.
120 /// LLD somewhat forces our hand here because that linker is self-sufficient only if its executable
121 /// (`argv[0]`) is named in specific way, otherwise it doesn't work and requires a
122 /// `-flavor LLD_FLAVOR` argument to choose which logic to use. Our shipped `rust-lld` in
123 /// particular is not named in such specific way, so it needs the flavor option, so we make our
124 /// linker flavors sufficiently fine-grained to satisfy LLD without inferring its flavor from other
125 /// target properties, in accordance with the first design goal.
126 ///
127 /// The first component of the flavor is tightly coupled with the compilation target,
128 /// while the `Cc` and `Lld` flags can vary within the same target.
129 #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
130 pub enum LinkerFlavor {
131 /// Unix-like linker with GNU extensions (both naked and compiler-wrapped forms).
132 /// Besides similar "default" Linux/BSD linkers this also includes Windows/GNU linker,
133 /// which is somewhat different because it doesn't produce ELFs.
134 Gnu(Cc, Lld),
135 /// Unix-like linker for Apple targets (both naked and compiler-wrapped forms).
136 /// Extracted from the "umbrella" `Unix` flavor due to its corresponding LLD flavor.
137 Darwin(Cc, Lld),
138 /// Unix-like linker for Wasm targets (both naked and compiler-wrapped forms).
139 /// Extracted from the "umbrella" `Unix` flavor due to its corresponding LLD flavor.
140 /// Non-LLD version does not exist, so the lld flag is currently hardcoded here.
141 WasmLld(Cc),
142 /// Basic Unix-like linker for "any other Unix" targets (Solaris/illumos, L4Re, MSP430, etc),
143 /// possibly with non-GNU extensions (both naked and compiler-wrapped forms).
144 /// LLD doesn't support any of these.
145 Unix(Cc),
146 /// MSVC-style linker for Windows and UEFI, LLD supports it.
147 Msvc(Lld),
148 /// Emscripten Compiler Frontend, a wrapper around `WasmLld(Cc::Yes)` that has a different
149 /// interface and produces some additional JavaScript output.
150 EmCc,
151 // Below: other linker-like tools with unique interfaces for exotic targets.
152 /// Linker tool for BPF.
153 Bpf,
154 /// Linker tool for Nvidia PTX.
155 Ptx,
156 }
157
158 /// Linker flavors available externally through command line (`-Clinker-flavor`)
159 /// or json target specifications.
160 /// FIXME: This set has accumulated historically, bring it more in line with the internal
161 /// linker flavors (`LinkerFlavor`).
162 #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
163 pub enum LinkerFlavorCli {
164 // New (unstable) flavors, with direct counterparts in `LinkerFlavor`.
165 Gnu(Cc, Lld),
166 Darwin(Cc, Lld),
167 WasmLld(Cc),
168 Unix(Cc),
169 // Note: `Msvc(Lld::No)` is also a stable value.
170 Msvc(Lld),
171 EmCc,
172 Bpf,
173 Ptx,
174
175 // Below: the legacy stable values.
176 Gcc,
177 Ld,
178 Lld(LldFlavor),
179 Em,
180 BpfLinker,
181 PtxLinker,
182 }
183
184 impl LinkerFlavorCli {
185 /// Returns whether this `-C linker-flavor` option is one of the unstable values.
is_unstable(&self) -> bool186 pub fn is_unstable(&self) -> bool {
187 match self {
188 LinkerFlavorCli::Gnu(..)
189 | LinkerFlavorCli::Darwin(..)
190 | LinkerFlavorCli::WasmLld(..)
191 | LinkerFlavorCli::Unix(..)
192 | LinkerFlavorCli::Msvc(Lld::Yes)
193 | LinkerFlavorCli::EmCc
194 | LinkerFlavorCli::Bpf
195 | LinkerFlavorCli::Ptx
196 | LinkerFlavorCli::BpfLinker
197 | LinkerFlavorCli::PtxLinker => true,
198 LinkerFlavorCli::Gcc
199 | LinkerFlavorCli::Ld
200 | LinkerFlavorCli::Lld(..)
201 | LinkerFlavorCli::Msvc(Lld::No)
202 | LinkerFlavorCli::Em => false,
203 }
204 }
205 }
206
207 #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
208 pub enum LldFlavor {
209 Wasm,
210 Ld64,
211 Ld,
212 Link,
213 }
214
215 impl LldFlavor {
as_str(&self) -> &'static str216 pub fn as_str(&self) -> &'static str {
217 match self {
218 LldFlavor::Wasm => "wasm",
219 LldFlavor::Ld64 => "darwin",
220 LldFlavor::Ld => "gnu",
221 LldFlavor::Link => "link",
222 }
223 }
224
from_str(s: &str) -> Option<Self>225 fn from_str(s: &str) -> Option<Self> {
226 Some(match s {
227 "darwin" => LldFlavor::Ld64,
228 "gnu" => LldFlavor::Ld,
229 "link" => LldFlavor::Link,
230 "wasm" => LldFlavor::Wasm,
231 _ => return None,
232 })
233 }
234 }
235
236 impl ToJson for LldFlavor {
to_json(&self) -> Json237 fn to_json(&self) -> Json {
238 self.as_str().to_json()
239 }
240 }
241
242 impl LinkerFlavor {
243 /// At this point the target's reference linker flavor doesn't yet exist and we need to infer
244 /// it. The inference always succeds and gives some result, and we don't report any flavor
245 /// incompatibility errors for json target specs. The CLI flavor is used as the main source
246 /// of truth, other flags are used in case of ambiguities.
from_cli_json(cli: LinkerFlavorCli, lld_flavor: LldFlavor, is_gnu: bool) -> LinkerFlavor247 fn from_cli_json(cli: LinkerFlavorCli, lld_flavor: LldFlavor, is_gnu: bool) -> LinkerFlavor {
248 match cli {
249 LinkerFlavorCli::Gnu(cc, lld) => LinkerFlavor::Gnu(cc, lld),
250 LinkerFlavorCli::Darwin(cc, lld) => LinkerFlavor::Darwin(cc, lld),
251 LinkerFlavorCli::WasmLld(cc) => LinkerFlavor::WasmLld(cc),
252 LinkerFlavorCli::Unix(cc) => LinkerFlavor::Unix(cc),
253 LinkerFlavorCli::Msvc(lld) => LinkerFlavor::Msvc(lld),
254 LinkerFlavorCli::EmCc => LinkerFlavor::EmCc,
255 LinkerFlavorCli::Bpf => LinkerFlavor::Bpf,
256 LinkerFlavorCli::Ptx => LinkerFlavor::Ptx,
257
258 // Below: legacy stable values
259 LinkerFlavorCli::Gcc => match lld_flavor {
260 LldFlavor::Ld if is_gnu => LinkerFlavor::Gnu(Cc::Yes, Lld::No),
261 LldFlavor::Ld64 => LinkerFlavor::Darwin(Cc::Yes, Lld::No),
262 LldFlavor::Wasm => LinkerFlavor::WasmLld(Cc::Yes),
263 LldFlavor::Ld | LldFlavor::Link => LinkerFlavor::Unix(Cc::Yes),
264 },
265 LinkerFlavorCli::Ld => match lld_flavor {
266 LldFlavor::Ld if is_gnu => LinkerFlavor::Gnu(Cc::No, Lld::No),
267 LldFlavor::Ld64 => LinkerFlavor::Darwin(Cc::No, Lld::No),
268 LldFlavor::Ld | LldFlavor::Wasm | LldFlavor::Link => LinkerFlavor::Unix(Cc::No),
269 },
270 LinkerFlavorCli::Lld(LldFlavor::Ld) => LinkerFlavor::Gnu(Cc::No, Lld::Yes),
271 LinkerFlavorCli::Lld(LldFlavor::Ld64) => LinkerFlavor::Darwin(Cc::No, Lld::Yes),
272 LinkerFlavorCli::Lld(LldFlavor::Wasm) => LinkerFlavor::WasmLld(Cc::No),
273 LinkerFlavorCli::Lld(LldFlavor::Link) => LinkerFlavor::Msvc(Lld::Yes),
274 LinkerFlavorCli::Em => LinkerFlavor::EmCc,
275 LinkerFlavorCli::BpfLinker => LinkerFlavor::Bpf,
276 LinkerFlavorCli::PtxLinker => LinkerFlavor::Ptx,
277 }
278 }
279
to_cli(self) -> LinkerFlavorCli280 fn to_cli(self) -> LinkerFlavorCli {
281 match self {
282 LinkerFlavor::Gnu(Cc::Yes, _)
283 | LinkerFlavor::Darwin(Cc::Yes, _)
284 | LinkerFlavor::WasmLld(Cc::Yes)
285 | LinkerFlavor::Unix(Cc::Yes) => LinkerFlavorCli::Gcc,
286 LinkerFlavor::Gnu(_, Lld::Yes) => LinkerFlavorCli::Lld(LldFlavor::Ld),
287 LinkerFlavor::Darwin(_, Lld::Yes) => LinkerFlavorCli::Lld(LldFlavor::Ld64),
288 LinkerFlavor::WasmLld(..) => LinkerFlavorCli::Lld(LldFlavor::Wasm),
289 LinkerFlavor::Gnu(..) | LinkerFlavor::Darwin(..) | LinkerFlavor::Unix(..) => {
290 LinkerFlavorCli::Ld
291 }
292 LinkerFlavor::Msvc(Lld::Yes) => LinkerFlavorCli::Lld(LldFlavor::Link),
293 LinkerFlavor::Msvc(..) => LinkerFlavorCli::Msvc(Lld::No),
294 LinkerFlavor::EmCc => LinkerFlavorCli::Em,
295 LinkerFlavor::Bpf => LinkerFlavorCli::BpfLinker,
296 LinkerFlavor::Ptx => LinkerFlavorCli::PtxLinker,
297 }
298 }
299
infer_cli_hints(cli: LinkerFlavorCli) -> (Option<Cc>, Option<Lld>)300 fn infer_cli_hints(cli: LinkerFlavorCli) -> (Option<Cc>, Option<Lld>) {
301 match cli {
302 LinkerFlavorCli::Gnu(cc, lld) | LinkerFlavorCli::Darwin(cc, lld) => {
303 (Some(cc), Some(lld))
304 }
305 LinkerFlavorCli::WasmLld(cc) => (Some(cc), Some(Lld::Yes)),
306 LinkerFlavorCli::Unix(cc) => (Some(cc), None),
307 LinkerFlavorCli::Msvc(lld) => (Some(Cc::No), Some(lld)),
308 LinkerFlavorCli::EmCc => (Some(Cc::Yes), Some(Lld::Yes)),
309 LinkerFlavorCli::Bpf | LinkerFlavorCli::Ptx => (None, None),
310
311 // Below: legacy stable values
312 LinkerFlavorCli::Gcc => (Some(Cc::Yes), None),
313 LinkerFlavorCli::Ld => (Some(Cc::No), Some(Lld::No)),
314 LinkerFlavorCli::Lld(_) => (Some(Cc::No), Some(Lld::Yes)),
315 LinkerFlavorCli::Em => (Some(Cc::Yes), Some(Lld::Yes)),
316 LinkerFlavorCli::BpfLinker | LinkerFlavorCli::PtxLinker => (None, None),
317 }
318 }
319
infer_linker_hints(linker_stem: &str) -> (Option<Cc>, Option<Lld>)320 fn infer_linker_hints(linker_stem: &str) -> (Option<Cc>, Option<Lld>) {
321 // Remove any version postfix.
322 let stem = linker_stem
323 .rsplit_once('-')
324 .and_then(|(lhs, rhs)| rhs.chars().all(char::is_numeric).then_some(lhs))
325 .unwrap_or(linker_stem);
326
327 // GCC/Clang can have an optional target prefix.
328 if stem == "emcc"
329 || stem == "gcc"
330 || stem.ends_with("-gcc")
331 || stem == "g++"
332 || stem.ends_with("-g++")
333 || stem == "clang"
334 || stem.ends_with("-clang")
335 || stem == "clang++"
336 || stem.ends_with("-clang++")
337 {
338 (Some(Cc::Yes), None)
339 } else if stem == "wasm-ld"
340 || stem.ends_with("-wasm-ld")
341 || stem == "ld.lld"
342 || stem == "lld"
343 || stem == "rust-lld"
344 || stem == "lld-link"
345 {
346 (Some(Cc::No), Some(Lld::Yes))
347 } else if stem == "ld" || stem.ends_with("-ld") || stem == "link" {
348 (Some(Cc::No), Some(Lld::No))
349 } else {
350 (None, None)
351 }
352 }
353
with_hints(self, (cc_hint, lld_hint): (Option<Cc>, Option<Lld>)) -> LinkerFlavor354 fn with_hints(self, (cc_hint, lld_hint): (Option<Cc>, Option<Lld>)) -> LinkerFlavor {
355 match self {
356 LinkerFlavor::Gnu(cc, lld) => {
357 LinkerFlavor::Gnu(cc_hint.unwrap_or(cc), lld_hint.unwrap_or(lld))
358 }
359 LinkerFlavor::Darwin(cc, lld) => {
360 LinkerFlavor::Darwin(cc_hint.unwrap_or(cc), lld_hint.unwrap_or(lld))
361 }
362 LinkerFlavor::WasmLld(cc) => LinkerFlavor::WasmLld(cc_hint.unwrap_or(cc)),
363 LinkerFlavor::Unix(cc) => LinkerFlavor::Unix(cc_hint.unwrap_or(cc)),
364 LinkerFlavor::Msvc(lld) => LinkerFlavor::Msvc(lld_hint.unwrap_or(lld)),
365 LinkerFlavor::EmCc | LinkerFlavor::Bpf | LinkerFlavor::Ptx => self,
366 }
367 }
368
with_cli_hints(self, cli: LinkerFlavorCli) -> LinkerFlavor369 pub fn with_cli_hints(self, cli: LinkerFlavorCli) -> LinkerFlavor {
370 self.with_hints(LinkerFlavor::infer_cli_hints(cli))
371 }
372
with_linker_hints(self, linker_stem: &str) -> LinkerFlavor373 pub fn with_linker_hints(self, linker_stem: &str) -> LinkerFlavor {
374 self.with_hints(LinkerFlavor::infer_linker_hints(linker_stem))
375 }
376
check_compatibility(self, cli: LinkerFlavorCli) -> Option<String>377 pub fn check_compatibility(self, cli: LinkerFlavorCli) -> Option<String> {
378 let compatible = |cli| {
379 // The CLI flavor should be compatible with the target if:
380 // 1. they are counterparts: they have the same principal flavor.
381 match (self, cli) {
382 (LinkerFlavor::Gnu(..), LinkerFlavorCli::Gnu(..))
383 | (LinkerFlavor::Darwin(..), LinkerFlavorCli::Darwin(..))
384 | (LinkerFlavor::WasmLld(..), LinkerFlavorCli::WasmLld(..))
385 | (LinkerFlavor::Unix(..), LinkerFlavorCli::Unix(..))
386 | (LinkerFlavor::Msvc(..), LinkerFlavorCli::Msvc(..))
387 | (LinkerFlavor::EmCc, LinkerFlavorCli::EmCc)
388 | (LinkerFlavor::Bpf, LinkerFlavorCli::Bpf)
389 | (LinkerFlavor::Ptx, LinkerFlavorCli::Ptx) => return true,
390 _ => {}
391 }
392
393 // 2. or, the flavor is legacy and survives this roundtrip.
394 cli == self.with_cli_hints(cli).to_cli()
395 };
396 (!compatible(cli)).then(|| {
397 LinkerFlavorCli::all()
398 .iter()
399 .filter(|cli| compatible(**cli))
400 .map(|cli| cli.desc())
401 .intersperse(", ")
402 .collect()
403 })
404 }
405
lld_flavor(self) -> LldFlavor406 pub fn lld_flavor(self) -> LldFlavor {
407 match self {
408 LinkerFlavor::Gnu(..)
409 | LinkerFlavor::Unix(..)
410 | LinkerFlavor::EmCc
411 | LinkerFlavor::Bpf
412 | LinkerFlavor::Ptx => LldFlavor::Ld,
413 LinkerFlavor::Darwin(..) => LldFlavor::Ld64,
414 LinkerFlavor::WasmLld(..) => LldFlavor::Wasm,
415 LinkerFlavor::Msvc(..) => LldFlavor::Link,
416 }
417 }
418
is_gnu(self) -> bool419 pub fn is_gnu(self) -> bool {
420 matches!(self, LinkerFlavor::Gnu(..))
421 }
422
423 /// Returns whether the flavor uses the `lld` linker.
uses_lld(self) -> bool424 pub fn uses_lld(self) -> bool {
425 // Exhaustive match in case new flavors are added in the future.
426 match self {
427 LinkerFlavor::Gnu(_, Lld::Yes)
428 | LinkerFlavor::Darwin(_, Lld::Yes)
429 | LinkerFlavor::WasmLld(..)
430 | LinkerFlavor::EmCc
431 | LinkerFlavor::Msvc(Lld::Yes) => true,
432 LinkerFlavor::Gnu(..)
433 | LinkerFlavor::Darwin(..)
434 | LinkerFlavor::Msvc(_)
435 | LinkerFlavor::Unix(_)
436 | LinkerFlavor::Bpf
437 | LinkerFlavor::Ptx => false,
438 }
439 }
440
441 /// Returns whether the flavor calls the linker via a C/C++ compiler.
uses_cc(self) -> bool442 pub fn uses_cc(self) -> bool {
443 // Exhaustive match in case new flavors are added in the future.
444 match self {
445 LinkerFlavor::Gnu(Cc::Yes, _)
446 | LinkerFlavor::Darwin(Cc::Yes, _)
447 | LinkerFlavor::WasmLld(Cc::Yes)
448 | LinkerFlavor::Unix(Cc::Yes)
449 | LinkerFlavor::EmCc => true,
450 LinkerFlavor::Gnu(..)
451 | LinkerFlavor::Darwin(..)
452 | LinkerFlavor::WasmLld(_)
453 | LinkerFlavor::Msvc(_)
454 | LinkerFlavor::Unix(_)
455 | LinkerFlavor::Bpf
456 | LinkerFlavor::Ptx => false,
457 }
458 }
459 }
460
461 macro_rules! linker_flavor_cli_impls {
462 ($(($($flavor:tt)*) $string:literal)*) => (
463 impl LinkerFlavorCli {
464 const fn all() -> &'static [LinkerFlavorCli] {
465 &[$($($flavor)*,)*]
466 }
467
468 pub const fn one_of() -> &'static str {
469 concat!("one of: ", $($string, " ",)*)
470 }
471
472 pub fn from_str(s: &str) -> Option<LinkerFlavorCli> {
473 Some(match s {
474 $($string => $($flavor)*,)*
475 _ => return None,
476 })
477 }
478
479 pub fn desc(self) -> &'static str {
480 match self {
481 $($($flavor)* => $string,)*
482 }
483 }
484 }
485 )
486 }
487
488 linker_flavor_cli_impls! {
489 (LinkerFlavorCli::Gnu(Cc::No, Lld::No)) "gnu"
490 (LinkerFlavorCli::Gnu(Cc::No, Lld::Yes)) "gnu-lld"
491 (LinkerFlavorCli::Gnu(Cc::Yes, Lld::No)) "gnu-cc"
492 (LinkerFlavorCli::Gnu(Cc::Yes, Lld::Yes)) "gnu-lld-cc"
493 (LinkerFlavorCli::Darwin(Cc::No, Lld::No)) "darwin"
494 (LinkerFlavorCli::Darwin(Cc::No, Lld::Yes)) "darwin-lld"
495 (LinkerFlavorCli::Darwin(Cc::Yes, Lld::No)) "darwin-cc"
496 (LinkerFlavorCli::Darwin(Cc::Yes, Lld::Yes)) "darwin-lld-cc"
497 (LinkerFlavorCli::WasmLld(Cc::No)) "wasm-lld"
498 (LinkerFlavorCli::WasmLld(Cc::Yes)) "wasm-lld-cc"
499 (LinkerFlavorCli::Unix(Cc::No)) "unix"
500 (LinkerFlavorCli::Unix(Cc::Yes)) "unix-cc"
501 (LinkerFlavorCli::Msvc(Lld::Yes)) "msvc-lld"
502 (LinkerFlavorCli::Msvc(Lld::No)) "msvc"
503 (LinkerFlavorCli::EmCc) "em-cc"
504 (LinkerFlavorCli::Bpf) "bpf"
505 (LinkerFlavorCli::Ptx) "ptx"
506
507 // Below: legacy stable values
508 (LinkerFlavorCli::Gcc) "gcc"
509 (LinkerFlavorCli::Ld) "ld"
510 (LinkerFlavorCli::Lld(LldFlavor::Ld)) "ld.lld"
511 (LinkerFlavorCli::Lld(LldFlavor::Ld64)) "ld64.lld"
512 (LinkerFlavorCli::Lld(LldFlavor::Link)) "lld-link"
513 (LinkerFlavorCli::Lld(LldFlavor::Wasm)) "wasm-ld"
514 (LinkerFlavorCli::Em) "em"
515 (LinkerFlavorCli::BpfLinker) "bpf-linker"
516 (LinkerFlavorCli::PtxLinker) "ptx-linker"
517 }
518
519 impl ToJson for LinkerFlavorCli {
to_json(&self) -> Json520 fn to_json(&self) -> Json {
521 self.desc().to_json()
522 }
523 }
524
525 #[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable, HashStable_Generic)]
526 pub enum PanicStrategy {
527 Unwind,
528 Abort,
529 }
530
531 impl PanicStrategy {
desc(&self) -> &str532 pub fn desc(&self) -> &str {
533 match *self {
534 PanicStrategy::Unwind => "unwind",
535 PanicStrategy::Abort => "abort",
536 }
537 }
538
desc_symbol(&self) -> Symbol539 pub const fn desc_symbol(&self) -> Symbol {
540 match *self {
541 PanicStrategy::Unwind => sym::unwind,
542 PanicStrategy::Abort => sym::abort,
543 }
544 }
545
all() -> [Symbol; 2]546 pub const fn all() -> [Symbol; 2] {
547 [Self::Abort.desc_symbol(), Self::Unwind.desc_symbol()]
548 }
549 }
550
551 impl ToJson for PanicStrategy {
to_json(&self) -> Json552 fn to_json(&self) -> Json {
553 match *self {
554 PanicStrategy::Abort => "abort".to_json(),
555 PanicStrategy::Unwind => "unwind".to_json(),
556 }
557 }
558 }
559
560 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
561 pub enum RelroLevel {
562 Full,
563 Partial,
564 Off,
565 None,
566 }
567
568 impl RelroLevel {
desc(&self) -> &str569 pub fn desc(&self) -> &str {
570 match *self {
571 RelroLevel::Full => "full",
572 RelroLevel::Partial => "partial",
573 RelroLevel::Off => "off",
574 RelroLevel::None => "none",
575 }
576 }
577 }
578
579 impl FromStr for RelroLevel {
580 type Err = ();
581
from_str(s: &str) -> Result<RelroLevel, ()>582 fn from_str(s: &str) -> Result<RelroLevel, ()> {
583 match s {
584 "full" => Ok(RelroLevel::Full),
585 "partial" => Ok(RelroLevel::Partial),
586 "off" => Ok(RelroLevel::Off),
587 "none" => Ok(RelroLevel::None),
588 _ => Err(()),
589 }
590 }
591 }
592
593 impl ToJson for RelroLevel {
to_json(&self) -> Json594 fn to_json(&self) -> Json {
595 match *self {
596 RelroLevel::Full => "full".to_json(),
597 RelroLevel::Partial => "partial".to_json(),
598 RelroLevel::Off => "off".to_json(),
599 RelroLevel::None => "None".to_json(),
600 }
601 }
602 }
603
604 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
605 pub enum MergeFunctions {
606 Disabled,
607 Trampolines,
608 Aliases,
609 }
610
611 impl MergeFunctions {
desc(&self) -> &str612 pub fn desc(&self) -> &str {
613 match *self {
614 MergeFunctions::Disabled => "disabled",
615 MergeFunctions::Trampolines => "trampolines",
616 MergeFunctions::Aliases => "aliases",
617 }
618 }
619 }
620
621 impl FromStr for MergeFunctions {
622 type Err = ();
623
from_str(s: &str) -> Result<MergeFunctions, ()>624 fn from_str(s: &str) -> Result<MergeFunctions, ()> {
625 match s {
626 "disabled" => Ok(MergeFunctions::Disabled),
627 "trampolines" => Ok(MergeFunctions::Trampolines),
628 "aliases" => Ok(MergeFunctions::Aliases),
629 _ => Err(()),
630 }
631 }
632 }
633
634 impl ToJson for MergeFunctions {
to_json(&self) -> Json635 fn to_json(&self) -> Json {
636 match *self {
637 MergeFunctions::Disabled => "disabled".to_json(),
638 MergeFunctions::Trampolines => "trampolines".to_json(),
639 MergeFunctions::Aliases => "aliases".to_json(),
640 }
641 }
642 }
643
644 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
645 pub enum RelocModel {
646 Static,
647 Pic,
648 Pie,
649 DynamicNoPic,
650 Ropi,
651 Rwpi,
652 RopiRwpi,
653 }
654
655 impl FromStr for RelocModel {
656 type Err = ();
657
from_str(s: &str) -> Result<RelocModel, ()>658 fn from_str(s: &str) -> Result<RelocModel, ()> {
659 Ok(match s {
660 "static" => RelocModel::Static,
661 "pic" => RelocModel::Pic,
662 "pie" => RelocModel::Pie,
663 "dynamic-no-pic" => RelocModel::DynamicNoPic,
664 "ropi" => RelocModel::Ropi,
665 "rwpi" => RelocModel::Rwpi,
666 "ropi-rwpi" => RelocModel::RopiRwpi,
667 _ => return Err(()),
668 })
669 }
670 }
671
672 impl ToJson for RelocModel {
to_json(&self) -> Json673 fn to_json(&self) -> Json {
674 match *self {
675 RelocModel::Static => "static",
676 RelocModel::Pic => "pic",
677 RelocModel::Pie => "pie",
678 RelocModel::DynamicNoPic => "dynamic-no-pic",
679 RelocModel::Ropi => "ropi",
680 RelocModel::Rwpi => "rwpi",
681 RelocModel::RopiRwpi => "ropi-rwpi",
682 }
683 .to_json()
684 }
685 }
686
687 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
688 pub enum CodeModel {
689 Tiny,
690 Small,
691 Kernel,
692 Medium,
693 Large,
694 }
695
696 impl FromStr for CodeModel {
697 type Err = ();
698
from_str(s: &str) -> Result<CodeModel, ()>699 fn from_str(s: &str) -> Result<CodeModel, ()> {
700 Ok(match s {
701 "tiny" => CodeModel::Tiny,
702 "small" => CodeModel::Small,
703 "kernel" => CodeModel::Kernel,
704 "medium" => CodeModel::Medium,
705 "large" => CodeModel::Large,
706 _ => return Err(()),
707 })
708 }
709 }
710
711 impl ToJson for CodeModel {
to_json(&self) -> Json712 fn to_json(&self) -> Json {
713 match *self {
714 CodeModel::Tiny => "tiny",
715 CodeModel::Small => "small",
716 CodeModel::Kernel => "kernel",
717 CodeModel::Medium => "medium",
718 CodeModel::Large => "large",
719 }
720 .to_json()
721 }
722 }
723
724 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
725 pub enum TlsModel {
726 GeneralDynamic,
727 LocalDynamic,
728 InitialExec,
729 LocalExec,
730 }
731
732 impl FromStr for TlsModel {
733 type Err = ();
734
from_str(s: &str) -> Result<TlsModel, ()>735 fn from_str(s: &str) -> Result<TlsModel, ()> {
736 Ok(match s {
737 // Note the difference "general" vs "global" difference. The model name is "general",
738 // but the user-facing option name is "global" for consistency with other compilers.
739 "global-dynamic" => TlsModel::GeneralDynamic,
740 "local-dynamic" => TlsModel::LocalDynamic,
741 "initial-exec" => TlsModel::InitialExec,
742 "local-exec" => TlsModel::LocalExec,
743 _ => return Err(()),
744 })
745 }
746 }
747
748 impl ToJson for TlsModel {
to_json(&self) -> Json749 fn to_json(&self) -> Json {
750 match *self {
751 TlsModel::GeneralDynamic => "global-dynamic",
752 TlsModel::LocalDynamic => "local-dynamic",
753 TlsModel::InitialExec => "initial-exec",
754 TlsModel::LocalExec => "local-exec",
755 }
756 .to_json()
757 }
758 }
759
760 /// Everything is flattened to a single enum to make the json encoding/decoding less annoying.
761 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
762 pub enum LinkOutputKind {
763 /// Dynamically linked non position-independent executable.
764 DynamicNoPicExe,
765 /// Dynamically linked position-independent executable.
766 DynamicPicExe,
767 /// Statically linked non position-independent executable.
768 StaticNoPicExe,
769 /// Statically linked position-independent executable.
770 StaticPicExe,
771 /// Regular dynamic library ("dynamically linked").
772 DynamicDylib,
773 /// Dynamic library with bundled libc ("statically linked").
774 StaticDylib,
775 /// WASI module with a lifetime past the _initialize entry point
776 WasiReactorExe,
777 }
778
779 impl LinkOutputKind {
as_str(&self) -> &'static str780 fn as_str(&self) -> &'static str {
781 match self {
782 LinkOutputKind::DynamicNoPicExe => "dynamic-nopic-exe",
783 LinkOutputKind::DynamicPicExe => "dynamic-pic-exe",
784 LinkOutputKind::StaticNoPicExe => "static-nopic-exe",
785 LinkOutputKind::StaticPicExe => "static-pic-exe",
786 LinkOutputKind::DynamicDylib => "dynamic-dylib",
787 LinkOutputKind::StaticDylib => "static-dylib",
788 LinkOutputKind::WasiReactorExe => "wasi-reactor-exe",
789 }
790 }
791
from_str(s: &str) -> Option<LinkOutputKind>792 pub(super) fn from_str(s: &str) -> Option<LinkOutputKind> {
793 Some(match s {
794 "dynamic-nopic-exe" => LinkOutputKind::DynamicNoPicExe,
795 "dynamic-pic-exe" => LinkOutputKind::DynamicPicExe,
796 "static-nopic-exe" => LinkOutputKind::StaticNoPicExe,
797 "static-pic-exe" => LinkOutputKind::StaticPicExe,
798 "dynamic-dylib" => LinkOutputKind::DynamicDylib,
799 "static-dylib" => LinkOutputKind::StaticDylib,
800 "wasi-reactor-exe" => LinkOutputKind::WasiReactorExe,
801 _ => return None,
802 })
803 }
804
can_link_dylib(self) -> bool805 pub fn can_link_dylib(self) -> bool {
806 match self {
807 LinkOutputKind::StaticNoPicExe | LinkOutputKind::StaticPicExe => false,
808 LinkOutputKind::DynamicNoPicExe
809 | LinkOutputKind::DynamicPicExe
810 | LinkOutputKind::DynamicDylib
811 | LinkOutputKind::StaticDylib
812 | LinkOutputKind::WasiReactorExe => true,
813 }
814 }
815 }
816
817 impl fmt::Display for LinkOutputKind {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result818 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
819 f.write_str(self.as_str())
820 }
821 }
822
823 pub type LinkArgs = BTreeMap<LinkerFlavor, Vec<StaticCow<str>>>;
824 pub type LinkArgsCli = BTreeMap<LinkerFlavorCli, Vec<StaticCow<str>>>;
825
826 /// Which kind of debuginfo does the target use?
827 ///
828 /// Useful in determining whether a target supports Split DWARF (a target with
829 /// `DebuginfoKind::Dwarf` and supporting `SplitDebuginfo::Unpacked` for example).
830 #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
831 pub enum DebuginfoKind {
832 /// DWARF debuginfo (such as that used on `x86_64_unknown_linux_gnu`).
833 #[default]
834 Dwarf,
835 /// DWARF debuginfo in dSYM files (such as on Apple platforms).
836 DwarfDsym,
837 /// Program database files (such as on Windows).
838 Pdb,
839 }
840
841 impl DebuginfoKind {
as_str(&self) -> &'static str842 fn as_str(&self) -> &'static str {
843 match self {
844 DebuginfoKind::Dwarf => "dwarf",
845 DebuginfoKind::DwarfDsym => "dwarf-dsym",
846 DebuginfoKind::Pdb => "pdb",
847 }
848 }
849 }
850
851 impl FromStr for DebuginfoKind {
852 type Err = ();
853
from_str(s: &str) -> Result<Self, ()>854 fn from_str(s: &str) -> Result<Self, ()> {
855 Ok(match s {
856 "dwarf" => DebuginfoKind::Dwarf,
857 "dwarf-dsym" => DebuginfoKind::DwarfDsym,
858 "pdb" => DebuginfoKind::Pdb,
859 _ => return Err(()),
860 })
861 }
862 }
863
864 impl ToJson for DebuginfoKind {
to_json(&self) -> Json865 fn to_json(&self) -> Json {
866 self.as_str().to_json()
867 }
868 }
869
870 impl fmt::Display for DebuginfoKind {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result871 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
872 f.write_str(self.as_str())
873 }
874 }
875
876 #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
877 pub enum SplitDebuginfo {
878 /// Split debug-information is disabled, meaning that on supported platforms
879 /// you can find all debug information in the executable itself. This is
880 /// only supported for ELF effectively.
881 ///
882 /// * Windows - not supported
883 /// * macOS - don't run `dsymutil`
884 /// * ELF - `.debug_*` sections
885 #[default]
886 Off,
887
888 /// Split debug-information can be found in a "packed" location separate
889 /// from the final artifact. This is supported on all platforms.
890 ///
891 /// * Windows - `*.pdb`
892 /// * macOS - `*.dSYM` (run `dsymutil`)
893 /// * ELF - `*.dwp` (run `thorin`)
894 Packed,
895
896 /// Split debug-information can be found in individual object files on the
897 /// filesystem. The main executable may point to the object files.
898 ///
899 /// * Windows - not supported
900 /// * macOS - supported, scattered object files
901 /// * ELF - supported, scattered `*.dwo` or `*.o` files (see `SplitDwarfKind`)
902 Unpacked,
903 }
904
905 impl SplitDebuginfo {
as_str(&self) -> &'static str906 fn as_str(&self) -> &'static str {
907 match self {
908 SplitDebuginfo::Off => "off",
909 SplitDebuginfo::Packed => "packed",
910 SplitDebuginfo::Unpacked => "unpacked",
911 }
912 }
913 }
914
915 impl FromStr for SplitDebuginfo {
916 type Err = ();
917
from_str(s: &str) -> Result<Self, ()>918 fn from_str(s: &str) -> Result<Self, ()> {
919 Ok(match s {
920 "off" => SplitDebuginfo::Off,
921 "unpacked" => SplitDebuginfo::Unpacked,
922 "packed" => SplitDebuginfo::Packed,
923 _ => return Err(()),
924 })
925 }
926 }
927
928 impl ToJson for SplitDebuginfo {
to_json(&self) -> Json929 fn to_json(&self) -> Json {
930 self.as_str().to_json()
931 }
932 }
933
934 impl fmt::Display for SplitDebuginfo {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result935 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
936 f.write_str(self.as_str())
937 }
938 }
939
940 #[derive(Clone, Debug, PartialEq, Eq)]
941 pub enum StackProbeType {
942 /// Don't emit any stack probes.
943 None,
944 /// It is harmless to use this option even on targets that do not have backend support for
945 /// stack probes as the failure mode is the same as if no stack-probe option was specified in
946 /// the first place.
947 Inline,
948 /// Call `__rust_probestack` whenever stack needs to be probed.
949 Call,
950 /// Use inline option for LLVM versions later than specified in `min_llvm_version_for_inline`
951 /// and call `__rust_probestack` otherwise.
952 InlineOrCall { min_llvm_version_for_inline: (u32, u32, u32) },
953 }
954
955 impl StackProbeType {
956 // LLVM X86 targets (ix86 and x86_64) can use inline-asm stack probes starting with LLVM 16.
957 // Notable past issues were rust#83139 (fixed in 14) and rust#84667 (fixed in 16).
958 const X86: Self = Self::InlineOrCall { min_llvm_version_for_inline: (16, 0, 0) };
959
from_json(json: &Json) -> Result<Self, String>960 fn from_json(json: &Json) -> Result<Self, String> {
961 let object = json.as_object().ok_or_else(|| "expected a JSON object")?;
962 let kind = object
963 .get("kind")
964 .and_then(|o| o.as_str())
965 .ok_or_else(|| "expected `kind` to be a string")?;
966 match kind {
967 "none" => Ok(StackProbeType::None),
968 "inline" => Ok(StackProbeType::Inline),
969 "call" => Ok(StackProbeType::Call),
970 "inline-or-call" => {
971 let min_version = object
972 .get("min-llvm-version-for-inline")
973 .and_then(|o| o.as_array())
974 .ok_or_else(|| "expected `min-llvm-version-for-inline` to be an array")?;
975 let mut iter = min_version.into_iter().map(|v| {
976 let int = v.as_u64().ok_or_else(
977 || "expected `min-llvm-version-for-inline` values to be integers",
978 )?;
979 u32::try_from(int)
980 .map_err(|_| "`min-llvm-version-for-inline` values don't convert to u32")
981 });
982 let min_llvm_version_for_inline = (
983 iter.next().unwrap_or(Ok(11))?,
984 iter.next().unwrap_or(Ok(0))?,
985 iter.next().unwrap_or(Ok(0))?,
986 );
987 Ok(StackProbeType::InlineOrCall { min_llvm_version_for_inline })
988 }
989 _ => Err(String::from(
990 "`kind` expected to be one of `none`, `inline`, `call` or `inline-or-call`",
991 )),
992 }
993 }
994 }
995
996 impl ToJson for StackProbeType {
to_json(&self) -> Json997 fn to_json(&self) -> Json {
998 Json::Object(match self {
999 StackProbeType::None => {
1000 [(String::from("kind"), "none".to_json())].into_iter().collect()
1001 }
1002 StackProbeType::Inline => {
1003 [(String::from("kind"), "inline".to_json())].into_iter().collect()
1004 }
1005 StackProbeType::Call => {
1006 [(String::from("kind"), "call".to_json())].into_iter().collect()
1007 }
1008 StackProbeType::InlineOrCall { min_llvm_version_for_inline: (maj, min, patch) } => [
1009 (String::from("kind"), "inline-or-call".to_json()),
1010 (
1011 String::from("min-llvm-version-for-inline"),
1012 Json::Array(vec![maj.to_json(), min.to_json(), patch.to_json()]),
1013 ),
1014 ]
1015 .into_iter()
1016 .collect(),
1017 })
1018 }
1019 }
1020
1021 bitflags::bitflags! {
1022 #[derive(Default, Encodable, Decodable)]
1023 pub struct SanitizerSet: u16 {
1024 const ADDRESS = 1 << 0;
1025 const LEAK = 1 << 1;
1026 const MEMORY = 1 << 2;
1027 const THREAD = 1 << 3;
1028 const HWADDRESS = 1 << 4;
1029 const CFI = 1 << 5;
1030 const MEMTAG = 1 << 6;
1031 const SHADOWCALLSTACK = 1 << 7;
1032 const KCFI = 1 << 8;
1033 const KERNELADDRESS = 1 << 9;
1034 const SAFESTACK = 1 << 10;
1035 }
1036 }
1037
1038 impl SanitizerSet {
1039 /// Return sanitizer's name
1040 ///
1041 /// Returns none if the flags is a set of sanitizers numbering not exactly one.
as_str(self) -> Option<&'static str>1042 pub fn as_str(self) -> Option<&'static str> {
1043 Some(match self {
1044 SanitizerSet::ADDRESS => "address",
1045 SanitizerSet::CFI => "cfi",
1046 SanitizerSet::KCFI => "kcfi",
1047 SanitizerSet::KERNELADDRESS => "kernel-address",
1048 SanitizerSet::LEAK => "leak",
1049 SanitizerSet::MEMORY => "memory",
1050 SanitizerSet::MEMTAG => "memtag",
1051 SanitizerSet::SAFESTACK => "safestack",
1052 SanitizerSet::SHADOWCALLSTACK => "shadow-call-stack",
1053 SanitizerSet::THREAD => "thread",
1054 SanitizerSet::HWADDRESS => "hwaddress",
1055 _ => return None,
1056 })
1057 }
1058 }
1059
1060 /// Formats a sanitizer set as a comma separated list of sanitizers' names.
1061 impl fmt::Display for SanitizerSet {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1062 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1063 let mut first = true;
1064 for s in *self {
1065 let name = s.as_str().unwrap_or_else(|| panic!("unrecognized sanitizer {s:?}"));
1066 if !first {
1067 f.write_str(", ")?;
1068 }
1069 f.write_str(name)?;
1070 first = false;
1071 }
1072 Ok(())
1073 }
1074 }
1075
1076 impl IntoIterator for SanitizerSet {
1077 type Item = SanitizerSet;
1078 type IntoIter = std::vec::IntoIter<SanitizerSet>;
1079
into_iter(self) -> Self::IntoIter1080 fn into_iter(self) -> Self::IntoIter {
1081 [
1082 SanitizerSet::ADDRESS,
1083 SanitizerSet::CFI,
1084 SanitizerSet::KCFI,
1085 SanitizerSet::LEAK,
1086 SanitizerSet::MEMORY,
1087 SanitizerSet::MEMTAG,
1088 SanitizerSet::SHADOWCALLSTACK,
1089 SanitizerSet::THREAD,
1090 SanitizerSet::HWADDRESS,
1091 SanitizerSet::KERNELADDRESS,
1092 SanitizerSet::SAFESTACK,
1093 ]
1094 .iter()
1095 .copied()
1096 .filter(|&s| self.contains(s))
1097 .collect::<Vec<_>>()
1098 .into_iter()
1099 }
1100 }
1101
1102 impl<CTX> HashStable<CTX> for SanitizerSet {
hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher)1103 fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
1104 self.bits().hash_stable(ctx, hasher);
1105 }
1106 }
1107
1108 impl ToJson for SanitizerSet {
to_json(&self) -> Json1109 fn to_json(&self) -> Json {
1110 self.into_iter()
1111 .map(|v| Some(v.as_str()?.to_json()))
1112 .collect::<Option<Vec<_>>>()
1113 .unwrap_or_default()
1114 .to_json()
1115 }
1116 }
1117
1118 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
1119 pub enum FramePointer {
1120 /// Forces the machine code generator to always preserve the frame pointers.
1121 Always,
1122 /// Forces the machine code generator to preserve the frame pointers except for the leaf
1123 /// functions (i.e. those that don't call other functions).
1124 NonLeaf,
1125 /// Allows the machine code generator to omit the frame pointers.
1126 ///
1127 /// This option does not guarantee that the frame pointers will be omitted.
1128 MayOmit,
1129 }
1130
1131 impl FromStr for FramePointer {
1132 type Err = ();
from_str(s: &str) -> Result<Self, ()>1133 fn from_str(s: &str) -> Result<Self, ()> {
1134 Ok(match s {
1135 "always" => Self::Always,
1136 "non-leaf" => Self::NonLeaf,
1137 "may-omit" => Self::MayOmit,
1138 _ => return Err(()),
1139 })
1140 }
1141 }
1142
1143 impl ToJson for FramePointer {
to_json(&self) -> Json1144 fn to_json(&self) -> Json {
1145 match *self {
1146 Self::Always => "always",
1147 Self::NonLeaf => "non-leaf",
1148 Self::MayOmit => "may-omit",
1149 }
1150 .to_json()
1151 }
1152 }
1153
1154 /// Controls use of stack canaries.
1155 #[derive(Clone, Copy, Debug, PartialEq, Hash, Eq)]
1156 pub enum StackProtector {
1157 /// Disable stack canary generation.
1158 None,
1159
1160 /// On LLVM, mark all generated LLVM functions with the `ssp` attribute (see
1161 /// llvm/docs/LangRef.rst). This triggers stack canary generation in
1162 /// functions which contain an array of a byte-sized type with more than
1163 /// eight elements.
1164 Basic,
1165
1166 /// On LLVM, mark all generated LLVM functions with the `sspstrong`
1167 /// attribute (see llvm/docs/LangRef.rst). This triggers stack canary
1168 /// generation in functions which either contain an array, or which take
1169 /// the address of a local variable.
1170 Strong,
1171
1172 /// Generate stack canaries in all functions.
1173 All,
1174 }
1175
1176 impl StackProtector {
as_str(&self) -> &'static str1177 fn as_str(&self) -> &'static str {
1178 match self {
1179 StackProtector::None => "none",
1180 StackProtector::Basic => "basic",
1181 StackProtector::Strong => "strong",
1182 StackProtector::All => "all",
1183 }
1184 }
1185 }
1186
1187 impl FromStr for StackProtector {
1188 type Err = ();
1189
from_str(s: &str) -> Result<StackProtector, ()>1190 fn from_str(s: &str) -> Result<StackProtector, ()> {
1191 Ok(match s {
1192 "none" => StackProtector::None,
1193 "basic" => StackProtector::Basic,
1194 "strong" => StackProtector::Strong,
1195 "all" => StackProtector::All,
1196 _ => return Err(()),
1197 })
1198 }
1199 }
1200
1201 impl fmt::Display for StackProtector {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1202 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1203 f.write_str(self.as_str())
1204 }
1205 }
1206
1207 macro_rules! supported_targets {
1208 ( $(($triple:literal, $module:ident),)+ ) => {
1209 $(mod $module;)+
1210
1211 /// List of supported targets
1212 pub const TARGETS: &[&str] = &[$($triple),+];
1213
1214 fn load_builtin(target: &str) -> Option<Target> {
1215 let mut t = match target {
1216 $( $triple => $module::target(), )+
1217 _ => return None,
1218 };
1219 t.is_builtin = true;
1220 debug!("got builtin target: {:?}", t);
1221 Some(t)
1222 }
1223
1224 #[cfg(test)]
1225 mod tests {
1226 mod tests_impl;
1227
1228 // Cannot put this into a separate file without duplication, make an exception.
1229 $(
1230 #[test] // `#[test]`
1231 fn $module() {
1232 tests_impl::test_target(super::$module::target());
1233 }
1234 )+
1235 }
1236 };
1237 }
1238
1239 supported_targets! {
1240 ("x86_64-unknown-linux-gnu", x86_64_unknown_linux_gnu),
1241 ("x86_64-unknown-linux-gnux32", x86_64_unknown_linux_gnux32),
1242 ("i686-unknown-linux-gnu", i686_unknown_linux_gnu),
1243 ("i586-unknown-linux-gnu", i586_unknown_linux_gnu),
1244 ("loongarch64-unknown-linux-gnu", loongarch64_unknown_linux_gnu),
1245 ("m68k-unknown-linux-gnu", m68k_unknown_linux_gnu),
1246 ("mips-unknown-linux-gnu", mips_unknown_linux_gnu),
1247 ("mips64-unknown-linux-gnuabi64", mips64_unknown_linux_gnuabi64),
1248 ("mips64el-unknown-linux-gnuabi64", mips64el_unknown_linux_gnuabi64),
1249 ("mipsisa32r6-unknown-linux-gnu", mipsisa32r6_unknown_linux_gnu),
1250 ("mipsisa32r6el-unknown-linux-gnu", mipsisa32r6el_unknown_linux_gnu),
1251 ("mipsisa64r6-unknown-linux-gnuabi64", mipsisa64r6_unknown_linux_gnuabi64),
1252 ("mipsisa64r6el-unknown-linux-gnuabi64", mipsisa64r6el_unknown_linux_gnuabi64),
1253 ("mipsel-unknown-linux-gnu", mipsel_unknown_linux_gnu),
1254 ("powerpc-unknown-linux-gnu", powerpc_unknown_linux_gnu),
1255 ("powerpc-unknown-linux-gnuspe", powerpc_unknown_linux_gnuspe),
1256 ("powerpc-unknown-linux-musl", powerpc_unknown_linux_musl),
1257 ("powerpc64-ibm-aix", powerpc64_ibm_aix),
1258 ("powerpc64-unknown-linux-gnu", powerpc64_unknown_linux_gnu),
1259 ("powerpc64-unknown-linux-musl", powerpc64_unknown_linux_musl),
1260 ("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu),
1261 ("powerpc64le-unknown-linux-musl", powerpc64le_unknown_linux_musl),
1262 ("s390x-unknown-linux-gnu", s390x_unknown_linux_gnu),
1263 ("s390x-unknown-linux-musl", s390x_unknown_linux_musl),
1264 ("sparc-unknown-linux-gnu", sparc_unknown_linux_gnu),
1265 ("sparc64-unknown-linux-gnu", sparc64_unknown_linux_gnu),
1266 ("arm-unknown-linux-gnueabi", arm_unknown_linux_gnueabi),
1267 ("arm-unknown-linux-gnueabihf", arm_unknown_linux_gnueabihf),
1268 ("armeb-unknown-linux-gnueabi", armeb_unknown_linux_gnueabi),
1269 ("arm-unknown-linux-musleabi", arm_unknown_linux_musleabi),
1270 ("arm-unknown-linux-musleabihf", arm_unknown_linux_musleabihf),
1271 ("armv4t-unknown-linux-gnueabi", armv4t_unknown_linux_gnueabi),
1272 ("armv5te-unknown-linux-gnueabi", armv5te_unknown_linux_gnueabi),
1273 ("armv5te-unknown-linux-musleabi", armv5te_unknown_linux_musleabi),
1274 ("armv5te-unknown-linux-uclibceabi", armv5te_unknown_linux_uclibceabi),
1275 ("armv7-unknown-linux-gnueabi", armv7_unknown_linux_gnueabi),
1276 ("armv7-unknown-linux-gnueabihf", armv7_unknown_linux_gnueabihf),
1277 ("thumbv7neon-unknown-linux-gnueabihf", thumbv7neon_unknown_linux_gnueabihf),
1278 ("thumbv7neon-unknown-linux-musleabihf", thumbv7neon_unknown_linux_musleabihf),
1279 ("armv7-unknown-linux-musleabi", armv7_unknown_linux_musleabi),
1280 ("armv7-unknown-linux-musleabihf", armv7_unknown_linux_musleabihf),
1281 ("aarch64-unknown-linux-gnu", aarch64_unknown_linux_gnu),
1282 ("aarch64-unknown-linux-musl", aarch64_unknown_linux_musl),
1283 ("x86_64-unknown-linux-musl", x86_64_unknown_linux_musl),
1284 ("i686-unknown-linux-musl", i686_unknown_linux_musl),
1285 ("i586-unknown-linux-musl", i586_unknown_linux_musl),
1286 ("mips-unknown-linux-musl", mips_unknown_linux_musl),
1287 ("mipsel-unknown-linux-musl", mipsel_unknown_linux_musl),
1288 ("mips64-unknown-linux-muslabi64", mips64_unknown_linux_muslabi64),
1289 ("mips64el-unknown-linux-muslabi64", mips64el_unknown_linux_muslabi64),
1290 ("hexagon-unknown-linux-musl", hexagon_unknown_linux_musl),
1291
1292 ("mips-unknown-linux-uclibc", mips_unknown_linux_uclibc),
1293 ("mipsel-unknown-linux-uclibc", mipsel_unknown_linux_uclibc),
1294
1295 ("i686-linux-android", i686_linux_android),
1296 ("x86_64-linux-android", x86_64_linux_android),
1297 ("arm-linux-androideabi", arm_linux_androideabi),
1298 ("armv7-linux-androideabi", armv7_linux_androideabi),
1299 ("thumbv7neon-linux-androideabi", thumbv7neon_linux_androideabi),
1300 ("aarch64-linux-android", aarch64_linux_android),
1301
1302 ("aarch64-unknown-freebsd", aarch64_unknown_freebsd),
1303 ("armv6-unknown-freebsd", armv6_unknown_freebsd),
1304 ("armv7-unknown-freebsd", armv7_unknown_freebsd),
1305 ("i686-unknown-freebsd", i686_unknown_freebsd),
1306 ("powerpc-unknown-freebsd", powerpc_unknown_freebsd),
1307 ("powerpc64-unknown-freebsd", powerpc64_unknown_freebsd),
1308 ("powerpc64le-unknown-freebsd", powerpc64le_unknown_freebsd),
1309 ("riscv64gc-unknown-freebsd", riscv64gc_unknown_freebsd),
1310 ("x86_64-unknown-freebsd", x86_64_unknown_freebsd),
1311
1312 ("x86_64-unknown-dragonfly", x86_64_unknown_dragonfly),
1313
1314 ("aarch64-unknown-openbsd", aarch64_unknown_openbsd),
1315 ("i686-unknown-openbsd", i686_unknown_openbsd),
1316 ("powerpc-unknown-openbsd", powerpc_unknown_openbsd),
1317 ("powerpc64-unknown-openbsd", powerpc64_unknown_openbsd),
1318 ("riscv64gc-unknown-openbsd", riscv64gc_unknown_openbsd),
1319 ("sparc64-unknown-openbsd", sparc64_unknown_openbsd),
1320 ("x86_64-unknown-openbsd", x86_64_unknown_openbsd),
1321
1322 ("aarch64-unknown-netbsd", aarch64_unknown_netbsd),
1323 ("aarch64_be-unknown-netbsd", aarch64_be_unknown_netbsd),
1324 ("armv6-unknown-netbsd-eabihf", armv6_unknown_netbsd_eabihf),
1325 ("armv7-unknown-netbsd-eabihf", armv7_unknown_netbsd_eabihf),
1326 ("i686-unknown-netbsd", i686_unknown_netbsd),
1327 ("powerpc-unknown-netbsd", powerpc_unknown_netbsd),
1328 ("riscv64gc-unknown-netbsd", riscv64gc_unknown_netbsd),
1329 ("sparc64-unknown-netbsd", sparc64_unknown_netbsd),
1330 ("x86_64-unknown-netbsd", x86_64_unknown_netbsd),
1331
1332 ("i686-unknown-haiku", i686_unknown_haiku),
1333 ("x86_64-unknown-haiku", x86_64_unknown_haiku),
1334
1335 ("aarch64-apple-darwin", aarch64_apple_darwin),
1336 ("x86_64-apple-darwin", x86_64_apple_darwin),
1337 ("x86_64h-apple-darwin", x86_64h_apple_darwin),
1338 ("i686-apple-darwin", i686_apple_darwin),
1339
1340 // FIXME(#106649): Remove aarch64-fuchsia in favor of aarch64-unknown-fuchsia
1341 ("aarch64-fuchsia", aarch64_fuchsia),
1342 ("aarch64-unknown-fuchsia", aarch64_unknown_fuchsia),
1343 ("riscv64gc-unknown-fuchsia", riscv64gc_unknown_fuchsia),
1344 // FIXME(#106649): Remove x86_64-fuchsia in favor of x86_64-unknown-fuchsia
1345 ("x86_64-fuchsia", x86_64_fuchsia),
1346 ("x86_64-unknown-fuchsia", x86_64_unknown_fuchsia),
1347
1348 ("avr-unknown-gnu-atmega328", avr_unknown_gnu_atmega328),
1349
1350 ("x86_64-unknown-l4re-uclibc", x86_64_unknown_l4re_uclibc),
1351
1352 ("aarch64-unknown-redox", aarch64_unknown_redox),
1353 ("x86_64-unknown-redox", x86_64_unknown_redox),
1354
1355 ("i386-apple-ios", i386_apple_ios),
1356 ("x86_64-apple-ios", x86_64_apple_ios),
1357 ("aarch64-apple-ios", aarch64_apple_ios),
1358 ("armv7-apple-ios", armv7_apple_ios),
1359 ("armv7s-apple-ios", armv7s_apple_ios),
1360 ("x86_64-apple-ios-macabi", x86_64_apple_ios_macabi),
1361 ("aarch64-apple-ios-macabi", aarch64_apple_ios_macabi),
1362 ("aarch64-apple-ios-sim", aarch64_apple_ios_sim),
1363 ("aarch64-apple-tvos", aarch64_apple_tvos),
1364 ("x86_64-apple-tvos", x86_64_apple_tvos),
1365
1366 ("armv7k-apple-watchos", armv7k_apple_watchos),
1367 ("arm64_32-apple-watchos", arm64_32_apple_watchos),
1368 ("x86_64-apple-watchos-sim", x86_64_apple_watchos_sim),
1369 ("aarch64-apple-watchos-sim", aarch64_apple_watchos_sim),
1370
1371 ("armebv7r-none-eabi", armebv7r_none_eabi),
1372 ("armebv7r-none-eabihf", armebv7r_none_eabihf),
1373 ("armv7r-none-eabi", armv7r_none_eabi),
1374 ("armv7r-none-eabihf", armv7r_none_eabihf),
1375
1376 ("x86_64-pc-solaris", x86_64_pc_solaris),
1377 ("x86_64-sun-solaris", x86_64_sun_solaris),
1378 ("sparcv9-sun-solaris", sparcv9_sun_solaris),
1379
1380 ("x86_64-unknown-illumos", x86_64_unknown_illumos),
1381
1382 ("x86_64-pc-windows-gnu", x86_64_pc_windows_gnu),
1383 ("i686-pc-windows-gnu", i686_pc_windows_gnu),
1384 ("i686-uwp-windows-gnu", i686_uwp_windows_gnu),
1385 ("x86_64-uwp-windows-gnu", x86_64_uwp_windows_gnu),
1386
1387 ("aarch64-pc-windows-gnullvm", aarch64_pc_windows_gnullvm),
1388 ("x86_64-pc-windows-gnullvm", x86_64_pc_windows_gnullvm),
1389
1390 ("aarch64-pc-windows-msvc", aarch64_pc_windows_msvc),
1391 ("aarch64-uwp-windows-msvc", aarch64_uwp_windows_msvc),
1392 ("x86_64-pc-windows-msvc", x86_64_pc_windows_msvc),
1393 ("x86_64-uwp-windows-msvc", x86_64_uwp_windows_msvc),
1394 ("i686-pc-windows-msvc", i686_pc_windows_msvc),
1395 ("i686-uwp-windows-msvc", i686_uwp_windows_msvc),
1396 ("i586-pc-windows-msvc", i586_pc_windows_msvc),
1397 ("thumbv7a-pc-windows-msvc", thumbv7a_pc_windows_msvc),
1398 ("thumbv7a-uwp-windows-msvc", thumbv7a_uwp_windows_msvc),
1399
1400 ("asmjs-unknown-emscripten", asmjs_unknown_emscripten),
1401 ("wasm32-unknown-emscripten", wasm32_unknown_emscripten),
1402 ("wasm32-unknown-unknown", wasm32_unknown_unknown),
1403 ("wasm32-wasi", wasm32_wasi),
1404 ("wasm64-unknown-unknown", wasm64_unknown_unknown),
1405
1406 ("thumbv6m-none-eabi", thumbv6m_none_eabi),
1407 ("thumbv7m-none-eabi", thumbv7m_none_eabi),
1408 ("thumbv7em-none-eabi", thumbv7em_none_eabi),
1409 ("thumbv7em-none-eabihf", thumbv7em_none_eabihf),
1410 ("thumbv8m.base-none-eabi", thumbv8m_base_none_eabi),
1411 ("thumbv8m.main-none-eabi", thumbv8m_main_none_eabi),
1412 ("thumbv8m.main-none-eabihf", thumbv8m_main_none_eabihf),
1413
1414 ("armv7a-none-eabi", armv7a_none_eabi),
1415 ("armv7a-none-eabihf", armv7a_none_eabihf),
1416
1417 ("msp430-none-elf", msp430_none_elf),
1418
1419 ("aarch64-unknown-hermit", aarch64_unknown_hermit),
1420 ("x86_64-unknown-hermit", x86_64_unknown_hermit),
1421
1422 ("riscv32i-unknown-none-elf", riscv32i_unknown_none_elf),
1423 ("riscv32im-unknown-none-elf", riscv32im_unknown_none_elf),
1424 ("riscv32imc-unknown-none-elf", riscv32imc_unknown_none_elf),
1425 ("riscv32imc-esp-espidf", riscv32imc_esp_espidf),
1426 ("riscv32imac-esp-espidf", riscv32imac_esp_espidf),
1427 ("riscv32imac-unknown-none-elf", riscv32imac_unknown_none_elf),
1428 ("riscv32imac-unknown-xous-elf", riscv32imac_unknown_xous_elf),
1429 ("riscv32gc-unknown-linux-gnu", riscv32gc_unknown_linux_gnu),
1430 ("riscv32gc-unknown-linux-musl", riscv32gc_unknown_linux_musl),
1431 ("riscv64imac-unknown-none-elf", riscv64imac_unknown_none_elf),
1432 ("riscv64gc-unknown-none-elf", riscv64gc_unknown_none_elf),
1433 ("riscv64gc-unknown-linux-gnu", riscv64gc_unknown_linux_gnu),
1434 ("riscv64gc-unknown-linux-musl", riscv64gc_unknown_linux_musl),
1435
1436 ("loongarch64-unknown-none", loongarch64_unknown_none),
1437 ("loongarch64-unknown-none-softfloat", loongarch64_unknown_none_softfloat),
1438
1439 ("aarch64-unknown-none", aarch64_unknown_none),
1440 ("aarch64-unknown-none-softfloat", aarch64_unknown_none_softfloat),
1441
1442 ("x86_64-fortanix-unknown-sgx", x86_64_fortanix_unknown_sgx),
1443
1444 ("x86_64-unknown-uefi", x86_64_unknown_uefi),
1445 ("i686-unknown-uefi", i686_unknown_uefi),
1446 ("aarch64-unknown-uefi", aarch64_unknown_uefi),
1447
1448 ("nvptx64-nvidia-cuda", nvptx64_nvidia_cuda),
1449
1450 ("i686-wrs-vxworks", i686_wrs_vxworks),
1451 ("x86_64-wrs-vxworks", x86_64_wrs_vxworks),
1452 ("armv7-wrs-vxworks-eabihf", armv7_wrs_vxworks_eabihf),
1453 ("aarch64-wrs-vxworks", aarch64_wrs_vxworks),
1454 ("powerpc-wrs-vxworks", powerpc_wrs_vxworks),
1455 ("powerpc-wrs-vxworks-spe", powerpc_wrs_vxworks_spe),
1456 ("powerpc64-wrs-vxworks", powerpc64_wrs_vxworks),
1457
1458 ("aarch64-kmc-solid_asp3", aarch64_kmc_solid_asp3),
1459 ("armv7a-kmc-solid_asp3-eabi", armv7a_kmc_solid_asp3_eabi),
1460 ("armv7a-kmc-solid_asp3-eabihf", armv7a_kmc_solid_asp3_eabihf),
1461
1462 ("mipsel-sony-psp", mipsel_sony_psp),
1463 ("mipsel-sony-psx", mipsel_sony_psx),
1464 ("mipsel-unknown-none", mipsel_unknown_none),
1465 ("thumbv4t-none-eabi", thumbv4t_none_eabi),
1466 ("armv4t-none-eabi", armv4t_none_eabi),
1467 ("thumbv5te-none-eabi", thumbv5te_none_eabi),
1468 ("armv5te-none-eabi", armv5te_none_eabi),
1469
1470 ("aarch64_be-unknown-linux-gnu", aarch64_be_unknown_linux_gnu),
1471 ("aarch64-unknown-linux-gnu_ilp32", aarch64_unknown_linux_gnu_ilp32),
1472 ("aarch64_be-unknown-linux-gnu_ilp32", aarch64_be_unknown_linux_gnu_ilp32),
1473
1474 ("bpfeb-unknown-none", bpfeb_unknown_none),
1475 ("bpfel-unknown-none", bpfel_unknown_none),
1476
1477 ("armv6k-nintendo-3ds", armv6k_nintendo_3ds),
1478
1479 ("aarch64-nintendo-switch-freestanding", aarch64_nintendo_switch_freestanding),
1480
1481 ("armv7-sony-vita-newlibeabihf", armv7_sony_vita_newlibeabihf),
1482
1483 ("armv7-unknown-linux-uclibceabi", armv7_unknown_linux_uclibceabi),
1484 ("armv7-unknown-linux-uclibceabihf", armv7_unknown_linux_uclibceabihf),
1485
1486 ("x86_64-unknown-none", x86_64_unknown_none),
1487
1488 ("mips64-openwrt-linux-musl", mips64_openwrt_linux_musl),
1489
1490 ("aarch64-unknown-nto-qnx710", aarch64_unknown_nto_qnx_710),
1491 ("x86_64-pc-nto-qnx710", x86_64_pc_nto_qnx710),
1492 ("i586-pc-nto-qnx700", i586_pc_nto_qnx700),
1493
1494 ("aarch64-unknown-linux-ohos", aarch64_unknown_linux_ohos),
1495 ("armv7-unknown-linux-ohos", armv7_unknown_linux_ohos),
1496 ("x86_64-unknown-linux-ohos", x86_64_unknown_linux_ohos),
1497 }
1498
1499 /// Cow-Vec-Str: Cow<'static, [Cow<'static, str>]>
1500 macro_rules! cvs {
1501 () => {
1502 ::std::borrow::Cow::Borrowed(&[])
1503 };
1504 ($($x:expr),+ $(,)?) => {
1505 ::std::borrow::Cow::Borrowed(&[
1506 $(
1507 ::std::borrow::Cow::Borrowed($x),
1508 )*
1509 ])
1510 };
1511 }
1512
1513 pub(crate) use cvs;
1514
1515 /// Warnings encountered when parsing the target `json`.
1516 ///
1517 /// Includes fields that weren't recognized and fields that don't have the expected type.
1518 #[derive(Debug, PartialEq)]
1519 pub struct TargetWarnings {
1520 unused_fields: Vec<String>,
1521 incorrect_type: Vec<String>,
1522 }
1523
1524 impl TargetWarnings {
empty() -> Self1525 pub fn empty() -> Self {
1526 Self { unused_fields: Vec::new(), incorrect_type: Vec::new() }
1527 }
1528
warning_messages(&self) -> Vec<String>1529 pub fn warning_messages(&self) -> Vec<String> {
1530 let mut warnings = vec![];
1531 if !self.unused_fields.is_empty() {
1532 warnings.push(format!(
1533 "target json file contains unused fields: {}",
1534 self.unused_fields.join(", ")
1535 ));
1536 }
1537 if !self.incorrect_type.is_empty() {
1538 warnings.push(format!(
1539 "target json file contains fields whose value doesn't have the correct json type: {}",
1540 self.incorrect_type.join(", ")
1541 ));
1542 }
1543 warnings
1544 }
1545 }
1546
1547 /// Everything `rustc` knows about how to compile for a specific target.
1548 ///
1549 /// Every field here must be specified, and has no default value.
1550 #[derive(PartialEq, Clone, Debug)]
1551 pub struct Target {
1552 /// Target triple to pass to LLVM.
1553 pub llvm_target: StaticCow<str>,
1554 /// Number of bits in a pointer. Influences the `target_pointer_width` `cfg` variable.
1555 pub pointer_width: u32,
1556 /// Architecture to use for ABI considerations. Valid options include: "x86",
1557 /// "x86_64", "arm", "aarch64", "mips", "powerpc", "powerpc64", and others.
1558 pub arch: StaticCow<str>,
1559 /// [Data layout](https://llvm.org/docs/LangRef.html#data-layout) to pass to LLVM.
1560 pub data_layout: StaticCow<str>,
1561 /// Optional settings with defaults.
1562 pub options: TargetOptions,
1563 }
1564
1565 impl Target {
parse_data_layout(&self) -> Result<TargetDataLayout, TargetDataLayoutErrors<'_>>1566 pub fn parse_data_layout(&self) -> Result<TargetDataLayout, TargetDataLayoutErrors<'_>> {
1567 let mut dl = TargetDataLayout::parse_from_llvm_datalayout_string(&self.data_layout)?;
1568
1569 // Perform consistency checks against the Target information.
1570 if dl.endian != self.endian {
1571 return Err(TargetDataLayoutErrors::InconsistentTargetArchitecture {
1572 dl: dl.endian.as_str(),
1573 target: self.endian.as_str(),
1574 });
1575 }
1576
1577 let target_pointer_width: u64 = self.pointer_width.into();
1578 if dl.pointer_size.bits() != target_pointer_width {
1579 return Err(TargetDataLayoutErrors::InconsistentTargetPointerWidth {
1580 pointer_size: dl.pointer_size.bits(),
1581 target: self.pointer_width,
1582 });
1583 }
1584
1585 dl.c_enum_min_size = self
1586 .c_enum_min_bits
1587 .map_or_else(
1588 || {
1589 self.c_int_width
1590 .parse()
1591 .map_err(|_| String::from("failed to parse c_int_width"))
1592 },
1593 Ok,
1594 )
1595 .and_then(|i| Integer::from_size(Size::from_bits(i)))
1596 .map_err(|err| TargetDataLayoutErrors::InvalidBitsSize { err })?;
1597
1598 Ok(dl)
1599 }
1600 }
1601
1602 pub trait HasTargetSpec {
target_spec(&self) -> &Target1603 fn target_spec(&self) -> &Target;
1604 }
1605
1606 impl HasTargetSpec for Target {
1607 #[inline]
target_spec(&self) -> &Target1608 fn target_spec(&self) -> &Target {
1609 self
1610 }
1611 }
1612
1613 type StaticCow<T> = Cow<'static, T>;
1614
1615 /// Optional aspects of a target specification.
1616 ///
1617 /// This has an implementation of `Default`, see each field for what the default is. In general,
1618 /// these try to take "minimal defaults" that don't assume anything about the runtime they run in.
1619 ///
1620 /// `TargetOptions` as a separate structure is mostly an implementation detail of `Target`
1621 /// construction, all its fields logically belong to `Target` and available from `Target`
1622 /// through `Deref` impls.
1623 #[derive(PartialEq, Clone, Debug)]
1624 pub struct TargetOptions {
1625 /// Whether the target is built-in or loaded from a custom target specification.
1626 pub is_builtin: bool,
1627
1628 /// Used as the `target_endian` `cfg` variable. Defaults to little endian.
1629 pub endian: Endian,
1630 /// Width of c_int type. Defaults to "32".
1631 pub c_int_width: StaticCow<str>,
1632 /// OS name to use for conditional compilation (`target_os`). Defaults to "none".
1633 /// "none" implies a bare metal target without `std` library.
1634 /// A couple of targets having `std` also use "unknown" as an `os` value,
1635 /// but they are exceptions.
1636 pub os: StaticCow<str>,
1637 /// Environment name to use for conditional compilation (`target_env`). Defaults to "".
1638 pub env: StaticCow<str>,
1639 /// ABI name to distinguish multiple ABIs on the same OS and architecture. For instance, `"eabi"`
1640 /// or `"eabihf"`. Defaults to "".
1641 pub abi: StaticCow<str>,
1642 /// Vendor name to use for conditional compilation (`target_vendor`). Defaults to "unknown".
1643 pub vendor: StaticCow<str>,
1644
1645 /// Linker to invoke
1646 pub linker: Option<StaticCow<str>>,
1647 /// Default linker flavor used if `-C linker-flavor` or `-C linker` are not passed
1648 /// on the command line. Defaults to `LinkerFlavor::Gnu(Cc::Yes, Lld::No)`.
1649 pub linker_flavor: LinkerFlavor,
1650 linker_flavor_json: LinkerFlavorCli,
1651 lld_flavor_json: LldFlavor,
1652 linker_is_gnu_json: bool,
1653
1654 /// Objects to link before and after all other object code.
1655 pub pre_link_objects: CrtObjects,
1656 pub post_link_objects: CrtObjects,
1657 /// Same as `(pre|post)_link_objects`, but when self-contained linking mode is enabled.
1658 pub pre_link_objects_self_contained: CrtObjects,
1659 pub post_link_objects_self_contained: CrtObjects,
1660 pub link_self_contained: LinkSelfContainedDefault,
1661
1662 /// Linker arguments that are passed *before* any user-defined libraries.
1663 pub pre_link_args: LinkArgs,
1664 pre_link_args_json: LinkArgsCli,
1665 /// Linker arguments that are unconditionally passed after any
1666 /// user-defined but before post-link objects. Standard platform
1667 /// libraries that should be always be linked to, usually go here.
1668 pub late_link_args: LinkArgs,
1669 late_link_args_json: LinkArgsCli,
1670 /// Linker arguments used in addition to `late_link_args` if at least one
1671 /// Rust dependency is dynamically linked.
1672 pub late_link_args_dynamic: LinkArgs,
1673 late_link_args_dynamic_json: LinkArgsCli,
1674 /// Linker arguments used in addition to `late_link_args` if all Rust
1675 /// dependencies are statically linked.
1676 pub late_link_args_static: LinkArgs,
1677 late_link_args_static_json: LinkArgsCli,
1678 /// Linker arguments that are unconditionally passed *after* any
1679 /// user-defined libraries.
1680 pub post_link_args: LinkArgs,
1681 post_link_args_json: LinkArgsCli,
1682
1683 /// Optional link script applied to `dylib` and `executable` crate types.
1684 /// This is a string containing the script, not a path. Can only be applied
1685 /// to linkers where linker flavor matches `LinkerFlavor::Gnu(..)`.
1686 pub link_script: Option<StaticCow<str>>,
1687 /// Environment variables to be set for the linker invocation.
1688 pub link_env: StaticCow<[(StaticCow<str>, StaticCow<str>)]>,
1689 /// Environment variables to be removed for the linker invocation.
1690 pub link_env_remove: StaticCow<[StaticCow<str>]>,
1691
1692 /// Extra arguments to pass to the external assembler (when used)
1693 pub asm_args: StaticCow<[StaticCow<str>]>,
1694
1695 /// Default CPU to pass to LLVM. Corresponds to `llc -mcpu=$cpu`. Defaults
1696 /// to "generic".
1697 pub cpu: StaticCow<str>,
1698 /// Default target features to pass to LLVM. These features will *always* be
1699 /// passed, and cannot be disabled even via `-C`. Corresponds to `llc
1700 /// -mattr=$features`.
1701 pub features: StaticCow<str>,
1702 /// Whether dynamic linking is available on this target. Defaults to false.
1703 pub dynamic_linking: bool,
1704 /// Whether dynamic linking can export TLS globals. Defaults to true.
1705 pub dll_tls_export: bool,
1706 /// If dynamic linking is available, whether only cdylibs are supported.
1707 pub only_cdylib: bool,
1708 /// Whether executables are available on this target. Defaults to true.
1709 pub executables: bool,
1710 /// Relocation model to use in object file. Corresponds to `llc
1711 /// -relocation-model=$relocation_model`. Defaults to `Pic`.
1712 pub relocation_model: RelocModel,
1713 /// Code model to use. Corresponds to `llc -code-model=$code_model`.
1714 /// Defaults to `None` which means "inherited from the base LLVM target".
1715 pub code_model: Option<CodeModel>,
1716 /// TLS model to use. Options are "global-dynamic" (default), "local-dynamic", "initial-exec"
1717 /// and "local-exec". This is similar to the -ftls-model option in GCC/Clang.
1718 pub tls_model: TlsModel,
1719 /// Do not emit code that uses the "red zone", if the ABI has one. Defaults to false.
1720 pub disable_redzone: bool,
1721 /// Frame pointer mode for this target. Defaults to `MayOmit`.
1722 pub frame_pointer: FramePointer,
1723 /// Emit each function in its own section. Defaults to true.
1724 pub function_sections: bool,
1725 /// String to prepend to the name of every dynamic library. Defaults to "lib".
1726 pub dll_prefix: StaticCow<str>,
1727 /// String to append to the name of every dynamic library. Defaults to ".so".
1728 pub dll_suffix: StaticCow<str>,
1729 /// String to append to the name of every executable.
1730 pub exe_suffix: StaticCow<str>,
1731 /// String to prepend to the name of every static library. Defaults to "lib".
1732 pub staticlib_prefix: StaticCow<str>,
1733 /// String to append to the name of every static library. Defaults to ".a".
1734 pub staticlib_suffix: StaticCow<str>,
1735 /// Values of the `target_family` cfg set for this target.
1736 ///
1737 /// Common options are: "unix", "windows". Defaults to no families.
1738 ///
1739 /// See <https://doc.rust-lang.org/reference/conditional-compilation.html#target_family>.
1740 pub families: StaticCow<[StaticCow<str>]>,
1741 /// Whether the target toolchain's ABI supports returning small structs as an integer.
1742 pub abi_return_struct_as_int: bool,
1743 /// Whether the target toolchain is like AIX's. Linker options on AIX are special and it uses
1744 /// XCOFF as binary format. Defaults to false.
1745 pub is_like_aix: bool,
1746 /// Whether the target toolchain is like macOS's. Only useful for compiling against iOS/macOS,
1747 /// in particular running dsymutil and some other stuff like `-dead_strip`. Defaults to false.
1748 /// Also indiates whether to use Apple-specific ABI changes, such as extending function
1749 /// parameters to 32-bits.
1750 pub is_like_osx: bool,
1751 /// Whether the target toolchain is like Solaris's.
1752 /// Only useful for compiling against Illumos/Solaris,
1753 /// as they have a different set of linker flags. Defaults to false.
1754 pub is_like_solaris: bool,
1755 /// Whether the target is like Windows.
1756 /// This is a combination of several more specific properties represented as a single flag:
1757 /// - The target uses a Windows ABI,
1758 /// - uses PE/COFF as a format for object code,
1759 /// - uses Windows-style dllexport/dllimport for shared libraries,
1760 /// - uses import libraries and .def files for symbol exports,
1761 /// - executables support setting a subsystem.
1762 pub is_like_windows: bool,
1763 /// Whether the target is like MSVC.
1764 /// This is a combination of several more specific properties represented as a single flag:
1765 /// - The target has all the properties from `is_like_windows`
1766 /// (for in-tree targets "is_like_msvc ⇒ is_like_windows" is ensured by a unit test),
1767 /// - has some MSVC-specific Windows ABI properties,
1768 /// - uses a link.exe-like linker,
1769 /// - uses CodeView/PDB for debuginfo and natvis for its visualization,
1770 /// - uses SEH-based unwinding,
1771 /// - supports control flow guard mechanism.
1772 pub is_like_msvc: bool,
1773 /// Whether a target toolchain is like WASM.
1774 pub is_like_wasm: bool,
1775 /// Whether a target toolchain is like Android, implying a Linux kernel and a Bionic libc
1776 pub is_like_android: bool,
1777 /// Default supported version of DWARF on this platform.
1778 /// Useful because some platforms (osx, bsd) only want up to DWARF2.
1779 pub default_dwarf_version: u32,
1780 /// The MinGW toolchain has a known issue that prevents it from correctly
1781 /// handling COFF object files with more than 2<sup>15</sup> sections. Since each weak
1782 /// symbol needs its own COMDAT section, weak linkage implies a large
1783 /// number sections that easily exceeds the given limit for larger
1784 /// codebases. Consequently we want a way to disallow weak linkage on some
1785 /// platforms.
1786 pub allows_weak_linkage: bool,
1787 /// Whether the linker support rpaths or not. Defaults to false.
1788 pub has_rpath: bool,
1789 /// Whether to disable linking to the default libraries, typically corresponds
1790 /// to `-nodefaultlibs`. Defaults to true.
1791 pub no_default_libraries: bool,
1792 /// Dynamically linked executables can be compiled as position independent
1793 /// if the default relocation model of position independent code is not
1794 /// changed. This is a requirement to take advantage of ASLR, as otherwise
1795 /// the functions in the executable are not randomized and can be used
1796 /// during an exploit of a vulnerability in any code.
1797 pub position_independent_executables: bool,
1798 /// Executables that are both statically linked and position-independent are supported.
1799 pub static_position_independent_executables: bool,
1800 /// Determines if the target always requires using the PLT for indirect
1801 /// library calls or not. This controls the default value of the `-Z plt` flag.
1802 pub plt_by_default: bool,
1803 /// Either partial, full, or off. Full RELRO makes the dynamic linker
1804 /// resolve all symbols at startup and marks the GOT read-only before
1805 /// starting the program, preventing overwriting the GOT.
1806 pub relro_level: RelroLevel,
1807 /// Format that archives should be emitted in. This affects whether we use
1808 /// LLVM to assemble an archive or fall back to the system linker, and
1809 /// currently only "gnu" is used to fall into LLVM. Unknown strings cause
1810 /// the system linker to be used.
1811 pub archive_format: StaticCow<str>,
1812 /// Is asm!() allowed? Defaults to true.
1813 pub allow_asm: bool,
1814 /// Whether the runtime startup code requires the `main` function be passed
1815 /// `argc` and `argv` values.
1816 pub main_needs_argc_argv: bool,
1817
1818 /// Flag indicating whether #[thread_local] is available for this target.
1819 pub has_thread_local: bool,
1820 /// This is mainly for easy compatibility with emscripten.
1821 /// If we give emcc .o files that are actually .bc files it
1822 /// will 'just work'.
1823 pub obj_is_bitcode: bool,
1824 /// Whether the target requires that emitted object code includes bitcode.
1825 pub forces_embed_bitcode: bool,
1826 /// Content of the LLVM cmdline section associated with embedded bitcode.
1827 pub bitcode_llvm_cmdline: StaticCow<str>,
1828
1829 /// Don't use this field; instead use the `.min_atomic_width()` method.
1830 pub min_atomic_width: Option<u64>,
1831
1832 /// Don't use this field; instead use the `.max_atomic_width()` method.
1833 pub max_atomic_width: Option<u64>,
1834
1835 /// Whether the target supports atomic CAS operations natively
1836 pub atomic_cas: bool,
1837
1838 /// Panic strategy: "unwind" or "abort"
1839 pub panic_strategy: PanicStrategy,
1840
1841 /// Whether or not linking dylibs to a static CRT is allowed.
1842 pub crt_static_allows_dylibs: bool,
1843 /// Whether or not the CRT is statically linked by default.
1844 pub crt_static_default: bool,
1845 /// Whether or not crt-static is respected by the compiler (or is a no-op).
1846 pub crt_static_respected: bool,
1847
1848 /// The implementation of stack probes to use.
1849 pub stack_probes: StackProbeType,
1850
1851 /// The minimum alignment for global symbols.
1852 pub min_global_align: Option<u64>,
1853
1854 /// Default number of codegen units to use in debug mode
1855 pub default_codegen_units: Option<u64>,
1856
1857 /// Whether to generate trap instructions in places where optimization would
1858 /// otherwise produce control flow that falls through into unrelated memory.
1859 pub trap_unreachable: bool,
1860
1861 /// This target requires everything to be compiled with LTO to emit a final
1862 /// executable, aka there is no native linker for this target.
1863 pub requires_lto: bool,
1864
1865 /// This target has no support for threads.
1866 pub singlethread: bool,
1867
1868 /// Whether library functions call lowering/optimization is disabled in LLVM
1869 /// for this target unconditionally.
1870 pub no_builtins: bool,
1871
1872 /// The default visibility for symbols in this target should be "hidden"
1873 /// rather than "default"
1874 pub default_hidden_visibility: bool,
1875
1876 /// Whether a .debug_gdb_scripts section will be added to the output object file
1877 pub emit_debug_gdb_scripts: bool,
1878
1879 /// Whether or not to unconditionally `uwtable` attributes on functions,
1880 /// typically because the platform needs to unwind for things like stack
1881 /// unwinders.
1882 pub requires_uwtable: bool,
1883
1884 /// Whether or not to emit `uwtable` attributes on functions if `-C force-unwind-tables`
1885 /// is not specified and `uwtable` is not required on this target.
1886 pub default_uwtable: bool,
1887
1888 /// Whether or not SIMD types are passed by reference in the Rust ABI,
1889 /// typically required if a target can be compiled with a mixed set of
1890 /// target features. This is `true` by default, and `false` for targets like
1891 /// wasm32 where the whole program either has simd or not.
1892 pub simd_types_indirect: bool,
1893
1894 /// Pass a list of symbol which should be exported in the dylib to the linker.
1895 pub limit_rdylib_exports: bool,
1896
1897 /// If set, have the linker export exactly these symbols, instead of using
1898 /// the usual logic to figure this out from the crate itself.
1899 pub override_export_symbols: Option<StaticCow<[StaticCow<str>]>>,
1900
1901 /// Determines how or whether the MergeFunctions LLVM pass should run for
1902 /// this target. Either "disabled", "trampolines", or "aliases".
1903 /// The MergeFunctions pass is generally useful, but some targets may need
1904 /// to opt out. The default is "aliases".
1905 ///
1906 /// Workaround for: <https://github.com/rust-lang/rust/issues/57356>
1907 pub merge_functions: MergeFunctions,
1908
1909 /// Use platform dependent mcount function
1910 pub mcount: StaticCow<str>,
1911
1912 /// LLVM ABI name, corresponds to the '-mabi' parameter available in multilib C compilers
1913 pub llvm_abiname: StaticCow<str>,
1914
1915 /// Whether or not RelaxElfRelocation flag will be passed to the linker
1916 pub relax_elf_relocations: bool,
1917
1918 /// Additional arguments to pass to LLVM, similar to the `-C llvm-args` codegen option.
1919 pub llvm_args: StaticCow<[StaticCow<str>]>,
1920
1921 /// Whether to use legacy .ctors initialization hooks rather than .init_array. Defaults
1922 /// to false (uses .init_array).
1923 pub use_ctors_section: bool,
1924
1925 /// Whether the linker is instructed to add a `GNU_EH_FRAME` ELF header
1926 /// used to locate unwinding information is passed
1927 /// (only has effect if the linker is `ld`-like).
1928 pub eh_frame_header: bool,
1929
1930 /// Is true if the target is an ARM architecture using thumb v1 which allows for
1931 /// thumb and arm interworking.
1932 pub has_thumb_interworking: bool,
1933
1934 /// Which kind of debuginfo is used by this target?
1935 pub debuginfo_kind: DebuginfoKind,
1936 /// How to handle split debug information, if at all. Specifying `None` has
1937 /// target-specific meaning.
1938 pub split_debuginfo: SplitDebuginfo,
1939 /// Which kinds of split debuginfo are supported by the target?
1940 pub supported_split_debuginfo: StaticCow<[SplitDebuginfo]>,
1941
1942 /// The sanitizers supported by this target
1943 ///
1944 /// Note that the support here is at a codegen level. If the machine code with sanitizer
1945 /// enabled can generated on this target, but the necessary supporting libraries are not
1946 /// distributed with the target, the sanitizer should still appear in this list for the target.
1947 pub supported_sanitizers: SanitizerSet,
1948
1949 /// If present it's a default value to use for adjusting the C ABI.
1950 pub default_adjusted_cabi: Option<Abi>,
1951
1952 /// Minimum number of bits in #[repr(C)] enum. Defaults to the size of c_int
1953 pub c_enum_min_bits: Option<u64>,
1954
1955 /// Whether or not the DWARF `.debug_aranges` section should be generated.
1956 pub generate_arange_section: bool,
1957
1958 /// Whether the target supports stack canary checks. `true` by default,
1959 /// since this is most common among tier 1 and tier 2 targets.
1960 pub supports_stack_protector: bool,
1961
1962 /// The name of entry function.
1963 /// Default value is "main"
1964 pub entry_name: StaticCow<str>,
1965
1966 /// The ABI of entry function.
1967 /// Default value is `Conv::C`, i.e. C call convention
1968 pub entry_abi: Conv,
1969
1970 /// Whether the target supports XRay instrumentation.
1971 pub supports_xray: bool,
1972
1973 /// Forces the use of emulated TLS (__emutls_get_address)
1974 pub force_emulated_tls: bool,
1975 }
1976
1977 /// Add arguments for the given flavor and also for its "twin" flavors
1978 /// that have a compatible command line interface.
add_link_args_iter( link_args: &mut LinkArgs, flavor: LinkerFlavor, args: impl Iterator<Item = StaticCow<str>> + Clone, )1979 fn add_link_args_iter(
1980 link_args: &mut LinkArgs,
1981 flavor: LinkerFlavor,
1982 args: impl Iterator<Item = StaticCow<str>> + Clone,
1983 ) {
1984 let mut insert = |flavor| link_args.entry(flavor).or_default().extend(args.clone());
1985 insert(flavor);
1986 match flavor {
1987 LinkerFlavor::Gnu(cc, lld) => {
1988 assert_eq!(lld, Lld::No);
1989 insert(LinkerFlavor::Gnu(cc, Lld::Yes));
1990 }
1991 LinkerFlavor::Darwin(cc, lld) => {
1992 assert_eq!(lld, Lld::No);
1993 insert(LinkerFlavor::Darwin(cc, Lld::Yes));
1994 }
1995 LinkerFlavor::Msvc(lld) => {
1996 assert_eq!(lld, Lld::No);
1997 insert(LinkerFlavor::Msvc(Lld::Yes));
1998 }
1999 LinkerFlavor::WasmLld(..)
2000 | LinkerFlavor::Unix(..)
2001 | LinkerFlavor::EmCc
2002 | LinkerFlavor::Bpf
2003 | LinkerFlavor::Ptx => {}
2004 }
2005 }
2006
add_link_args(link_args: &mut LinkArgs, flavor: LinkerFlavor, args: &[&'static str])2007 fn add_link_args(link_args: &mut LinkArgs, flavor: LinkerFlavor, args: &[&'static str]) {
2008 add_link_args_iter(link_args, flavor, args.iter().copied().map(Cow::Borrowed))
2009 }
2010
2011 impl TargetOptions {
link_args(flavor: LinkerFlavor, args: &[&'static str]) -> LinkArgs2012 fn link_args(flavor: LinkerFlavor, args: &[&'static str]) -> LinkArgs {
2013 let mut link_args = LinkArgs::new();
2014 add_link_args(&mut link_args, flavor, args);
2015 link_args
2016 }
2017
add_pre_link_args(&mut self, flavor: LinkerFlavor, args: &[&'static str])2018 fn add_pre_link_args(&mut self, flavor: LinkerFlavor, args: &[&'static str]) {
2019 add_link_args(&mut self.pre_link_args, flavor, args);
2020 }
2021
add_post_link_args(&mut self, flavor: LinkerFlavor, args: &[&'static str])2022 fn add_post_link_args(&mut self, flavor: LinkerFlavor, args: &[&'static str]) {
2023 add_link_args(&mut self.post_link_args, flavor, args);
2024 }
2025
update_from_cli(&mut self)2026 fn update_from_cli(&mut self) {
2027 self.linker_flavor = LinkerFlavor::from_cli_json(
2028 self.linker_flavor_json,
2029 self.lld_flavor_json,
2030 self.linker_is_gnu_json,
2031 );
2032 for (args, args_json) in [
2033 (&mut self.pre_link_args, &self.pre_link_args_json),
2034 (&mut self.late_link_args, &self.late_link_args_json),
2035 (&mut self.late_link_args_dynamic, &self.late_link_args_dynamic_json),
2036 (&mut self.late_link_args_static, &self.late_link_args_static_json),
2037 (&mut self.post_link_args, &self.post_link_args_json),
2038 ] {
2039 args.clear();
2040 for (flavor, args_json) in args_json {
2041 let linker_flavor = self.linker_flavor.with_cli_hints(*flavor);
2042 // Normalize to no lld to avoid asserts.
2043 let linker_flavor = match linker_flavor {
2044 LinkerFlavor::Gnu(cc, _) => LinkerFlavor::Gnu(cc, Lld::No),
2045 LinkerFlavor::Darwin(cc, _) => LinkerFlavor::Darwin(cc, Lld::No),
2046 LinkerFlavor::Msvc(_) => LinkerFlavor::Msvc(Lld::No),
2047 _ => linker_flavor,
2048 };
2049 if !args.contains_key(&linker_flavor) {
2050 add_link_args_iter(args, linker_flavor, args_json.iter().cloned());
2051 }
2052 }
2053 }
2054 }
2055
update_to_cli(&mut self)2056 fn update_to_cli(&mut self) {
2057 self.linker_flavor_json = self.linker_flavor.to_cli();
2058 self.lld_flavor_json = self.linker_flavor.lld_flavor();
2059 self.linker_is_gnu_json = self.linker_flavor.is_gnu();
2060 for (args, args_json) in [
2061 (&self.pre_link_args, &mut self.pre_link_args_json),
2062 (&self.late_link_args, &mut self.late_link_args_json),
2063 (&self.late_link_args_dynamic, &mut self.late_link_args_dynamic_json),
2064 (&self.late_link_args_static, &mut self.late_link_args_static_json),
2065 (&self.post_link_args, &mut self.post_link_args_json),
2066 ] {
2067 *args_json =
2068 args.iter().map(|(flavor, args)| (flavor.to_cli(), args.clone())).collect();
2069 }
2070 }
2071 }
2072
2073 impl Default for TargetOptions {
2074 /// Creates a set of "sane defaults" for any target. This is still
2075 /// incomplete, and if used for compilation, will certainly not work.
default() -> TargetOptions2076 fn default() -> TargetOptions {
2077 TargetOptions {
2078 is_builtin: false,
2079 endian: Endian::Little,
2080 c_int_width: "32".into(),
2081 os: "none".into(),
2082 env: "".into(),
2083 abi: "".into(),
2084 vendor: "unknown".into(),
2085 linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.into()),
2086 linker_flavor: LinkerFlavor::Gnu(Cc::Yes, Lld::No),
2087 linker_flavor_json: LinkerFlavorCli::Gcc,
2088 lld_flavor_json: LldFlavor::Ld,
2089 linker_is_gnu_json: true,
2090 link_script: None,
2091 asm_args: cvs![],
2092 cpu: "generic".into(),
2093 features: "".into(),
2094 dynamic_linking: false,
2095 dll_tls_export: true,
2096 only_cdylib: false,
2097 executables: true,
2098 relocation_model: RelocModel::Pic,
2099 code_model: None,
2100 tls_model: TlsModel::GeneralDynamic,
2101 disable_redzone: false,
2102 frame_pointer: FramePointer::MayOmit,
2103 function_sections: true,
2104 dll_prefix: "lib".into(),
2105 dll_suffix: ".so".into(),
2106 exe_suffix: "".into(),
2107 staticlib_prefix: "lib".into(),
2108 staticlib_suffix: ".a".into(),
2109 families: cvs![],
2110 abi_return_struct_as_int: false,
2111 is_like_aix: false,
2112 is_like_osx: false,
2113 is_like_solaris: false,
2114 is_like_windows: false,
2115 is_like_msvc: false,
2116 is_like_wasm: false,
2117 is_like_android: false,
2118 default_dwarf_version: 4,
2119 allows_weak_linkage: true,
2120 has_rpath: false,
2121 no_default_libraries: true,
2122 position_independent_executables: false,
2123 static_position_independent_executables: false,
2124 plt_by_default: true,
2125 relro_level: RelroLevel::None,
2126 pre_link_objects: Default::default(),
2127 post_link_objects: Default::default(),
2128 pre_link_objects_self_contained: Default::default(),
2129 post_link_objects_self_contained: Default::default(),
2130 link_self_contained: LinkSelfContainedDefault::False,
2131 pre_link_args: LinkArgs::new(),
2132 pre_link_args_json: LinkArgsCli::new(),
2133 late_link_args: LinkArgs::new(),
2134 late_link_args_json: LinkArgsCli::new(),
2135 late_link_args_dynamic: LinkArgs::new(),
2136 late_link_args_dynamic_json: LinkArgsCli::new(),
2137 late_link_args_static: LinkArgs::new(),
2138 late_link_args_static_json: LinkArgsCli::new(),
2139 post_link_args: LinkArgs::new(),
2140 post_link_args_json: LinkArgsCli::new(),
2141 link_env: cvs![],
2142 link_env_remove: cvs![],
2143 archive_format: "gnu".into(),
2144 main_needs_argc_argv: true,
2145 allow_asm: true,
2146 has_thread_local: false,
2147 obj_is_bitcode: false,
2148 forces_embed_bitcode: false,
2149 bitcode_llvm_cmdline: "".into(),
2150 min_atomic_width: None,
2151 max_atomic_width: None,
2152 atomic_cas: true,
2153 panic_strategy: PanicStrategy::Unwind,
2154 crt_static_allows_dylibs: false,
2155 crt_static_default: false,
2156 crt_static_respected: false,
2157 stack_probes: StackProbeType::None,
2158 min_global_align: None,
2159 default_codegen_units: None,
2160 trap_unreachable: true,
2161 requires_lto: false,
2162 singlethread: false,
2163 no_builtins: false,
2164 default_hidden_visibility: false,
2165 emit_debug_gdb_scripts: true,
2166 requires_uwtable: false,
2167 default_uwtable: false,
2168 simd_types_indirect: true,
2169 limit_rdylib_exports: true,
2170 override_export_symbols: None,
2171 merge_functions: MergeFunctions::Aliases,
2172 mcount: "mcount".into(),
2173 llvm_abiname: "".into(),
2174 relax_elf_relocations: false,
2175 llvm_args: cvs![],
2176 use_ctors_section: false,
2177 eh_frame_header: true,
2178 has_thumb_interworking: false,
2179 debuginfo_kind: Default::default(),
2180 split_debuginfo: Default::default(),
2181 // `Off` is supported by default, but targets can remove this manually, e.g. Windows.
2182 supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
2183 supported_sanitizers: SanitizerSet::empty(),
2184 default_adjusted_cabi: None,
2185 c_enum_min_bits: None,
2186 generate_arange_section: true,
2187 supports_stack_protector: true,
2188 entry_name: "main".into(),
2189 entry_abi: Conv::C,
2190 supports_xray: false,
2191 force_emulated_tls: false,
2192 }
2193 }
2194 }
2195
2196 /// `TargetOptions` being a separate type is basically an implementation detail of `Target` that is
2197 /// used for providing defaults. Perhaps there's a way to merge `TargetOptions` into `Target` so
2198 /// this `Deref` implementation is no longer necessary.
2199 impl Deref for Target {
2200 type Target = TargetOptions;
2201
2202 #[inline]
deref(&self) -> &Self::Target2203 fn deref(&self) -> &Self::Target {
2204 &self.options
2205 }
2206 }
2207 impl DerefMut for Target {
2208 #[inline]
deref_mut(&mut self) -> &mut Self::Target2209 fn deref_mut(&mut self) -> &mut Self::Target {
2210 &mut self.options
2211 }
2212 }
2213
2214 impl Target {
2215 /// Given a function ABI, turn it into the correct ABI for this target.
adjust_abi(&self, abi: Abi) -> Abi2216 pub fn adjust_abi(&self, abi: Abi) -> Abi {
2217 match abi {
2218 Abi::C { .. } => self.default_adjusted_cabi.unwrap_or(abi),
2219 Abi::System { unwind } if self.is_like_windows && self.arch == "x86" => {
2220 Abi::Stdcall { unwind }
2221 }
2222 Abi::System { unwind } => Abi::C { unwind },
2223 Abi::EfiApi if self.arch == "arm" => Abi::Aapcs { unwind: false },
2224 Abi::EfiApi if self.arch == "x86_64" => Abi::Win64 { unwind: false },
2225 Abi::EfiApi => Abi::C { unwind: false },
2226
2227 // See commentary in `is_abi_supported`.
2228 Abi::Stdcall { .. } | Abi::Thiscall { .. } if self.arch == "x86" => abi,
2229 Abi::Stdcall { unwind } | Abi::Thiscall { unwind } => Abi::C { unwind },
2230 Abi::Fastcall { .. } if self.arch == "x86" => abi,
2231 Abi::Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => abi,
2232 Abi::Fastcall { unwind } | Abi::Vectorcall { unwind } => Abi::C { unwind },
2233
2234 abi => abi,
2235 }
2236 }
2237
2238 /// Returns a None if the UNSUPPORTED_CALLING_CONVENTIONS lint should be emitted
is_abi_supported(&self, abi: Abi) -> Option<bool>2239 pub fn is_abi_supported(&self, abi: Abi) -> Option<bool> {
2240 use Abi::*;
2241 Some(match abi {
2242 Rust
2243 | C { .. }
2244 | System { .. }
2245 | RustIntrinsic
2246 | RustCall
2247 | PlatformIntrinsic
2248 | Unadjusted
2249 | Cdecl { .. }
2250 | RustCold => true,
2251 EfiApi => {
2252 ["arm", "aarch64", "riscv32", "riscv64", "x86", "x86_64"].contains(&&self.arch[..])
2253 }
2254 X86Interrupt => ["x86", "x86_64"].contains(&&self.arch[..]),
2255 Aapcs { .. } => "arm" == self.arch,
2256 CCmseNonSecureCall => ["arm", "aarch64"].contains(&&self.arch[..]),
2257 Win64 { .. } | SysV64 { .. } => self.arch == "x86_64",
2258 PtxKernel => self.arch == "nvptx64",
2259 Msp430Interrupt => self.arch == "msp430",
2260 AmdGpuKernel => self.arch == "amdgcn",
2261 AvrInterrupt | AvrNonBlockingInterrupt => self.arch == "avr",
2262 Wasm => ["wasm32", "wasm64"].contains(&&self.arch[..]),
2263 Thiscall { .. } => self.arch == "x86",
2264 // On windows these fall-back to platform native calling convention (C) when the
2265 // architecture is not supported.
2266 //
2267 // This is I believe a historical accident that has occurred as part of Microsoft
2268 // striving to allow most of the code to "just" compile when support for 64-bit x86
2269 // was added and then later again, when support for ARM architectures was added.
2270 //
2271 // This is well documented across MSDN. Support for this in Rust has been added in
2272 // #54576. This makes much more sense in context of Microsoft's C++ than it does in
2273 // Rust, but there isn't much leeway remaining here to change it back at the time this
2274 // comment has been written.
2275 //
2276 // Following are the relevant excerpts from the MSDN documentation.
2277 //
2278 // > The __vectorcall calling convention is only supported in native code on x86 and
2279 // x64 processors that include Streaming SIMD Extensions 2 (SSE2) and above.
2280 // > ...
2281 // > On ARM machines, __vectorcall is accepted and ignored by the compiler.
2282 //
2283 // -- https://docs.microsoft.com/en-us/cpp/cpp/vectorcall?view=msvc-160
2284 //
2285 // > On ARM and x64 processors, __stdcall is accepted and ignored by the compiler;
2286 //
2287 // -- https://docs.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-160
2288 //
2289 // > In most cases, keywords or compiler switches that specify an unsupported
2290 // > convention on a particular platform are ignored, and the platform default
2291 // > convention is used.
2292 //
2293 // -- https://docs.microsoft.com/en-us/cpp/cpp/argument-passing-and-naming-conventions
2294 Stdcall { .. } | Fastcall { .. } | Vectorcall { .. } if self.is_like_windows => true,
2295 // Outside of Windows we want to only support these calling conventions for the
2296 // architectures for which these calling conventions are actually well defined.
2297 Stdcall { .. } | Fastcall { .. } if self.arch == "x86" => true,
2298 Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => true,
2299 // Return a `None` for other cases so that we know to emit a future compat lint.
2300 Stdcall { .. } | Fastcall { .. } | Vectorcall { .. } => return None,
2301 })
2302 }
2303
2304 /// Minimum integer size in bits that this target can perform atomic
2305 /// operations on.
min_atomic_width(&self) -> u642306 pub fn min_atomic_width(&self) -> u64 {
2307 self.min_atomic_width.unwrap_or(8)
2308 }
2309
2310 /// Maximum integer size in bits that this target can perform atomic
2311 /// operations on.
max_atomic_width(&self) -> u642312 pub fn max_atomic_width(&self) -> u64 {
2313 self.max_atomic_width.unwrap_or_else(|| self.pointer_width.into())
2314 }
2315
2316 /// Loads a target descriptor from a JSON object.
from_json(obj: Json) -> Result<(Target, TargetWarnings), String>2317 pub fn from_json(obj: Json) -> Result<(Target, TargetWarnings), String> {
2318 // While ugly, this code must remain this way to retain
2319 // compatibility with existing JSON fields and the internal
2320 // expected naming of the Target and TargetOptions structs.
2321 // To ensure compatibility is retained, the built-in targets
2322 // are round-tripped through this code to catch cases where
2323 // the JSON parser is not updated to match the structs.
2324
2325 let mut obj = match obj {
2326 Value::Object(obj) => obj,
2327 _ => return Err("Expected JSON object for target")?,
2328 };
2329
2330 let mut get_req_field = |name: &str| {
2331 obj.remove(name)
2332 .and_then(|j| j.as_str().map(str::to_string))
2333 .ok_or_else(|| format!("Field {name} in target specification is required"))
2334 };
2335
2336 let mut base = Target {
2337 llvm_target: get_req_field("llvm-target")?.into(),
2338 pointer_width: get_req_field("target-pointer-width")?
2339 .parse::<u32>()
2340 .map_err(|_| "target-pointer-width must be an integer".to_string())?,
2341 data_layout: get_req_field("data-layout")?.into(),
2342 arch: get_req_field("arch")?.into(),
2343 options: Default::default(),
2344 };
2345
2346 let mut incorrect_type = vec![];
2347
2348 macro_rules! key {
2349 ($key_name:ident) => ( {
2350 let name = (stringify!($key_name)).replace("_", "-");
2351 if let Some(s) = obj.remove(&name).and_then(|s| s.as_str().map(str::to_string).map(Cow::from)) {
2352 base.$key_name = s;
2353 }
2354 } );
2355 ($key_name:ident = $json_name:expr) => ( {
2356 let name = $json_name;
2357 if let Some(s) = obj.remove(name).and_then(|s| s.as_str().map(str::to_string).map(Cow::from)) {
2358 base.$key_name = s;
2359 }
2360 } );
2361 ($key_name:ident, bool) => ( {
2362 let name = (stringify!($key_name)).replace("_", "-");
2363 if let Some(s) = obj.remove(&name).and_then(|b| b.as_bool()) {
2364 base.$key_name = s;
2365 }
2366 } );
2367 ($key_name:ident = $json_name:expr, bool) => ( {
2368 let name = $json_name;
2369 if let Some(s) = obj.remove(name).and_then(|b| b.as_bool()) {
2370 base.$key_name = s;
2371 }
2372 } );
2373 ($key_name:ident, u32) => ( {
2374 let name = (stringify!($key_name)).replace("_", "-");
2375 if let Some(s) = obj.remove(&name).and_then(|b| b.as_u64()) {
2376 if s < 1 || s > 5 {
2377 return Err("Not a valid DWARF version number".into());
2378 }
2379 base.$key_name = s as u32;
2380 }
2381 } );
2382 ($key_name:ident, Option<u64>) => ( {
2383 let name = (stringify!($key_name)).replace("_", "-");
2384 if let Some(s) = obj.remove(&name).and_then(|b| b.as_u64()) {
2385 base.$key_name = Some(s);
2386 }
2387 } );
2388 ($key_name:ident, MergeFunctions) => ( {
2389 let name = (stringify!($key_name)).replace("_", "-");
2390 obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
2391 match s.parse::<MergeFunctions>() {
2392 Ok(mergefunc) => base.$key_name = mergefunc,
2393 _ => return Some(Err(format!("'{}' is not a valid value for \
2394 merge-functions. Use 'disabled', \
2395 'trampolines', or 'aliases'.",
2396 s))),
2397 }
2398 Some(Ok(()))
2399 })).unwrap_or(Ok(()))
2400 } );
2401 ($key_name:ident, RelocModel) => ( {
2402 let name = (stringify!($key_name)).replace("_", "-");
2403 obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
2404 match s.parse::<RelocModel>() {
2405 Ok(relocation_model) => base.$key_name = relocation_model,
2406 _ => return Some(Err(format!("'{}' is not a valid relocation model. \
2407 Run `rustc --print relocation-models` to \
2408 see the list of supported values.", s))),
2409 }
2410 Some(Ok(()))
2411 })).unwrap_or(Ok(()))
2412 } );
2413 ($key_name:ident, CodeModel) => ( {
2414 let name = (stringify!($key_name)).replace("_", "-");
2415 obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
2416 match s.parse::<CodeModel>() {
2417 Ok(code_model) => base.$key_name = Some(code_model),
2418 _ => return Some(Err(format!("'{}' is not a valid code model. \
2419 Run `rustc --print code-models` to \
2420 see the list of supported values.", s))),
2421 }
2422 Some(Ok(()))
2423 })).unwrap_or(Ok(()))
2424 } );
2425 ($key_name:ident, TlsModel) => ( {
2426 let name = (stringify!($key_name)).replace("_", "-");
2427 obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
2428 match s.parse::<TlsModel>() {
2429 Ok(tls_model) => base.$key_name = tls_model,
2430 _ => return Some(Err(format!("'{}' is not a valid TLS model. \
2431 Run `rustc --print tls-models` to \
2432 see the list of supported values.", s))),
2433 }
2434 Some(Ok(()))
2435 })).unwrap_or(Ok(()))
2436 } );
2437 ($key_name:ident, PanicStrategy) => ( {
2438 let name = (stringify!($key_name)).replace("_", "-");
2439 obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
2440 match s {
2441 "unwind" => base.$key_name = PanicStrategy::Unwind,
2442 "abort" => base.$key_name = PanicStrategy::Abort,
2443 _ => return Some(Err(format!("'{}' is not a valid value for \
2444 panic-strategy. Use 'unwind' or 'abort'.",
2445 s))),
2446 }
2447 Some(Ok(()))
2448 })).unwrap_or(Ok(()))
2449 } );
2450 ($key_name:ident, RelroLevel) => ( {
2451 let name = (stringify!($key_name)).replace("_", "-");
2452 obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
2453 match s.parse::<RelroLevel>() {
2454 Ok(level) => base.$key_name = level,
2455 _ => return Some(Err(format!("'{}' is not a valid value for \
2456 relro-level. Use 'full', 'partial, or 'off'.",
2457 s))),
2458 }
2459 Some(Ok(()))
2460 })).unwrap_or(Ok(()))
2461 } );
2462 ($key_name:ident, DebuginfoKind) => ( {
2463 let name = (stringify!($key_name)).replace("_", "-");
2464 obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
2465 match s.parse::<DebuginfoKind>() {
2466 Ok(level) => base.$key_name = level,
2467 _ => return Some(Err(
2468 format!("'{s}' is not a valid value for debuginfo-kind. Use 'dwarf', \
2469 'dwarf-dsym' or 'pdb'.")
2470 )),
2471 }
2472 Some(Ok(()))
2473 })).unwrap_or(Ok(()))
2474 } );
2475 ($key_name:ident, SplitDebuginfo) => ( {
2476 let name = (stringify!($key_name)).replace("_", "-");
2477 obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
2478 match s.parse::<SplitDebuginfo>() {
2479 Ok(level) => base.$key_name = level,
2480 _ => return Some(Err(format!("'{}' is not a valid value for \
2481 split-debuginfo. Use 'off' or 'dsymutil'.",
2482 s))),
2483 }
2484 Some(Ok(()))
2485 })).unwrap_or(Ok(()))
2486 } );
2487 ($key_name:ident, list) => ( {
2488 let name = (stringify!($key_name)).replace("_", "-");
2489 if let Some(j) = obj.remove(&name) {
2490 if let Some(v) = j.as_array() {
2491 base.$key_name = v.iter()
2492 .map(|a| a.as_str().unwrap().to_string().into())
2493 .collect();
2494 } else {
2495 incorrect_type.push(name)
2496 }
2497 }
2498 } );
2499 ($key_name:ident, opt_list) => ( {
2500 let name = (stringify!($key_name)).replace("_", "-");
2501 if let Some(j) = obj.remove(&name) {
2502 if let Some(v) = j.as_array() {
2503 base.$key_name = Some(v.iter()
2504 .map(|a| a.as_str().unwrap().to_string().into())
2505 .collect());
2506 } else {
2507 incorrect_type.push(name)
2508 }
2509 }
2510 } );
2511 ($key_name:ident, fallible_list) => ( {
2512 let name = (stringify!($key_name)).replace("_", "-");
2513 obj.remove(&name).and_then(|j| {
2514 if let Some(v) = j.as_array() {
2515 match v.iter().map(|a| FromStr::from_str(a.as_str().unwrap())).collect() {
2516 Ok(l) => { base.$key_name = l },
2517 // FIXME: `fallible_list` can't re-use the `key!` macro for list
2518 // elements and the error messages from that macro, so it has a bad
2519 // generic message instead
2520 Err(_) => return Some(Err(
2521 format!("`{:?}` is not a valid value for `{}`", j, name)
2522 )),
2523 }
2524 } else {
2525 incorrect_type.push(name)
2526 }
2527 Some(Ok(()))
2528 }).unwrap_or(Ok(()))
2529 } );
2530 ($key_name:ident, optional) => ( {
2531 let name = (stringify!($key_name)).replace("_", "-");
2532 if let Some(o) = obj.remove(&name) {
2533 base.$key_name = o
2534 .as_str()
2535 .map(|s| s.to_string().into());
2536 }
2537 } );
2538 ($key_name:ident = $json_name:expr, LldFlavor) => ( {
2539 let name = $json_name;
2540 obj.remove(name).and_then(|o| o.as_str().and_then(|s| {
2541 if let Some(flavor) = LldFlavor::from_str(&s) {
2542 base.$key_name = flavor;
2543 } else {
2544 return Some(Err(format!(
2545 "'{}' is not a valid value for lld-flavor. \
2546 Use 'darwin', 'gnu', 'link' or 'wasm'.",
2547 s)))
2548 }
2549 Some(Ok(()))
2550 })).unwrap_or(Ok(()))
2551 } );
2552 ($key_name:ident = $json_name:expr, LinkerFlavor) => ( {
2553 let name = $json_name;
2554 obj.remove(name).and_then(|o| o.as_str().and_then(|s| {
2555 match LinkerFlavorCli::from_str(s) {
2556 Some(linker_flavor) => base.$key_name = linker_flavor,
2557 _ => return Some(Err(format!("'{}' is not a valid value for linker-flavor. \
2558 Use {}", s, LinkerFlavorCli::one_of()))),
2559 }
2560 Some(Ok(()))
2561 })).unwrap_or(Ok(()))
2562 } );
2563 ($key_name:ident, StackProbeType) => ( {
2564 let name = (stringify!($key_name)).replace("_", "-");
2565 obj.remove(&name).and_then(|o| match StackProbeType::from_json(&o) {
2566 Ok(v) => {
2567 base.$key_name = v;
2568 Some(Ok(()))
2569 },
2570 Err(s) => Some(Err(
2571 format!("`{:?}` is not a valid value for `{}`: {}", o, name, s)
2572 )),
2573 }).unwrap_or(Ok(()))
2574 } );
2575 ($key_name:ident, SanitizerSet) => ( {
2576 let name = (stringify!($key_name)).replace("_", "-");
2577 if let Some(o) = obj.remove(&name) {
2578 if let Some(a) = o.as_array() {
2579 for s in a {
2580 base.$key_name |= match s.as_str() {
2581 Some("address") => SanitizerSet::ADDRESS,
2582 Some("cfi") => SanitizerSet::CFI,
2583 Some("kcfi") => SanitizerSet::KCFI,
2584 Some("kernel-address") => SanitizerSet::KERNELADDRESS,
2585 Some("leak") => SanitizerSet::LEAK,
2586 Some("memory") => SanitizerSet::MEMORY,
2587 Some("memtag") => SanitizerSet::MEMTAG,
2588 Some("safestack") => SanitizerSet::SAFESTACK,
2589 Some("shadow-call-stack") => SanitizerSet::SHADOWCALLSTACK,
2590 Some("thread") => SanitizerSet::THREAD,
2591 Some("hwaddress") => SanitizerSet::HWADDRESS,
2592 Some(s) => return Err(format!("unknown sanitizer {}", s)),
2593 _ => return Err(format!("not a string: {:?}", s)),
2594 };
2595 }
2596 } else {
2597 incorrect_type.push(name)
2598 }
2599 }
2600 Ok::<(), String>(())
2601 } );
2602
2603 ($key_name:ident = $json_name:expr, link_self_contained) => ( {
2604 let name = $json_name;
2605 obj.remove(name).and_then(|o| o.as_str().and_then(|s| {
2606 match s.parse::<LinkSelfContainedDefault>() {
2607 Ok(lsc_default) => base.$key_name = lsc_default,
2608 _ => return Some(Err(format!("'{}' is not a valid `-Clink-self-contained` default. \
2609 Use 'false', 'true', 'musl' or 'mingw'", s))),
2610 }
2611 Some(Ok(()))
2612 })).unwrap_or(Ok(()))
2613 } );
2614 ($key_name:ident = $json_name:expr, link_objects) => ( {
2615 let name = $json_name;
2616 if let Some(val) = obj.remove(name) {
2617 let obj = val.as_object().ok_or_else(|| format!("{}: expected a \
2618 JSON object with fields per CRT object kind.", name))?;
2619 let mut args = CrtObjects::new();
2620 for (k, v) in obj {
2621 let kind = LinkOutputKind::from_str(&k).ok_or_else(|| {
2622 format!("{}: '{}' is not a valid value for CRT object kind. \
2623 Use '(dynamic,static)-(nopic,pic)-exe' or \
2624 '(dynamic,static)-dylib' or 'wasi-reactor-exe'", name, k)
2625 })?;
2626
2627 let v = v.as_array().ok_or_else(||
2628 format!("{}.{}: expected a JSON array", name, k)
2629 )?.iter().enumerate()
2630 .map(|(i,s)| {
2631 let s = s.as_str().ok_or_else(||
2632 format!("{}.{}[{}]: expected a JSON string", name, k, i))?;
2633 Ok(s.to_string().into())
2634 })
2635 .collect::<Result<Vec<_>, String>>()?;
2636
2637 args.insert(kind, v);
2638 }
2639 base.$key_name = args;
2640 }
2641 } );
2642 ($key_name:ident = $json_name:expr, link_args) => ( {
2643 let name = $json_name;
2644 if let Some(val) = obj.remove(name) {
2645 let obj = val.as_object().ok_or_else(|| format!("{}: expected a \
2646 JSON object with fields per linker-flavor.", name))?;
2647 let mut args = LinkArgsCli::new();
2648 for (k, v) in obj {
2649 let flavor = LinkerFlavorCli::from_str(&k).ok_or_else(|| {
2650 format!("{}: '{}' is not a valid value for linker-flavor. \
2651 Use 'em', 'gcc', 'ld' or 'msvc'", name, k)
2652 })?;
2653
2654 let v = v.as_array().ok_or_else(||
2655 format!("{}.{}: expected a JSON array", name, k)
2656 )?.iter().enumerate()
2657 .map(|(i,s)| {
2658 let s = s.as_str().ok_or_else(||
2659 format!("{}.{}[{}]: expected a JSON string", name, k, i))?;
2660 Ok(s.to_string().into())
2661 })
2662 .collect::<Result<Vec<_>, String>>()?;
2663
2664 args.insert(flavor, v);
2665 }
2666 base.$key_name = args;
2667 }
2668 } );
2669 ($key_name:ident, env) => ( {
2670 let name = (stringify!($key_name)).replace("_", "-");
2671 if let Some(o) = obj.remove(&name) {
2672 if let Some(a) = o.as_array() {
2673 for o in a {
2674 if let Some(s) = o.as_str() {
2675 let p = s.split('=').collect::<Vec<_>>();
2676 if p.len() == 2 {
2677 let k = p[0].to_string();
2678 let v = p[1].to_string();
2679 base.$key_name.to_mut().push((k.into(), v.into()));
2680 }
2681 }
2682 }
2683 } else {
2684 incorrect_type.push(name)
2685 }
2686 }
2687 } );
2688 ($key_name:ident, Option<Abi>) => ( {
2689 let name = (stringify!($key_name)).replace("_", "-");
2690 obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
2691 match lookup_abi(s) {
2692 Some(abi) => base.$key_name = Some(abi),
2693 _ => return Some(Err(format!("'{}' is not a valid value for abi", s))),
2694 }
2695 Some(Ok(()))
2696 })).unwrap_or(Ok(()))
2697 } );
2698 ($key_name:ident, TargetFamilies) => ( {
2699 if let Some(value) = obj.remove("target-family") {
2700 if let Some(v) = value.as_array() {
2701 base.$key_name = v.iter()
2702 .map(|a| a.as_str().unwrap().to_string().into())
2703 .collect();
2704 } else if let Some(v) = value.as_str() {
2705 base.$key_name = vec![v.to_string().into()].into();
2706 }
2707 }
2708 } );
2709 ($key_name:ident, Conv) => ( {
2710 let name = (stringify!($key_name)).replace("_", "-");
2711 obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
2712 match Conv::from_str(s) {
2713 Ok(c) => {
2714 base.$key_name = c;
2715 Some(Ok(()))
2716 }
2717 Err(e) => Some(Err(e))
2718 }
2719 })).unwrap_or(Ok(()))
2720 } );
2721 }
2722
2723 if let Some(j) = obj.remove("target-endian") {
2724 if let Some(s) = j.as_str() {
2725 base.endian = s.parse()?;
2726 } else {
2727 incorrect_type.push("target-endian".into())
2728 }
2729 }
2730
2731 if let Some(fp) = obj.remove("frame-pointer") {
2732 if let Some(s) = fp.as_str() {
2733 base.frame_pointer = s
2734 .parse()
2735 .map_err(|()| format!("'{s}' is not a valid value for frame-pointer"))?;
2736 } else {
2737 incorrect_type.push("frame-pointer".into())
2738 }
2739 }
2740
2741 key!(is_builtin, bool);
2742 key!(c_int_width = "target-c-int-width");
2743 key!(c_enum_min_bits, Option<u64>); // if None, matches c_int_width
2744 key!(os);
2745 key!(env);
2746 key!(abi);
2747 key!(vendor);
2748 key!(linker, optional);
2749 key!(linker_flavor_json = "linker-flavor", LinkerFlavor)?;
2750 key!(lld_flavor_json = "lld-flavor", LldFlavor)?;
2751 key!(linker_is_gnu_json = "linker-is-gnu", bool);
2752 key!(pre_link_objects = "pre-link-objects", link_objects);
2753 key!(post_link_objects = "post-link-objects", link_objects);
2754 key!(pre_link_objects_self_contained = "pre-link-objects-fallback", link_objects);
2755 key!(post_link_objects_self_contained = "post-link-objects-fallback", link_objects);
2756 key!(link_self_contained = "crt-objects-fallback", link_self_contained)?;
2757 key!(pre_link_args_json = "pre-link-args", link_args);
2758 key!(late_link_args_json = "late-link-args", link_args);
2759 key!(late_link_args_dynamic_json = "late-link-args-dynamic", link_args);
2760 key!(late_link_args_static_json = "late-link-args-static", link_args);
2761 key!(post_link_args_json = "post-link-args", link_args);
2762 key!(link_script, optional);
2763 key!(link_env, env);
2764 key!(link_env_remove, list);
2765 key!(asm_args, list);
2766 key!(cpu);
2767 key!(features);
2768 key!(dynamic_linking, bool);
2769 key!(dll_tls_export, bool);
2770 key!(only_cdylib, bool);
2771 key!(executables, bool);
2772 key!(relocation_model, RelocModel)?;
2773 key!(code_model, CodeModel)?;
2774 key!(tls_model, TlsModel)?;
2775 key!(disable_redzone, bool);
2776 key!(function_sections, bool);
2777 key!(dll_prefix);
2778 key!(dll_suffix);
2779 key!(exe_suffix);
2780 key!(staticlib_prefix);
2781 key!(staticlib_suffix);
2782 key!(families, TargetFamilies);
2783 key!(abi_return_struct_as_int, bool);
2784 key!(is_like_aix, bool);
2785 key!(is_like_osx, bool);
2786 key!(is_like_solaris, bool);
2787 key!(is_like_windows, bool);
2788 key!(is_like_msvc, bool);
2789 key!(is_like_wasm, bool);
2790 key!(is_like_android, bool);
2791 key!(default_dwarf_version, u32);
2792 key!(allows_weak_linkage, bool);
2793 key!(has_rpath, bool);
2794 key!(no_default_libraries, bool);
2795 key!(position_independent_executables, bool);
2796 key!(static_position_independent_executables, bool);
2797 key!(plt_by_default, bool);
2798 key!(relro_level, RelroLevel)?;
2799 key!(archive_format);
2800 key!(allow_asm, bool);
2801 key!(main_needs_argc_argv, bool);
2802 key!(has_thread_local, bool);
2803 key!(obj_is_bitcode, bool);
2804 key!(forces_embed_bitcode, bool);
2805 key!(bitcode_llvm_cmdline);
2806 key!(max_atomic_width, Option<u64>);
2807 key!(min_atomic_width, Option<u64>);
2808 key!(atomic_cas, bool);
2809 key!(panic_strategy, PanicStrategy)?;
2810 key!(crt_static_allows_dylibs, bool);
2811 key!(crt_static_default, bool);
2812 key!(crt_static_respected, bool);
2813 key!(stack_probes, StackProbeType)?;
2814 key!(min_global_align, Option<u64>);
2815 key!(default_codegen_units, Option<u64>);
2816 key!(trap_unreachable, bool);
2817 key!(requires_lto, bool);
2818 key!(singlethread, bool);
2819 key!(no_builtins, bool);
2820 key!(default_hidden_visibility, bool);
2821 key!(emit_debug_gdb_scripts, bool);
2822 key!(requires_uwtable, bool);
2823 key!(default_uwtable, bool);
2824 key!(simd_types_indirect, bool);
2825 key!(limit_rdylib_exports, bool);
2826 key!(override_export_symbols, opt_list);
2827 key!(merge_functions, MergeFunctions)?;
2828 key!(mcount = "target-mcount");
2829 key!(llvm_abiname);
2830 key!(relax_elf_relocations, bool);
2831 key!(llvm_args, list);
2832 key!(use_ctors_section, bool);
2833 key!(eh_frame_header, bool);
2834 key!(has_thumb_interworking, bool);
2835 key!(debuginfo_kind, DebuginfoKind)?;
2836 key!(split_debuginfo, SplitDebuginfo)?;
2837 key!(supported_split_debuginfo, fallible_list)?;
2838 key!(supported_sanitizers, SanitizerSet)?;
2839 key!(default_adjusted_cabi, Option<Abi>)?;
2840 key!(generate_arange_section, bool);
2841 key!(supports_stack_protector, bool);
2842 key!(entry_name);
2843 key!(entry_abi, Conv)?;
2844 key!(supports_xray, bool);
2845 key!(force_emulated_tls, bool);
2846
2847 if base.is_builtin {
2848 // This can cause unfortunate ICEs later down the line.
2849 return Err("may not set is_builtin for targets not built-in".into());
2850 }
2851 base.update_from_cli();
2852
2853 // Each field should have been read using `Json::remove` so any keys remaining are unused.
2854 let remaining_keys = obj.keys();
2855 Ok((
2856 base,
2857 TargetWarnings { unused_fields: remaining_keys.cloned().collect(), incorrect_type },
2858 ))
2859 }
2860
2861 /// Load a built-in target
expect_builtin(target_triple: &TargetTriple) -> Target2862 pub fn expect_builtin(target_triple: &TargetTriple) -> Target {
2863 match *target_triple {
2864 TargetTriple::TargetTriple(ref target_triple) => {
2865 load_builtin(target_triple).expect("built-in target")
2866 }
2867 TargetTriple::TargetJson { .. } => {
2868 panic!("built-in targets doesn't support target-paths")
2869 }
2870 }
2871 }
2872
2873 /// Search for a JSON file specifying the given target triple.
2874 ///
2875 /// If none is found in `$RUST_TARGET_PATH`, look for a file called `target.json` inside the
2876 /// sysroot under the target-triple's `rustlib` directory. Note that it could also just be a
2877 /// bare filename already, so also check for that. If one of the hardcoded targets we know
2878 /// about, just return it directly.
2879 ///
2880 /// The error string could come from any of the APIs called, including filesystem access and
2881 /// JSON decoding.
search( target_triple: &TargetTriple, sysroot: &Path, ) -> Result<(Target, TargetWarnings), String>2882 pub fn search(
2883 target_triple: &TargetTriple,
2884 sysroot: &Path,
2885 ) -> Result<(Target, TargetWarnings), String> {
2886 use std::env;
2887 use std::fs;
2888
2889 fn load_file(path: &Path) -> Result<(Target, TargetWarnings), String> {
2890 let contents = fs::read_to_string(path).map_err(|e| e.to_string())?;
2891 let obj = serde_json::from_str(&contents).map_err(|e| e.to_string())?;
2892 Target::from_json(obj)
2893 }
2894
2895 match *target_triple {
2896 TargetTriple::TargetTriple(ref target_triple) => {
2897 // check if triple is in list of built-in targets
2898 if let Some(t) = load_builtin(target_triple) {
2899 return Ok((t, TargetWarnings::empty()));
2900 }
2901
2902 // search for a file named `target_triple`.json in RUST_TARGET_PATH
2903 let path = {
2904 let mut target = target_triple.to_string();
2905 target.push_str(".json");
2906 PathBuf::from(target)
2907 };
2908
2909 let target_path = env::var_os("RUST_TARGET_PATH").unwrap_or_default();
2910
2911 for dir in env::split_paths(&target_path) {
2912 let p = dir.join(&path);
2913 if p.is_file() {
2914 return load_file(&p);
2915 }
2916 }
2917
2918 // Additionally look in the sysroot under `lib/rustlib/<triple>/target.json`
2919 // as a fallback.
2920 let rustlib_path = crate::target_rustlib_path(sysroot, target_triple);
2921 let p = PathBuf::from_iter([
2922 Path::new(sysroot),
2923 Path::new(&rustlib_path),
2924 Path::new("target.json"),
2925 ]);
2926 if p.is_file() {
2927 return load_file(&p);
2928 }
2929
2930 Err(format!("Could not find specification for target {target_triple:?}"))
2931 }
2932 TargetTriple::TargetJson { ref contents, .. } => {
2933 let obj = serde_json::from_str(contents).map_err(|e| e.to_string())?;
2934 Target::from_json(obj)
2935 }
2936 }
2937 }
2938 }
2939
2940 impl ToJson for Target {
to_json(&self) -> Json2941 fn to_json(&self) -> Json {
2942 let mut d = serde_json::Map::new();
2943 let default: TargetOptions = Default::default();
2944 let mut target = self.clone();
2945 target.update_to_cli();
2946
2947 macro_rules! target_val {
2948 ($attr:ident) => {{
2949 let name = (stringify!($attr)).replace("_", "-");
2950 d.insert(name, target.$attr.to_json());
2951 }};
2952 }
2953
2954 macro_rules! target_option_val {
2955 ($attr:ident) => {{
2956 let name = (stringify!($attr)).replace("_", "-");
2957 if default.$attr != target.$attr {
2958 d.insert(name, target.$attr.to_json());
2959 }
2960 }};
2961 ($attr:ident, $json_name:expr) => {{
2962 let name = $json_name;
2963 if default.$attr != target.$attr {
2964 d.insert(name.into(), target.$attr.to_json());
2965 }
2966 }};
2967 (link_args - $attr:ident, $json_name:expr) => {{
2968 let name = $json_name;
2969 if default.$attr != target.$attr {
2970 let obj = target
2971 .$attr
2972 .iter()
2973 .map(|(k, v)| (k.desc().to_string(), v.clone()))
2974 .collect::<BTreeMap<_, _>>();
2975 d.insert(name.to_string(), obj.to_json());
2976 }
2977 }};
2978 (env - $attr:ident) => {{
2979 let name = (stringify!($attr)).replace("_", "-");
2980 if default.$attr != target.$attr {
2981 let obj = target
2982 .$attr
2983 .iter()
2984 .map(|&(ref k, ref v)| format!("{k}={v}"))
2985 .collect::<Vec<_>>();
2986 d.insert(name, obj.to_json());
2987 }
2988 }};
2989 }
2990
2991 target_val!(llvm_target);
2992 d.insert("target-pointer-width".to_string(), self.pointer_width.to_string().to_json());
2993 target_val!(arch);
2994 target_val!(data_layout);
2995
2996 target_option_val!(is_builtin);
2997 target_option_val!(endian, "target-endian");
2998 target_option_val!(c_int_width, "target-c-int-width");
2999 target_option_val!(os);
3000 target_option_val!(env);
3001 target_option_val!(abi);
3002 target_option_val!(vendor);
3003 target_option_val!(linker);
3004 target_option_val!(linker_flavor_json, "linker-flavor");
3005 target_option_val!(lld_flavor_json, "lld-flavor");
3006 target_option_val!(linker_is_gnu_json, "linker-is-gnu");
3007 target_option_val!(pre_link_objects);
3008 target_option_val!(post_link_objects);
3009 target_option_val!(pre_link_objects_self_contained, "pre-link-objects-fallback");
3010 target_option_val!(post_link_objects_self_contained, "post-link-objects-fallback");
3011 target_option_val!(link_self_contained, "crt-objects-fallback");
3012 target_option_val!(link_args - pre_link_args_json, "pre-link-args");
3013 target_option_val!(link_args - late_link_args_json, "late-link-args");
3014 target_option_val!(link_args - late_link_args_dynamic_json, "late-link-args-dynamic");
3015 target_option_val!(link_args - late_link_args_static_json, "late-link-args-static");
3016 target_option_val!(link_args - post_link_args_json, "post-link-args");
3017 target_option_val!(link_script);
3018 target_option_val!(env - link_env);
3019 target_option_val!(link_env_remove);
3020 target_option_val!(asm_args);
3021 target_option_val!(cpu);
3022 target_option_val!(features);
3023 target_option_val!(dynamic_linking);
3024 target_option_val!(dll_tls_export);
3025 target_option_val!(only_cdylib);
3026 target_option_val!(executables);
3027 target_option_val!(relocation_model);
3028 target_option_val!(code_model);
3029 target_option_val!(tls_model);
3030 target_option_val!(disable_redzone);
3031 target_option_val!(frame_pointer);
3032 target_option_val!(function_sections);
3033 target_option_val!(dll_prefix);
3034 target_option_val!(dll_suffix);
3035 target_option_val!(exe_suffix);
3036 target_option_val!(staticlib_prefix);
3037 target_option_val!(staticlib_suffix);
3038 target_option_val!(families, "target-family");
3039 target_option_val!(abi_return_struct_as_int);
3040 target_option_val!(is_like_aix);
3041 target_option_val!(is_like_osx);
3042 target_option_val!(is_like_solaris);
3043 target_option_val!(is_like_windows);
3044 target_option_val!(is_like_msvc);
3045 target_option_val!(is_like_wasm);
3046 target_option_val!(is_like_android);
3047 target_option_val!(default_dwarf_version);
3048 target_option_val!(allows_weak_linkage);
3049 target_option_val!(has_rpath);
3050 target_option_val!(no_default_libraries);
3051 target_option_val!(position_independent_executables);
3052 target_option_val!(static_position_independent_executables);
3053 target_option_val!(plt_by_default);
3054 target_option_val!(relro_level);
3055 target_option_val!(archive_format);
3056 target_option_val!(allow_asm);
3057 target_option_val!(main_needs_argc_argv);
3058 target_option_val!(has_thread_local);
3059 target_option_val!(obj_is_bitcode);
3060 target_option_val!(forces_embed_bitcode);
3061 target_option_val!(bitcode_llvm_cmdline);
3062 target_option_val!(min_atomic_width);
3063 target_option_val!(max_atomic_width);
3064 target_option_val!(atomic_cas);
3065 target_option_val!(panic_strategy);
3066 target_option_val!(crt_static_allows_dylibs);
3067 target_option_val!(crt_static_default);
3068 target_option_val!(crt_static_respected);
3069 target_option_val!(stack_probes);
3070 target_option_val!(min_global_align);
3071 target_option_val!(default_codegen_units);
3072 target_option_val!(trap_unreachable);
3073 target_option_val!(requires_lto);
3074 target_option_val!(singlethread);
3075 target_option_val!(no_builtins);
3076 target_option_val!(default_hidden_visibility);
3077 target_option_val!(emit_debug_gdb_scripts);
3078 target_option_val!(requires_uwtable);
3079 target_option_val!(default_uwtable);
3080 target_option_val!(simd_types_indirect);
3081 target_option_val!(limit_rdylib_exports);
3082 target_option_val!(override_export_symbols);
3083 target_option_val!(merge_functions);
3084 target_option_val!(mcount, "target-mcount");
3085 target_option_val!(llvm_abiname);
3086 target_option_val!(relax_elf_relocations);
3087 target_option_val!(llvm_args);
3088 target_option_val!(use_ctors_section);
3089 target_option_val!(eh_frame_header);
3090 target_option_val!(has_thumb_interworking);
3091 target_option_val!(debuginfo_kind);
3092 target_option_val!(split_debuginfo);
3093 target_option_val!(supported_split_debuginfo);
3094 target_option_val!(supported_sanitizers);
3095 target_option_val!(c_enum_min_bits);
3096 target_option_val!(generate_arange_section);
3097 target_option_val!(supports_stack_protector);
3098 target_option_val!(entry_name);
3099 target_option_val!(entry_abi);
3100 target_option_val!(supports_xray);
3101 target_option_val!(force_emulated_tls);
3102
3103 if let Some(abi) = self.default_adjusted_cabi {
3104 d.insert("default-adjusted-cabi".into(), Abi::name(abi).to_json());
3105 }
3106
3107 Json::Object(d)
3108 }
3109 }
3110
3111 /// Either a target triple string or a path to a JSON file.
3112 #[derive(Clone, Debug)]
3113 pub enum TargetTriple {
3114 TargetTriple(String),
3115 TargetJson {
3116 /// Warning: This field may only be used by rustdoc. Using it anywhere else will lead to
3117 /// inconsistencies as it is discarded during serialization.
3118 path_for_rustdoc: PathBuf,
3119 triple: String,
3120 contents: String,
3121 },
3122 }
3123
3124 // Use a manual implementation to ignore the path field
3125 impl PartialEq for TargetTriple {
eq(&self, other: &Self) -> bool3126 fn eq(&self, other: &Self) -> bool {
3127 match (self, other) {
3128 (Self::TargetTriple(l0), Self::TargetTriple(r0)) => l0 == r0,
3129 (
3130 Self::TargetJson { path_for_rustdoc: _, triple: l_triple, contents: l_contents },
3131 Self::TargetJson { path_for_rustdoc: _, triple: r_triple, contents: r_contents },
3132 ) => l_triple == r_triple && l_contents == r_contents,
3133 _ => false,
3134 }
3135 }
3136 }
3137
3138 // Use a manual implementation to ignore the path field
3139 impl Hash for TargetTriple {
hash<H: Hasher>(&self, state: &mut H) -> ()3140 fn hash<H: Hasher>(&self, state: &mut H) -> () {
3141 match self {
3142 TargetTriple::TargetTriple(triple) => {
3143 0u8.hash(state);
3144 triple.hash(state)
3145 }
3146 TargetTriple::TargetJson { path_for_rustdoc: _, triple, contents } => {
3147 1u8.hash(state);
3148 triple.hash(state);
3149 contents.hash(state)
3150 }
3151 }
3152 }
3153 }
3154
3155 // Use a manual implementation to prevent encoding the target json file path in the crate metadata
3156 impl<S: Encoder> Encodable<S> for TargetTriple {
encode(&self, s: &mut S)3157 fn encode(&self, s: &mut S) {
3158 match self {
3159 TargetTriple::TargetTriple(triple) => s.emit_enum_variant(0, |s| s.emit_str(triple)),
3160 TargetTriple::TargetJson { path_for_rustdoc: _, triple, contents } => s
3161 .emit_enum_variant(1, |s| {
3162 s.emit_str(triple);
3163 s.emit_str(contents)
3164 }),
3165 }
3166 }
3167 }
3168
3169 impl<D: Decoder> Decodable<D> for TargetTriple {
decode(d: &mut D) -> Self3170 fn decode(d: &mut D) -> Self {
3171 match d.read_usize() {
3172 0 => TargetTriple::TargetTriple(d.read_str().to_owned()),
3173 1 => TargetTriple::TargetJson {
3174 path_for_rustdoc: PathBuf::new(),
3175 triple: d.read_str().to_owned(),
3176 contents: d.read_str().to_owned(),
3177 },
3178 _ => {
3179 panic!("invalid enum variant tag while decoding `TargetTriple`, expected 0..2");
3180 }
3181 }
3182 }
3183 }
3184
3185 impl TargetTriple {
3186 /// Creates a target triple from the passed target triple string.
from_triple(triple: &str) -> Self3187 pub fn from_triple(triple: &str) -> Self {
3188 TargetTriple::TargetTriple(triple.into())
3189 }
3190
3191 /// Creates a target triple from the passed target path.
from_path(path: &Path) -> Result<Self, io::Error>3192 pub fn from_path(path: &Path) -> Result<Self, io::Error> {
3193 let canonicalized_path = try_canonicalize(path)?;
3194 let contents = std::fs::read_to_string(&canonicalized_path).map_err(|err| {
3195 io::Error::new(
3196 io::ErrorKind::InvalidInput,
3197 format!("target path {canonicalized_path:?} is not a valid file: {err}"),
3198 )
3199 })?;
3200 let triple = canonicalized_path
3201 .file_stem()
3202 .expect("target path must not be empty")
3203 .to_str()
3204 .expect("target path must be valid unicode")
3205 .to_owned();
3206 Ok(TargetTriple::TargetJson { path_for_rustdoc: canonicalized_path, triple, contents })
3207 }
3208
3209 /// Returns a string triple for this target.
3210 ///
3211 /// If this target is a path, the file name (without extension) is returned.
triple(&self) -> &str3212 pub fn triple(&self) -> &str {
3213 match *self {
3214 TargetTriple::TargetTriple(ref triple)
3215 | TargetTriple::TargetJson { ref triple, .. } => triple,
3216 }
3217 }
3218
3219 /// Returns an extended string triple for this target.
3220 ///
3221 /// If this target is a path, a hash of the path is appended to the triple returned
3222 /// by `triple()`.
debug_triple(&self) -> String3223 pub fn debug_triple(&self) -> String {
3224 use std::collections::hash_map::DefaultHasher;
3225
3226 match self {
3227 TargetTriple::TargetTriple(triple) => triple.to_owned(),
3228 TargetTriple::TargetJson { path_for_rustdoc: _, triple, contents: content } => {
3229 let mut hasher = DefaultHasher::new();
3230 content.hash(&mut hasher);
3231 let hash = hasher.finish();
3232 format!("{triple}-{hash}")
3233 }
3234 }
3235 }
3236 }
3237
3238 impl fmt::Display for TargetTriple {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result3239 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3240 write!(f, "{}", self.debug_triple())
3241 }
3242 }
3243