]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
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 | |
a7813a04 | 20 | //! will be given. |
1a4d82fc JJ |
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 | //! | |
136023e0 | 28 | //! Targets are defined using [JSON](https://json.org/). The `Target` struct in |
1a4d82fc JJ |
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 | |
54a0048b SL |
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. | |
1a4d82fc | 36 | |
5869c6ff | 37 | use crate::abi::Endian; |
923072b8 | 38 | use crate::json::{Json, ToJson}; |
dfeec247 | 39 | use crate::spec::abi::{lookup as lookup_abi, Abi}; |
f9f354fc | 40 | use crate::spec::crt_objects::{CrtObjects, CrtObjectsFallback}; |
cdc7bbd5 | 41 | use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; |
923072b8 | 42 | use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; |
29967ef6 | 43 | use rustc_span::symbol::{sym, Symbol}; |
923072b8 | 44 | use serde_json::Value; |
5e7ed085 | 45 | use std::borrow::Cow; |
5bcae85e | 46 | use std::collections::BTreeMap; |
5869c6ff | 47 | use std::convert::TryFrom; |
923072b8 | 48 | use std::hash::{Hash, Hasher}; |
a2a8927a | 49 | use std::iter::FromIterator; |
29967ef6 | 50 | use std::ops::{Deref, DerefMut}; |
0531ce1d | 51 | use std::path::{Path, PathBuf}; |
83c7162d | 52 | use std::str::FromStr; |
dfeec247 | 53 | use std::{fmt, io}; |
1a4d82fc | 54 | |
60c5eb7d XL |
55 | use rustc_macros::HashStable_Generic; |
56 | ||
83c7162d | 57 | pub mod abi; |
f9f354fc XL |
58 | pub mod crt_objects; |
59 | ||
d9579d0f | 60 | mod android_base; |
1a4d82fc | 61 | mod apple_base; |
ba9703b0 | 62 | mod apple_sdk_base; |
1b1a35ee | 63 | mod avr_gnu_base; |
17df50a5 | 64 | mod bpf_base; |
d9579d0f AL |
65 | mod dragonfly_base; |
66 | mod freebsd_base; | |
dfeec247 | 67 | mod fuchsia_base; |
9e0c209e | 68 | mod haiku_base; |
b7449926 | 69 | mod hermit_base; |
ba9703b0 | 70 | mod illumos_base; |
dfeec247 | 71 | mod l4re_base; |
d9579d0f | 72 | mod linux_base; |
29967ef6 | 73 | mod linux_gnu_base; |
e1599b0c | 74 | mod linux_kernel_base; |
a7813a04 | 75 | mod linux_musl_base; |
29967ef6 | 76 | mod linux_uclibc_base; |
ba9703b0 | 77 | mod msvc_base; |
c1a9b12d | 78 | mod netbsd_base; |
dfeec247 XL |
79 | mod openbsd_base; |
80 | mod redox_base; | |
7453a54e | 81 | mod solaris_base; |
c295e0f8 | 82 | mod solid_base; |
dfeec247 | 83 | mod thumb_base; |
ba9703b0 | 84 | mod uefi_msvc_base; |
dfeec247 | 85 | mod vxworks_base; |
cdc7bbd5 | 86 | mod wasm_base; |
ba9703b0 | 87 | mod windows_gnu_base; |
04454e1e | 88 | mod windows_gnullvm_base; |
62682a34 | 89 | mod windows_msvc_base; |
ba9703b0 | 90 | mod windows_uwp_gnu_base; |
e1599b0c | 91 | mod windows_uwp_msvc_base; |
1a4d82fc | 92 | |
e74abb32 | 93 | #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] |
83c7162d XL |
94 | pub enum LinkerFlavor { |
95 | Em, | |
96 | Gcc, | |
5099ac24 | 97 | L4Bender, |
83c7162d XL |
98 | Ld, |
99 | Msvc, | |
100 | Lld(LldFlavor), | |
9fa01778 | 101 | PtxLinker, |
17df50a5 | 102 | BpfLinker, |
83c7162d XL |
103 | } |
104 | ||
e74abb32 | 105 | #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] |
83c7162d XL |
106 | pub enum LldFlavor { |
107 | Wasm, | |
108 | Ld64, | |
109 | Ld, | |
110 | Link, | |
111 | } | |
112 | ||
b7449926 | 113 | impl LldFlavor { |
923072b8 FG |
114 | pub fn as_str(&self) -> &'static str { |
115 | match self { | |
116 | LldFlavor::Wasm => "wasm", | |
117 | LldFlavor::Ld64 => "darwin", | |
118 | LldFlavor::Ld => "gnu", | |
119 | LldFlavor::Link => "link", | |
120 | } | |
121 | } | |
122 | ||
b7449926 XL |
123 | fn from_str(s: &str) -> Option<Self> { |
124 | Some(match s { | |
125 | "darwin" => LldFlavor::Ld64, | |
126 | "gnu" => LldFlavor::Ld, | |
127 | "link" => LldFlavor::Link, | |
128 | "wasm" => LldFlavor::Wasm, | |
129 | _ => return None, | |
130 | }) | |
131 | } | |
132 | } | |
133 | ||
134 | impl ToJson for LldFlavor { | |
135 | fn to_json(&self) -> Json { | |
923072b8 | 136 | self.as_str().to_json() |
b7449926 XL |
137 | } |
138 | } | |
139 | ||
83c7162d XL |
140 | impl ToJson for LinkerFlavor { |
141 | fn to_json(&self) -> Json { | |
142 | self.desc().to_json() | |
143 | } | |
144 | } | |
145 | macro_rules! flavor_mappings { | |
146 | ($((($($flavor:tt)*), $string:expr),)*) => ( | |
147 | impl LinkerFlavor { | |
148 | pub const fn one_of() -> &'static str { | |
dc9dc135 | 149 | concat!("one of: ", $($string, " ",)*) |
83c7162d XL |
150 | } |
151 | ||
152 | pub fn from_str(s: &str) -> Option<Self> { | |
153 | Some(match s { | |
dc9dc135 | 154 | $($string => $($flavor)*,)* |
83c7162d XL |
155 | _ => return None, |
156 | }) | |
157 | } | |
158 | ||
159 | pub fn desc(&self) -> &str { | |
160 | match *self { | |
dc9dc135 | 161 | $($($flavor)* => $string,)* |
83c7162d XL |
162 | } |
163 | } | |
164 | } | |
165 | ) | |
166 | } | |
167 | ||
83c7162d XL |
168 | flavor_mappings! { |
169 | ((LinkerFlavor::Em), "em"), | |
170 | ((LinkerFlavor::Gcc), "gcc"), | |
5099ac24 | 171 | ((LinkerFlavor::L4Bender), "l4-bender"), |
83c7162d XL |
172 | ((LinkerFlavor::Ld), "ld"), |
173 | ((LinkerFlavor::Msvc), "msvc"), | |
9fa01778 | 174 | ((LinkerFlavor::PtxLinker), "ptx-linker"), |
17df50a5 | 175 | ((LinkerFlavor::BpfLinker), "bpf-linker"), |
83c7162d XL |
176 | ((LinkerFlavor::Lld(LldFlavor::Wasm)), "wasm-ld"), |
177 | ((LinkerFlavor::Lld(LldFlavor::Ld64)), "ld64.lld"), | |
178 | ((LinkerFlavor::Lld(LldFlavor::Ld)), "ld.lld"), | |
179 | ((LinkerFlavor::Lld(LldFlavor::Link)), "lld-link"), | |
180 | } | |
181 | ||
3dfed10e | 182 | #[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable, HashStable_Generic)] |
83c7162d XL |
183 | pub enum PanicStrategy { |
184 | Unwind, | |
185 | Abort, | |
186 | } | |
187 | ||
188 | impl PanicStrategy { | |
189 | pub fn desc(&self) -> &str { | |
190 | match *self { | |
191 | PanicStrategy::Unwind => "unwind", | |
192 | PanicStrategy::Abort => "abort", | |
193 | } | |
194 | } | |
29967ef6 | 195 | |
5e7ed085 | 196 | pub const fn desc_symbol(&self) -> Symbol { |
29967ef6 XL |
197 | match *self { |
198 | PanicStrategy::Unwind => sym::unwind, | |
199 | PanicStrategy::Abort => sym::abort, | |
200 | } | |
201 | } | |
5e7ed085 FG |
202 | |
203 | pub const fn all() -> [Symbol; 2] { | |
204 | [Self::Abort.desc_symbol(), Self::Unwind.desc_symbol()] | |
205 | } | |
83c7162d XL |
206 | } |
207 | ||
208 | impl ToJson for PanicStrategy { | |
209 | fn to_json(&self) -> Json { | |
210 | match *self { | |
211 | PanicStrategy::Abort => "abort".to_json(), | |
212 | PanicStrategy::Unwind => "unwind".to_json(), | |
213 | } | |
214 | } | |
215 | } | |
216 | ||
923072b8 | 217 | #[derive(Clone, Copy, Debug, PartialEq, Hash)] |
83c7162d XL |
218 | pub enum RelroLevel { |
219 | Full, | |
220 | Partial, | |
221 | Off, | |
222 | None, | |
223 | } | |
224 | ||
225 | impl RelroLevel { | |
226 | pub fn desc(&self) -> &str { | |
227 | match *self { | |
228 | RelroLevel::Full => "full", | |
229 | RelroLevel::Partial => "partial", | |
230 | RelroLevel::Off => "off", | |
231 | RelroLevel::None => "none", | |
232 | } | |
233 | } | |
234 | } | |
235 | ||
236 | impl FromStr for RelroLevel { | |
237 | type Err = (); | |
238 | ||
239 | fn from_str(s: &str) -> Result<RelroLevel, ()> { | |
240 | match s { | |
241 | "full" => Ok(RelroLevel::Full), | |
242 | "partial" => Ok(RelroLevel::Partial), | |
243 | "off" => Ok(RelroLevel::Off), | |
244 | "none" => Ok(RelroLevel::None), | |
245 | _ => Err(()), | |
246 | } | |
247 | } | |
248 | } | |
249 | ||
250 | impl ToJson for RelroLevel { | |
251 | fn to_json(&self) -> Json { | |
252 | match *self { | |
253 | RelroLevel::Full => "full".to_json(), | |
254 | RelroLevel::Partial => "partial".to_json(), | |
255 | RelroLevel::Off => "off".to_json(), | |
256 | RelroLevel::None => "None".to_json(), | |
257 | } | |
258 | } | |
259 | } | |
260 | ||
923072b8 | 261 | #[derive(Clone, Copy, Debug, PartialEq, Hash)] |
9fa01778 XL |
262 | pub enum MergeFunctions { |
263 | Disabled, | |
264 | Trampolines, | |
dfeec247 | 265 | Aliases, |
9fa01778 XL |
266 | } |
267 | ||
268 | impl MergeFunctions { | |
269 | pub fn desc(&self) -> &str { | |
270 | match *self { | |
271 | MergeFunctions::Disabled => "disabled", | |
272 | MergeFunctions::Trampolines => "trampolines", | |
273 | MergeFunctions::Aliases => "aliases", | |
274 | } | |
275 | } | |
276 | } | |
277 | ||
278 | impl FromStr for MergeFunctions { | |
279 | type Err = (); | |
280 | ||
281 | fn from_str(s: &str) -> Result<MergeFunctions, ()> { | |
282 | match s { | |
283 | "disabled" => Ok(MergeFunctions::Disabled), | |
284 | "trampolines" => Ok(MergeFunctions::Trampolines), | |
285 | "aliases" => Ok(MergeFunctions::Aliases), | |
286 | _ => Err(()), | |
287 | } | |
288 | } | |
289 | } | |
290 | ||
291 | impl ToJson for MergeFunctions { | |
292 | fn to_json(&self) -> Json { | |
293 | match *self { | |
294 | MergeFunctions::Disabled => "disabled".to_json(), | |
295 | MergeFunctions::Trampolines => "trampolines".to_json(), | |
296 | MergeFunctions::Aliases => "aliases".to_json(), | |
297 | } | |
298 | } | |
299 | } | |
300 | ||
f9f354fc XL |
301 | #[derive(Clone, Copy, PartialEq, Hash, Debug)] |
302 | pub enum RelocModel { | |
303 | Static, | |
304 | Pic, | |
c295e0f8 | 305 | Pie, |
f9f354fc XL |
306 | DynamicNoPic, |
307 | Ropi, | |
308 | Rwpi, | |
309 | RopiRwpi, | |
310 | } | |
311 | ||
312 | impl FromStr for RelocModel { | |
313 | type Err = (); | |
314 | ||
315 | fn from_str(s: &str) -> Result<RelocModel, ()> { | |
316 | Ok(match s { | |
317 | "static" => RelocModel::Static, | |
318 | "pic" => RelocModel::Pic, | |
c295e0f8 | 319 | "pie" => RelocModel::Pie, |
f9f354fc XL |
320 | "dynamic-no-pic" => RelocModel::DynamicNoPic, |
321 | "ropi" => RelocModel::Ropi, | |
322 | "rwpi" => RelocModel::Rwpi, | |
323 | "ropi-rwpi" => RelocModel::RopiRwpi, | |
324 | _ => return Err(()), | |
325 | }) | |
326 | } | |
327 | } | |
328 | ||
329 | impl ToJson for RelocModel { | |
330 | fn to_json(&self) -> Json { | |
331 | match *self { | |
332 | RelocModel::Static => "static", | |
333 | RelocModel::Pic => "pic", | |
c295e0f8 | 334 | RelocModel::Pie => "pie", |
f9f354fc XL |
335 | RelocModel::DynamicNoPic => "dynamic-no-pic", |
336 | RelocModel::Ropi => "ropi", | |
337 | RelocModel::Rwpi => "rwpi", | |
338 | RelocModel::RopiRwpi => "ropi-rwpi", | |
339 | } | |
340 | .to_json() | |
341 | } | |
342 | } | |
343 | ||
344 | #[derive(Clone, Copy, PartialEq, Hash, Debug)] | |
345 | pub enum CodeModel { | |
346 | Tiny, | |
347 | Small, | |
348 | Kernel, | |
349 | Medium, | |
350 | Large, | |
351 | } | |
352 | ||
353 | impl FromStr for CodeModel { | |
354 | type Err = (); | |
355 | ||
356 | fn from_str(s: &str) -> Result<CodeModel, ()> { | |
357 | Ok(match s { | |
358 | "tiny" => CodeModel::Tiny, | |
359 | "small" => CodeModel::Small, | |
360 | "kernel" => CodeModel::Kernel, | |
361 | "medium" => CodeModel::Medium, | |
362 | "large" => CodeModel::Large, | |
363 | _ => return Err(()), | |
364 | }) | |
365 | } | |
366 | } | |
367 | ||
368 | impl ToJson for CodeModel { | |
369 | fn to_json(&self) -> Json { | |
370 | match *self { | |
371 | CodeModel::Tiny => "tiny", | |
372 | CodeModel::Small => "small", | |
373 | CodeModel::Kernel => "kernel", | |
374 | CodeModel::Medium => "medium", | |
375 | CodeModel::Large => "large", | |
376 | } | |
377 | .to_json() | |
378 | } | |
379 | } | |
380 | ||
381 | #[derive(Clone, Copy, PartialEq, Hash, Debug)] | |
382 | pub enum TlsModel { | |
383 | GeneralDynamic, | |
384 | LocalDynamic, | |
385 | InitialExec, | |
386 | LocalExec, | |
387 | } | |
388 | ||
389 | impl FromStr for TlsModel { | |
390 | type Err = (); | |
391 | ||
392 | fn from_str(s: &str) -> Result<TlsModel, ()> { | |
393 | Ok(match s { | |
394 | // Note the difference "general" vs "global" difference. The model name is "general", | |
395 | // but the user-facing option name is "global" for consistency with other compilers. | |
396 | "global-dynamic" => TlsModel::GeneralDynamic, | |
397 | "local-dynamic" => TlsModel::LocalDynamic, | |
398 | "initial-exec" => TlsModel::InitialExec, | |
399 | "local-exec" => TlsModel::LocalExec, | |
400 | _ => return Err(()), | |
401 | }) | |
402 | } | |
403 | } | |
404 | ||
405 | impl ToJson for TlsModel { | |
406 | fn to_json(&self) -> Json { | |
407 | match *self { | |
408 | TlsModel::GeneralDynamic => "global-dynamic", | |
409 | TlsModel::LocalDynamic => "local-dynamic", | |
410 | TlsModel::InitialExec => "initial-exec", | |
411 | TlsModel::LocalExec => "local-exec", | |
412 | } | |
413 | .to_json() | |
414 | } | |
415 | } | |
416 | ||
417 | /// Everything is flattened to a single enum to make the json encoding/decoding less annoying. | |
418 | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] | |
419 | pub enum LinkOutputKind { | |
420 | /// Dynamically linked non position-independent executable. | |
421 | DynamicNoPicExe, | |
422 | /// Dynamically linked position-independent executable. | |
423 | DynamicPicExe, | |
424 | /// Statically linked non position-independent executable. | |
425 | StaticNoPicExe, | |
426 | /// Statically linked position-independent executable. | |
427 | StaticPicExe, | |
428 | /// Regular dynamic library ("dynamically linked"). | |
429 | DynamicDylib, | |
430 | /// Dynamic library with bundled libc ("statically linked"). | |
431 | StaticDylib, | |
5869c6ff XL |
432 | /// WASI module with a lifetime past the _initialize entry point |
433 | WasiReactorExe, | |
f9f354fc XL |
434 | } |
435 | ||
436 | impl LinkOutputKind { | |
437 | fn as_str(&self) -> &'static str { | |
438 | match self { | |
439 | LinkOutputKind::DynamicNoPicExe => "dynamic-nopic-exe", | |
440 | LinkOutputKind::DynamicPicExe => "dynamic-pic-exe", | |
441 | LinkOutputKind::StaticNoPicExe => "static-nopic-exe", | |
442 | LinkOutputKind::StaticPicExe => "static-pic-exe", | |
443 | LinkOutputKind::DynamicDylib => "dynamic-dylib", | |
444 | LinkOutputKind::StaticDylib => "static-dylib", | |
5869c6ff | 445 | LinkOutputKind::WasiReactorExe => "wasi-reactor-exe", |
f9f354fc XL |
446 | } |
447 | } | |
448 | ||
449 | pub(super) fn from_str(s: &str) -> Option<LinkOutputKind> { | |
450 | Some(match s { | |
451 | "dynamic-nopic-exe" => LinkOutputKind::DynamicNoPicExe, | |
452 | "dynamic-pic-exe" => LinkOutputKind::DynamicPicExe, | |
453 | "static-nopic-exe" => LinkOutputKind::StaticNoPicExe, | |
454 | "static-pic-exe" => LinkOutputKind::StaticPicExe, | |
455 | "dynamic-dylib" => LinkOutputKind::DynamicDylib, | |
456 | "static-dylib" => LinkOutputKind::StaticDylib, | |
5869c6ff | 457 | "wasi-reactor-exe" => LinkOutputKind::WasiReactorExe, |
f9f354fc XL |
458 | _ => return None, |
459 | }) | |
460 | } | |
461 | } | |
462 | ||
463 | impl fmt::Display for LinkOutputKind { | |
464 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
465 | f.write_str(self.as_str()) | |
466 | } | |
467 | } | |
468 | ||
5e7ed085 | 469 | pub type LinkArgs = BTreeMap<LinkerFlavor, Vec<StaticCow<str>>>; |
5bcae85e | 470 | |
5869c6ff XL |
471 | #[derive(Clone, Copy, Hash, Debug, PartialEq, Eq)] |
472 | pub enum SplitDebuginfo { | |
473 | /// Split debug-information is disabled, meaning that on supported platforms | |
474 | /// you can find all debug information in the executable itself. This is | |
475 | /// only supported for ELF effectively. | |
476 | /// | |
477 | /// * Windows - not supported | |
478 | /// * macOS - don't run `dsymutil` | |
479 | /// * ELF - `.dwarf_*` sections | |
480 | Off, | |
481 | ||
482 | /// Split debug-information can be found in a "packed" location separate | |
483 | /// from the final artifact. This is supported on all platforms. | |
484 | /// | |
485 | /// * Windows - `*.pdb` | |
486 | /// * macOS - `*.dSYM` (run `dsymutil`) | |
487 | /// * ELF - `*.dwp` (run `rust-llvm-dwp`) | |
488 | Packed, | |
489 | ||
490 | /// Split debug-information can be found in individual object files on the | |
491 | /// filesystem. The main executable may point to the object files. | |
492 | /// | |
493 | /// * Windows - not supported | |
494 | /// * macOS - supported, scattered object files | |
a2a8927a | 495 | /// * ELF - supported, scattered `*.dwo` or `*.o` files (see `SplitDwarfKind`) |
5869c6ff XL |
496 | Unpacked, |
497 | } | |
498 | ||
499 | impl SplitDebuginfo { | |
500 | fn as_str(&self) -> &'static str { | |
501 | match self { | |
502 | SplitDebuginfo::Off => "off", | |
503 | SplitDebuginfo::Packed => "packed", | |
504 | SplitDebuginfo::Unpacked => "unpacked", | |
505 | } | |
506 | } | |
507 | } | |
508 | ||
509 | impl FromStr for SplitDebuginfo { | |
510 | type Err = (); | |
511 | ||
512 | fn from_str(s: &str) -> Result<SplitDebuginfo, ()> { | |
513 | Ok(match s { | |
514 | "off" => SplitDebuginfo::Off, | |
515 | "unpacked" => SplitDebuginfo::Unpacked, | |
516 | "packed" => SplitDebuginfo::Packed, | |
517 | _ => return Err(()), | |
518 | }) | |
519 | } | |
520 | } | |
521 | ||
522 | impl ToJson for SplitDebuginfo { | |
523 | fn to_json(&self) -> Json { | |
524 | self.as_str().to_json() | |
525 | } | |
526 | } | |
527 | ||
528 | impl fmt::Display for SplitDebuginfo { | |
529 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
530 | f.write_str(self.as_str()) | |
531 | } | |
532 | } | |
533 | ||
5869c6ff XL |
534 | #[derive(Clone, Debug, PartialEq, Eq)] |
535 | pub enum StackProbeType { | |
536 | /// Don't emit any stack probes. | |
537 | None, | |
538 | /// It is harmless to use this option even on targets that do not have backend support for | |
539 | /// stack probes as the failure mode is the same as if no stack-probe option was specified in | |
540 | /// the first place. | |
541 | Inline, | |
542 | /// Call `__rust_probestack` whenever stack needs to be probed. | |
543 | Call, | |
544 | /// Use inline option for LLVM versions later than specified in `min_llvm_version_for_inline` | |
545 | /// and call `__rust_probestack` otherwise. | |
546 | InlineOrCall { min_llvm_version_for_inline: (u32, u32, u32) }, | |
547 | } | |
548 | ||
549 | impl StackProbeType { | |
550 | fn from_json(json: &Json) -> Result<Self, String> { | |
551 | let object = json.as_object().ok_or_else(|| "expected a JSON object")?; | |
552 | let kind = object | |
553 | .get("kind") | |
923072b8 | 554 | .and_then(|o| o.as_str()) |
5869c6ff XL |
555 | .ok_or_else(|| "expected `kind` to be a string")?; |
556 | match kind { | |
557 | "none" => Ok(StackProbeType::None), | |
558 | "inline" => Ok(StackProbeType::Inline), | |
559 | "call" => Ok(StackProbeType::Call), | |
560 | "inline-or-call" => { | |
561 | let min_version = object | |
562 | .get("min-llvm-version-for-inline") | |
563 | .and_then(|o| o.as_array()) | |
564 | .ok_or_else(|| "expected `min-llvm-version-for-inline` to be an array")?; | |
565 | let mut iter = min_version.into_iter().map(|v| { | |
566 | let int = v.as_u64().ok_or_else( | |
567 | || "expected `min-llvm-version-for-inline` values to be integers", | |
568 | )?; | |
569 | u32::try_from(int) | |
570 | .map_err(|_| "`min-llvm-version-for-inline` values don't convert to u32") | |
571 | }); | |
572 | let min_llvm_version_for_inline = ( | |
573 | iter.next().unwrap_or(Ok(11))?, | |
574 | iter.next().unwrap_or(Ok(0))?, | |
575 | iter.next().unwrap_or(Ok(0))?, | |
576 | ); | |
577 | Ok(StackProbeType::InlineOrCall { min_llvm_version_for_inline }) | |
578 | } | |
579 | _ => Err(String::from( | |
6a06907d | 580 | "`kind` expected to be one of `none`, `inline`, `call` or `inline-or-call`", |
5869c6ff XL |
581 | )), |
582 | } | |
583 | } | |
584 | } | |
585 | ||
586 | impl ToJson for StackProbeType { | |
587 | fn to_json(&self) -> Json { | |
588 | Json::Object(match self { | |
589 | StackProbeType::None => { | |
5099ac24 | 590 | [(String::from("kind"), "none".to_json())].into_iter().collect() |
5869c6ff XL |
591 | } |
592 | StackProbeType::Inline => { | |
5099ac24 | 593 | [(String::from("kind"), "inline".to_json())].into_iter().collect() |
5869c6ff XL |
594 | } |
595 | StackProbeType::Call => { | |
5099ac24 | 596 | [(String::from("kind"), "call".to_json())].into_iter().collect() |
5869c6ff | 597 | } |
923072b8 | 598 | StackProbeType::InlineOrCall { min_llvm_version_for_inline: (maj, min, patch) } => [ |
5869c6ff XL |
599 | (String::from("kind"), "inline-or-call".to_json()), |
600 | ( | |
601 | String::from("min-llvm-version-for-inline"), | |
923072b8 | 602 | Json::Array(vec![maj.to_json(), min.to_json(), patch.to_json()]), |
5869c6ff XL |
603 | ), |
604 | ] | |
605 | .into_iter() | |
606 | .collect(), | |
607 | }) | |
608 | } | |
609 | } | |
610 | ||
cdc7bbd5 XL |
611 | bitflags::bitflags! { |
612 | #[derive(Default, Encodable, Decodable)] | |
613 | pub struct SanitizerSet: u8 { | |
614 | const ADDRESS = 1 << 0; | |
615 | const LEAK = 1 << 1; | |
616 | const MEMORY = 1 << 2; | |
617 | const THREAD = 1 << 3; | |
618 | const HWADDRESS = 1 << 4; | |
3c0e092e | 619 | const CFI = 1 << 5; |
5099ac24 | 620 | const MEMTAG = 1 << 6; |
064997fb | 621 | const SHADOWCALLSTACK = 1 << 7; |
cdc7bbd5 XL |
622 | } |
623 | } | |
624 | ||
625 | impl SanitizerSet { | |
626 | /// Return sanitizer's name | |
627 | /// | |
628 | /// Returns none if the flags is a set of sanitizers numbering not exactly one. | |
5e7ed085 | 629 | pub fn as_str(self) -> Option<&'static str> { |
cdc7bbd5 XL |
630 | Some(match self { |
631 | SanitizerSet::ADDRESS => "address", | |
3c0e092e | 632 | SanitizerSet::CFI => "cfi", |
cdc7bbd5 XL |
633 | SanitizerSet::LEAK => "leak", |
634 | SanitizerSet::MEMORY => "memory", | |
5099ac24 | 635 | SanitizerSet::MEMTAG => "memtag", |
064997fb | 636 | SanitizerSet::SHADOWCALLSTACK => "shadow-call-stack", |
cdc7bbd5 XL |
637 | SanitizerSet::THREAD => "thread", |
638 | SanitizerSet::HWADDRESS => "hwaddress", | |
639 | _ => return None, | |
640 | }) | |
641 | } | |
642 | } | |
643 | ||
644 | /// Formats a sanitizer set as a comma separated list of sanitizers' names. | |
645 | impl fmt::Display for SanitizerSet { | |
646 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
647 | let mut first = true; | |
648 | for s in *self { | |
649 | let name = s.as_str().unwrap_or_else(|| panic!("unrecognized sanitizer {:?}", s)); | |
650 | if !first { | |
651 | f.write_str(", ")?; | |
652 | } | |
653 | f.write_str(name)?; | |
654 | first = false; | |
655 | } | |
656 | Ok(()) | |
657 | } | |
658 | } | |
659 | ||
660 | impl IntoIterator for SanitizerSet { | |
661 | type Item = SanitizerSet; | |
662 | type IntoIter = std::vec::IntoIter<SanitizerSet>; | |
663 | ||
664 | fn into_iter(self) -> Self::IntoIter { | |
665 | [ | |
666 | SanitizerSet::ADDRESS, | |
3c0e092e | 667 | SanitizerSet::CFI, |
cdc7bbd5 XL |
668 | SanitizerSet::LEAK, |
669 | SanitizerSet::MEMORY, | |
5099ac24 | 670 | SanitizerSet::MEMTAG, |
064997fb | 671 | SanitizerSet::SHADOWCALLSTACK, |
cdc7bbd5 XL |
672 | SanitizerSet::THREAD, |
673 | SanitizerSet::HWADDRESS, | |
674 | ] | |
675 | .iter() | |
676 | .copied() | |
677 | .filter(|&s| self.contains(s)) | |
678 | .collect::<Vec<_>>() | |
679 | .into_iter() | |
680 | } | |
681 | } | |
682 | ||
683 | impl<CTX> HashStable<CTX> for SanitizerSet { | |
684 | fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { | |
685 | self.bits().hash_stable(ctx, hasher); | |
686 | } | |
687 | } | |
688 | ||
689 | impl ToJson for SanitizerSet { | |
690 | fn to_json(&self) -> Json { | |
691 | self.into_iter() | |
692 | .map(|v| Some(v.as_str()?.to_json())) | |
693 | .collect::<Option<Vec<_>>>() | |
94222f64 | 694 | .unwrap_or_default() |
cdc7bbd5 XL |
695 | .to_json() |
696 | } | |
697 | } | |
698 | ||
136023e0 XL |
699 | #[derive(Clone, Copy, PartialEq, Hash, Debug)] |
700 | pub enum FramePointer { | |
701 | /// Forces the machine code generator to always preserve the frame pointers. | |
702 | Always, | |
703 | /// Forces the machine code generator to preserve the frame pointers except for the leaf | |
704 | /// functions (i.e. those that don't call other functions). | |
705 | NonLeaf, | |
706 | /// Allows the machine code generator to omit the frame pointers. | |
707 | /// | |
708 | /// This option does not guarantee that the frame pointers will be omitted. | |
709 | MayOmit, | |
710 | } | |
711 | ||
712 | impl FromStr for FramePointer { | |
713 | type Err = (); | |
714 | fn from_str(s: &str) -> Result<Self, ()> { | |
715 | Ok(match s { | |
716 | "always" => Self::Always, | |
717 | "non-leaf" => Self::NonLeaf, | |
718 | "may-omit" => Self::MayOmit, | |
719 | _ => return Err(()), | |
720 | }) | |
721 | } | |
722 | } | |
723 | ||
724 | impl ToJson for FramePointer { | |
725 | fn to_json(&self) -> Json { | |
726 | match *self { | |
727 | Self::Always => "always", | |
728 | Self::NonLeaf => "non-leaf", | |
729 | Self::MayOmit => "may-omit", | |
730 | } | |
731 | .to_json() | |
732 | } | |
733 | } | |
734 | ||
3c0e092e XL |
735 | /// Controls use of stack canaries. |
736 | #[derive(Clone, Copy, Debug, PartialEq, Hash, Eq)] | |
737 | pub enum StackProtector { | |
738 | /// Disable stack canary generation. | |
739 | None, | |
740 | ||
741 | /// On LLVM, mark all generated LLVM functions with the `ssp` attribute (see | |
742 | /// llvm/docs/LangRef.rst). This triggers stack canary generation in | |
743 | /// functions which contain an array of a byte-sized type with more than | |
744 | /// eight elements. | |
745 | Basic, | |
746 | ||
747 | /// On LLVM, mark all generated LLVM functions with the `sspstrong` | |
748 | /// attribute (see llvm/docs/LangRef.rst). This triggers stack canary | |
749 | /// generation in functions which either contain an array, or which take | |
750 | /// the address of a local variable. | |
751 | Strong, | |
752 | ||
753 | /// Generate stack canaries in all functions. | |
754 | All, | |
755 | } | |
756 | ||
757 | impl StackProtector { | |
758 | fn as_str(&self) -> &'static str { | |
759 | match self { | |
760 | StackProtector::None => "none", | |
761 | StackProtector::Basic => "basic", | |
762 | StackProtector::Strong => "strong", | |
763 | StackProtector::All => "all", | |
764 | } | |
765 | } | |
766 | } | |
767 | ||
768 | impl FromStr for StackProtector { | |
769 | type Err = (); | |
770 | ||
771 | fn from_str(s: &str) -> Result<StackProtector, ()> { | |
772 | Ok(match s { | |
773 | "none" => StackProtector::None, | |
774 | "basic" => StackProtector::Basic, | |
775 | "strong" => StackProtector::Strong, | |
776 | "all" => StackProtector::All, | |
777 | _ => return Err(()), | |
778 | }) | |
779 | } | |
780 | } | |
781 | ||
782 | impl fmt::Display for StackProtector { | |
783 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
784 | f.write_str(self.as_str()) | |
785 | } | |
786 | } | |
787 | ||
cdc7bbd5 XL |
788 | macro_rules! supported_targets { |
789 | ( $(($( $triple:literal, )+ $module:ident ),)+ ) => { | |
790 | $(mod $module;)+ | |
791 | ||
792 | /// List of supported targets | |
793 | pub const TARGETS: &[&str] = &[$($($triple),+),+]; | |
794 | ||
795 | fn load_builtin(target: &str) -> Option<Target> { | |
796 | let mut t = match target { | |
797 | $( $($triple)|+ => $module::target(), )+ | |
798 | _ => return None, | |
799 | }; | |
800 | t.is_builtin = true; | |
801 | debug!("got builtin target: {:?}", t); | |
802 | Some(t) | |
803 | } | |
804 | ||
805 | #[cfg(test)] | |
806 | mod tests { | |
807 | mod tests_impl; | |
808 | ||
809 | // Cannot put this into a separate file without duplication, make an exception. | |
810 | $( | |
811 | #[test] // `#[test]` | |
812 | fn $module() { | |
813 | tests_impl::test_target(super::$module::target()); | |
814 | } | |
815 | )+ | |
816 | } | |
817 | }; | |
818 | } | |
819 | ||
7453a54e SL |
820 | supported_targets! { |
821 | ("x86_64-unknown-linux-gnu", x86_64_unknown_linux_gnu), | |
abe05a73 | 822 | ("x86_64-unknown-linux-gnux32", x86_64_unknown_linux_gnux32), |
7453a54e SL |
823 | ("i686-unknown-linux-gnu", i686_unknown_linux_gnu), |
824 | ("i586-unknown-linux-gnu", i586_unknown_linux_gnu), | |
c295e0f8 | 825 | ("m68k-unknown-linux-gnu", m68k_unknown_linux_gnu), |
7453a54e | 826 | ("mips-unknown-linux-gnu", mips_unknown_linux_gnu), |
9e0c209e SL |
827 | ("mips64-unknown-linux-gnuabi64", mips64_unknown_linux_gnuabi64), |
828 | ("mips64el-unknown-linux-gnuabi64", mips64el_unknown_linux_gnuabi64), | |
532ac7d7 XL |
829 | ("mipsisa32r6-unknown-linux-gnu", mipsisa32r6_unknown_linux_gnu), |
830 | ("mipsisa32r6el-unknown-linux-gnu", mipsisa32r6el_unknown_linux_gnu), | |
831 | ("mipsisa64r6-unknown-linux-gnuabi64", mipsisa64r6_unknown_linux_gnuabi64), | |
832 | ("mipsisa64r6el-unknown-linux-gnuabi64", mipsisa64r6el_unknown_linux_gnuabi64), | |
7453a54e SL |
833 | ("mipsel-unknown-linux-gnu", mipsel_unknown_linux_gnu), |
834 | ("powerpc-unknown-linux-gnu", powerpc_unknown_linux_gnu), | |
0531ce1d | 835 | ("powerpc-unknown-linux-gnuspe", powerpc_unknown_linux_gnuspe), |
a1dfa0c6 | 836 | ("powerpc-unknown-linux-musl", powerpc_unknown_linux_musl), |
7453a54e | 837 | ("powerpc64-unknown-linux-gnu", powerpc64_unknown_linux_gnu), |
a1dfa0c6 | 838 | ("powerpc64-unknown-linux-musl", powerpc64_unknown_linux_musl), |
7453a54e | 839 | ("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu), |
8faf50e0 | 840 | ("powerpc64le-unknown-linux-musl", powerpc64le_unknown_linux_musl), |
9e0c209e | 841 | ("s390x-unknown-linux-gnu", s390x_unknown_linux_gnu), |
6a06907d | 842 | ("s390x-unknown-linux-musl", s390x_unknown_linux_musl), |
0531ce1d | 843 | ("sparc-unknown-linux-gnu", sparc_unknown_linux_gnu), |
2c00a5a8 | 844 | ("sparc64-unknown-linux-gnu", sparc64_unknown_linux_gnu), |
7453a54e SL |
845 | ("arm-unknown-linux-gnueabi", arm_unknown_linux_gnueabi), |
846 | ("arm-unknown-linux-gnueabihf", arm_unknown_linux_gnueabihf), | |
5bcae85e SL |
847 | ("arm-unknown-linux-musleabi", arm_unknown_linux_musleabi), |
848 | ("arm-unknown-linux-musleabihf", arm_unknown_linux_musleabihf), | |
ff7c6d11 | 849 | ("armv4t-unknown-linux-gnueabi", armv4t_unknown_linux_gnueabi), |
476ff2be | 850 | ("armv5te-unknown-linux-gnueabi", armv5te_unknown_linux_gnueabi), |
83c7162d | 851 | ("armv5te-unknown-linux-musleabi", armv5te_unknown_linux_musleabi), |
fc512014 | 852 | ("armv5te-unknown-linux-uclibceabi", armv5te_unknown_linux_uclibceabi), |
416331ca | 853 | ("armv7-unknown-linux-gnueabi", armv7_unknown_linux_gnueabi), |
7453a54e | 854 | ("armv7-unknown-linux-gnueabihf", armv7_unknown_linux_gnueabihf), |
0731742a | 855 | ("thumbv7neon-unknown-linux-gnueabihf", thumbv7neon_unknown_linux_gnueabihf), |
60c5eb7d | 856 | ("thumbv7neon-unknown-linux-musleabihf", thumbv7neon_unknown_linux_musleabihf), |
416331ca | 857 | ("armv7-unknown-linux-musleabi", armv7_unknown_linux_musleabi), |
5bcae85e | 858 | ("armv7-unknown-linux-musleabihf", armv7_unknown_linux_musleabihf), |
7453a54e | 859 | ("aarch64-unknown-linux-gnu", aarch64_unknown_linux_gnu), |
ea8adc8c | 860 | ("aarch64-unknown-linux-musl", aarch64_unknown_linux_musl), |
7453a54e SL |
861 | ("x86_64-unknown-linux-musl", x86_64_unknown_linux_musl), |
862 | ("i686-unknown-linux-musl", i686_unknown_linux_musl), | |
2c00a5a8 | 863 | ("i586-unknown-linux-musl", i586_unknown_linux_musl), |
7453a54e SL |
864 | ("mips-unknown-linux-musl", mips_unknown_linux_musl), |
865 | ("mipsel-unknown-linux-musl", mipsel_unknown_linux_musl), | |
e1599b0c XL |
866 | ("mips64-unknown-linux-muslabi64", mips64_unknown_linux_muslabi64), |
867 | ("mips64el-unknown-linux-muslabi64", mips64el_unknown_linux_muslabi64), | |
416331ca | 868 | ("hexagon-unknown-linux-musl", hexagon_unknown_linux_musl), |
2c00a5a8 | 869 | |
9e0c209e SL |
870 | ("mips-unknown-linux-uclibc", mips_unknown_linux_uclibc), |
871 | ("mipsel-unknown-linux-uclibc", mipsel_unknown_linux_uclibc), | |
7453a54e SL |
872 | |
873 | ("i686-linux-android", i686_linux_android), | |
cc61c64b | 874 | ("x86_64-linux-android", x86_64_linux_android), |
7453a54e | 875 | ("arm-linux-androideabi", arm_linux_androideabi), |
a7813a04 | 876 | ("armv7-linux-androideabi", armv7_linux_androideabi), |
0731742a | 877 | ("thumbv7neon-linux-androideabi", thumbv7neon_linux_androideabi), |
7453a54e SL |
878 | ("aarch64-linux-android", aarch64_linux_android), |
879 | ||
6a06907d | 880 | ("x86_64-unknown-none-linuxkernel", x86_64_unknown_none_linuxkernel), |
e1599b0c | 881 | |
8bb4bdeb | 882 | ("aarch64-unknown-freebsd", aarch64_unknown_freebsd), |
532ac7d7 XL |
883 | ("armv6-unknown-freebsd", armv6_unknown_freebsd), |
884 | ("armv7-unknown-freebsd", armv7_unknown_freebsd), | |
7453a54e | 885 | ("i686-unknown-freebsd", i686_unknown_freebsd), |
94222f64 | 886 | ("powerpc-unknown-freebsd", powerpc_unknown_freebsd), |
9fa01778 | 887 | ("powerpc64-unknown-freebsd", powerpc64_unknown_freebsd), |
136023e0 | 888 | ("powerpc64le-unknown-freebsd", powerpc64le_unknown_freebsd), |
a2a8927a | 889 | ("riscv64gc-unknown-freebsd", riscv64gc_unknown_freebsd), |
7453a54e SL |
890 | ("x86_64-unknown-freebsd", x86_64_unknown_freebsd), |
891 | ||
7453a54e SL |
892 | ("x86_64-unknown-dragonfly", x86_64_unknown_dragonfly), |
893 | ||
94b46f34 | 894 | ("aarch64-unknown-openbsd", aarch64_unknown_openbsd), |
476ff2be | 895 | ("i686-unknown-openbsd", i686_unknown_openbsd), |
e1599b0c | 896 | ("sparc64-unknown-openbsd", sparc64_unknown_openbsd), |
7453a54e | 897 | ("x86_64-unknown-openbsd", x86_64_unknown_openbsd), |
6a06907d | 898 | ("powerpc-unknown-openbsd", powerpc_unknown_openbsd), |
476ff2be | 899 | |
b7449926 | 900 | ("aarch64-unknown-netbsd", aarch64_unknown_netbsd), |
94b46f34 XL |
901 | ("armv6-unknown-netbsd-eabihf", armv6_unknown_netbsd_eabihf), |
902 | ("armv7-unknown-netbsd-eabihf", armv7_unknown_netbsd_eabihf), | |
8bb4bdeb | 903 | ("i686-unknown-netbsd", i686_unknown_netbsd), |
0531ce1d | 904 | ("powerpc-unknown-netbsd", powerpc_unknown_netbsd), |
32a655c1 | 905 | ("sparc64-unknown-netbsd", sparc64_unknown_netbsd), |
7453a54e | 906 | ("x86_64-unknown-netbsd", x86_64_unknown_netbsd), |
7453a54e | 907 | |
c30ab7b3 SL |
908 | ("i686-unknown-haiku", i686_unknown_haiku), |
909 | ("x86_64-unknown-haiku", x86_64_unknown_haiku), | |
9e0c209e | 910 | |
f9652781 | 911 | ("aarch64-apple-darwin", aarch64_apple_darwin), |
7453a54e SL |
912 | ("x86_64-apple-darwin", x86_64_apple_darwin), |
913 | ("i686-apple-darwin", i686_apple_darwin), | |
914 | ||
8faf50e0 XL |
915 | ("aarch64-fuchsia", aarch64_fuchsia), |
916 | ("x86_64-fuchsia", x86_64_fuchsia), | |
c30ab7b3 | 917 | |
1b1a35ee | 918 | ("avr-unknown-gnu-atmega328", avr_unknown_gnu_atmega328), |
f035d41b | 919 | |
3b2f2976 XL |
920 | ("x86_64-unknown-l4re-uclibc", x86_64_unknown_l4re_uclibc), |
921 | ||
416331ca | 922 | ("aarch64-unknown-redox", aarch64_unknown_redox), |
32a655c1 SL |
923 | ("x86_64-unknown-redox", x86_64_unknown_redox), |
924 | ||
7453a54e SL |
925 | ("i386-apple-ios", i386_apple_ios), |
926 | ("x86_64-apple-ios", x86_64_apple_ios), | |
927 | ("aarch64-apple-ios", aarch64_apple_ios), | |
928 | ("armv7-apple-ios", armv7_apple_ios), | |
929 | ("armv7s-apple-ios", armv7s_apple_ios), | |
e1599b0c | 930 | ("x86_64-apple-ios-macabi", x86_64_apple_ios_macabi), |
fc512014 | 931 | ("aarch64-apple-ios-macabi", aarch64_apple_ios_macabi), |
6a06907d | 932 | ("aarch64-apple-ios-sim", aarch64_apple_ios_sim), |
ba9703b0 XL |
933 | ("aarch64-apple-tvos", aarch64_apple_tvos), |
934 | ("x86_64-apple-tvos", x86_64_apple_tvos), | |
7453a54e | 935 | |
923072b8 FG |
936 | ("armv7k-apple-watchos", armv7k_apple_watchos), |
937 | ("arm64_32-apple-watchos", arm64_32_apple_watchos), | |
938 | ("x86_64-apple-watchos-sim", x86_64_apple_watchos_sim), | |
939 | ("aarch64-apple-watchos-sim", aarch64_apple_watchos_sim), | |
940 | ||
b7449926 | 941 | ("armebv7r-none-eabi", armebv7r_none_eabi), |
94b46f34 | 942 | ("armebv7r-none-eabihf", armebv7r_none_eabihf), |
b7449926 XL |
943 | ("armv7r-none-eabi", armv7r_none_eabi), |
944 | ("armv7r-none-eabihf", armv7r_none_eabihf), | |
94b46f34 | 945 | |
6a06907d XL |
946 | ("x86_64-pc-solaris", x86_64_pc_solaris), |
947 | ("x86_64-sun-solaris", x86_64_sun_solaris), | |
8bb4bdeb | 948 | ("sparcv9-sun-solaris", sparcv9_sun_solaris), |
7453a54e | 949 | |
ba9703b0 XL |
950 | ("x86_64-unknown-illumos", x86_64_unknown_illumos), |
951 | ||
7453a54e SL |
952 | ("x86_64-pc-windows-gnu", x86_64_pc_windows_gnu), |
953 | ("i686-pc-windows-gnu", i686_pc_windows_gnu), | |
416331ca XL |
954 | ("i686-uwp-windows-gnu", i686_uwp_windows_gnu), |
955 | ("x86_64-uwp-windows-gnu", x86_64_uwp_windows_gnu), | |
7453a54e | 956 | |
04454e1e FG |
957 | ("aarch64-pc-windows-gnullvm", aarch64_pc_windows_gnullvm), |
958 | ("x86_64-pc-windows-gnullvm", x86_64_pc_windows_gnullvm), | |
959 | ||
b7449926 | 960 | ("aarch64-pc-windows-msvc", aarch64_pc_windows_msvc), |
e1599b0c | 961 | ("aarch64-uwp-windows-msvc", aarch64_uwp_windows_msvc), |
7453a54e | 962 | ("x86_64-pc-windows-msvc", x86_64_pc_windows_msvc), |
e1599b0c | 963 | ("x86_64-uwp-windows-msvc", x86_64_uwp_windows_msvc), |
7453a54e | 964 | ("i686-pc-windows-msvc", i686_pc_windows_msvc), |
e1599b0c | 965 | ("i686-uwp-windows-msvc", i686_uwp_windows_msvc), |
54a0048b | 966 | ("i586-pc-windows-msvc", i586_pc_windows_msvc), |
b7449926 | 967 | ("thumbv7a-pc-windows-msvc", thumbv7a_pc_windows_msvc), |
f9f354fc | 968 | ("thumbv7a-uwp-windows-msvc", thumbv7a_uwp_windows_msvc), |
7453a54e | 969 | |
c30ab7b3 SL |
970 | ("asmjs-unknown-emscripten", asmjs_unknown_emscripten), |
971 | ("wasm32-unknown-emscripten", wasm32_unknown_emscripten), | |
abe05a73 | 972 | ("wasm32-unknown-unknown", wasm32_unknown_unknown), |
48663c56 | 973 | ("wasm32-wasi", wasm32_wasi), |
cdc7bbd5 | 974 | ("wasm64-unknown-unknown", wasm64_unknown_unknown), |
c30ab7b3 SL |
975 | |
976 | ("thumbv6m-none-eabi", thumbv6m_none_eabi), | |
977 | ("thumbv7m-none-eabi", thumbv7m_none_eabi), | |
978 | ("thumbv7em-none-eabi", thumbv7em_none_eabi), | |
979 | ("thumbv7em-none-eabihf", thumbv7em_none_eabihf), | |
a1dfa0c6 | 980 | ("thumbv8m.base-none-eabi", thumbv8m_base_none_eabi), |
0731742a XL |
981 | ("thumbv8m.main-none-eabi", thumbv8m_main_none_eabi), |
982 | ("thumbv8m.main-none-eabihf", thumbv8m_main_none_eabihf), | |
041b39d2 | 983 | |
dfeec247 XL |
984 | ("armv7a-none-eabi", armv7a_none_eabi), |
985 | ("armv7a-none-eabihf", armv7a_none_eabihf), | |
986 | ||
041b39d2 | 987 | ("msp430-none-elf", msp430_none_elf), |
ff7c6d11 | 988 | |
b7449926 XL |
989 | ("aarch64-unknown-hermit", aarch64_unknown_hermit), |
990 | ("x86_64-unknown-hermit", x86_64_unknown_hermit), | |
6a06907d | 991 | |
416331ca | 992 | ("riscv32i-unknown-none-elf", riscv32i_unknown_none_elf), |
5e7ed085 | 993 | ("riscv32im-unknown-none-elf", riscv32im_unknown_none_elf), |
b7449926 | 994 | ("riscv32imc-unknown-none-elf", riscv32imc_unknown_none_elf), |
94222f64 | 995 | ("riscv32imc-esp-espidf", riscv32imc_esp_espidf), |
b7449926 | 996 | ("riscv32imac-unknown-none-elf", riscv32imac_unknown_none_elf), |
923072b8 | 997 | ("riscv32imac-unknown-xous-elf", riscv32imac_unknown_xous_elf), |
1b1a35ee | 998 | ("riscv32gc-unknown-linux-gnu", riscv32gc_unknown_linux_gnu), |
6a06907d | 999 | ("riscv32gc-unknown-linux-musl", riscv32gc_unknown_linux_musl), |
9fa01778 XL |
1000 | ("riscv64imac-unknown-none-elf", riscv64imac_unknown_none_elf), |
1001 | ("riscv64gc-unknown-none-elf", riscv64gc_unknown_none_elf), | |
60c5eb7d | 1002 | ("riscv64gc-unknown-linux-gnu", riscv64gc_unknown_linux_gnu), |
6a06907d | 1003 | ("riscv64gc-unknown-linux-musl", riscv64gc_unknown_linux_musl), |
b7449926 XL |
1004 | |
1005 | ("aarch64-unknown-none", aarch64_unknown_none), | |
e74abb32 | 1006 | ("aarch64-unknown-none-softfloat", aarch64_unknown_none_softfloat), |
a1dfa0c6 XL |
1007 | |
1008 | ("x86_64-fortanix-unknown-sgx", x86_64_fortanix_unknown_sgx), | |
0731742a XL |
1009 | |
1010 | ("x86_64-unknown-uefi", x86_64_unknown_uefi), | |
e1599b0c | 1011 | ("i686-unknown-uefi", i686_unknown_uefi), |
94222f64 | 1012 | ("aarch64-unknown-uefi", aarch64_unknown_uefi), |
9fa01778 XL |
1013 | |
1014 | ("nvptx64-nvidia-cuda", nvptx64_nvidia_cuda), | |
416331ca | 1015 | |
416331ca | 1016 | ("i686-wrs-vxworks", i686_wrs_vxworks), |
e1599b0c XL |
1017 | ("x86_64-wrs-vxworks", x86_64_wrs_vxworks), |
1018 | ("armv7-wrs-vxworks-eabihf", armv7_wrs_vxworks_eabihf), | |
416331ca XL |
1019 | ("aarch64-wrs-vxworks", aarch64_wrs_vxworks), |
1020 | ("powerpc-wrs-vxworks", powerpc_wrs_vxworks), | |
1021 | ("powerpc-wrs-vxworks-spe", powerpc_wrs_vxworks_spe), | |
1022 | ("powerpc64-wrs-vxworks", powerpc64_wrs_vxworks), | |
f9f354fc | 1023 | |
c295e0f8 XL |
1024 | ("aarch64-kmc-solid_asp3", aarch64_kmc_solid_asp3), |
1025 | ("armv7a-kmc-solid_asp3-eabi", armv7a_kmc_solid_asp3_eabi), | |
1026 | ("armv7a-kmc-solid_asp3-eabihf", armv7a_kmc_solid_asp3_eabihf), | |
1027 | ||
f9f354fc | 1028 | ("mipsel-sony-psp", mipsel_sony_psp), |
29967ef6 | 1029 | ("mipsel-unknown-none", mipsel_unknown_none), |
3dfed10e | 1030 | ("thumbv4t-none-eabi", thumbv4t_none_eabi), |
5869c6ff XL |
1031 | |
1032 | ("aarch64_be-unknown-linux-gnu", aarch64_be_unknown_linux_gnu), | |
1033 | ("aarch64-unknown-linux-gnu_ilp32", aarch64_unknown_linux_gnu_ilp32), | |
1034 | ("aarch64_be-unknown-linux-gnu_ilp32", aarch64_be_unknown_linux_gnu_ilp32), | |
17df50a5 XL |
1035 | |
1036 | ("bpfeb-unknown-none", bpfeb_unknown_none), | |
1037 | ("bpfel-unknown-none", bpfel_unknown_none), | |
c295e0f8 XL |
1038 | |
1039 | ("armv6k-nintendo-3ds", armv6k_nintendo_3ds), | |
1040 | ||
064997fb FG |
1041 | ("aarch64-nintendo-switch-freestanding", aarch64_nintendo_switch_freestanding), |
1042 | ||
5099ac24 | 1043 | ("armv7-unknown-linux-uclibceabi", armv7_unknown_linux_uclibceabi), |
c295e0f8 | 1044 | ("armv7-unknown-linux-uclibceabihf", armv7_unknown_linux_uclibceabihf), |
3c0e092e XL |
1045 | |
1046 | ("x86_64-unknown-none", x86_64_unknown_none), | |
5099ac24 FG |
1047 | |
1048 | ("mips64-openwrt-linux-musl", mips64_openwrt_linux_musl), | |
7453a54e SL |
1049 | } |
1050 | ||
5e7ed085 FG |
1051 | /// Cow-Vec-Str: Cow<'static, [Cow<'static, str>]> |
1052 | macro_rules! cvs { | |
1053 | () => { | |
1054 | ::std::borrow::Cow::Borrowed(&[]) | |
1055 | }; | |
1056 | ($($x:expr),+ $(,)?) => { | |
1057 | ::std::borrow::Cow::Borrowed(&[ | |
1058 | $( | |
1059 | ::std::borrow::Cow::Borrowed($x), | |
1060 | )* | |
1061 | ]) | |
1062 | }; | |
1063 | } | |
1064 | ||
1065 | pub(crate) use cvs; | |
1066 | ||
136023e0 XL |
1067 | /// Warnings encountered when parsing the target `json`. |
1068 | /// | |
1069 | /// Includes fields that weren't recognized and fields that don't have the expected type. | |
1070 | #[derive(Debug, PartialEq)] | |
1071 | pub struct TargetWarnings { | |
1072 | unused_fields: Vec<String>, | |
1073 | incorrect_type: Vec<String>, | |
1074 | } | |
1075 | ||
1076 | impl TargetWarnings { | |
1077 | pub fn empty() -> Self { | |
1078 | Self { unused_fields: Vec::new(), incorrect_type: Vec::new() } | |
1079 | } | |
1080 | ||
1081 | pub fn warning_messages(&self) -> Vec<String> { | |
1082 | let mut warnings = vec![]; | |
1083 | if !self.unused_fields.is_empty() { | |
1084 | warnings.push(format!( | |
1085 | "target json file contains unused fields: {}", | |
1086 | self.unused_fields.join(", ") | |
1087 | )); | |
1088 | } | |
1089 | if !self.incorrect_type.is_empty() { | |
1090 | warnings.push(format!( | |
1091 | "target json file contains fields whose value doesn't have the correct json type: {}", | |
1092 | self.incorrect_type.join(", ") | |
1093 | )); | |
1094 | } | |
1095 | warnings | |
1096 | } | |
1097 | } | |
1098 | ||
1a4d82fc JJ |
1099 | /// Everything `rustc` knows about how to compile for a specific target. |
1100 | /// | |
1101 | /// Every field here must be specified, and has no default value. | |
5bcae85e | 1102 | #[derive(PartialEq, Clone, Debug)] |
1a4d82fc | 1103 | pub struct Target { |
1a4d82fc | 1104 | /// Target triple to pass to LLVM. |
5e7ed085 | 1105 | pub llvm_target: StaticCow<str>, |
29967ef6 XL |
1106 | /// Number of bits in a pointer. Influences the `target_pointer_width` `cfg` variable. |
1107 | pub pointer_width: u32, | |
416331ca XL |
1108 | /// Architecture to use for ABI considerations. Valid options include: "x86", |
1109 | /// "x86_64", "arm", "aarch64", "mips", "powerpc", "powerpc64", and others. | |
5e7ed085 | 1110 | pub arch: StaticCow<str>, |
136023e0 | 1111 | /// [Data layout](https://llvm.org/docs/LangRef.html#data-layout) to pass to LLVM. |
5e7ed085 | 1112 | pub data_layout: StaticCow<str>, |
1a4d82fc JJ |
1113 | /// Optional settings with defaults. |
1114 | pub options: TargetOptions, | |
1115 | } | |
1116 | ||
a1dfa0c6 | 1117 | pub trait HasTargetSpec { |
83c7162d XL |
1118 | fn target_spec(&self) -> &Target; |
1119 | } | |
1120 | ||
a1dfa0c6 | 1121 | impl HasTargetSpec for Target { |
17df50a5 | 1122 | #[inline] |
83c7162d XL |
1123 | fn target_spec(&self) -> &Target { |
1124 | self | |
1125 | } | |
1126 | } | |
1127 | ||
5e7ed085 FG |
1128 | type StaticCow<T> = Cow<'static, T>; |
1129 | ||
1a4d82fc JJ |
1130 | /// Optional aspects of a target specification. |
1131 | /// | |
1132 | /// This has an implementation of `Default`, see each field for what the default is. In general, | |
1133 | /// these try to take "minimal defaults" that don't assume anything about the runtime they run in. | |
29967ef6 XL |
1134 | /// |
1135 | /// `TargetOptions` as a separate structure is mostly an implementation detail of `Target` | |
1136 | /// construction, all its fields logically belong to `Target` and available from `Target` | |
1137 | /// through `Deref` impls. | |
5bcae85e | 1138 | #[derive(PartialEq, Clone, Debug)] |
1a4d82fc | 1139 | pub struct TargetOptions { |
54a0048b SL |
1140 | /// Whether the target is built-in or loaded from a custom target specification. |
1141 | pub is_builtin: bool, | |
1142 | ||
5869c6ff XL |
1143 | /// Used as the `target_endian` `cfg` variable. Defaults to little endian. |
1144 | pub endian: Endian, | |
29967ef6 | 1145 | /// Width of c_int type. Defaults to "32". |
5e7ed085 | 1146 | pub c_int_width: StaticCow<str>, |
fc512014 XL |
1147 | /// OS name to use for conditional compilation (`target_os`). Defaults to "none". |
1148 | /// "none" implies a bare metal target without `std` library. | |
1149 | /// A couple of targets having `std` also use "unknown" as an `os` value, | |
1150 | /// but they are exceptions. | |
5e7ed085 | 1151 | pub os: StaticCow<str>, |
fc512014 | 1152 | /// Environment name to use for conditional compilation (`target_env`). Defaults to "". |
5e7ed085 | 1153 | pub env: StaticCow<str>, |
136023e0 XL |
1154 | /// ABI name to distinguish multiple ABIs on the same OS and architecture. For instance, `"eabi"` |
1155 | /// or `"eabihf"`. Defaults to "". | |
5e7ed085 | 1156 | pub abi: StaticCow<str>, |
fc512014 | 1157 | /// Vendor name to use for conditional compilation (`target_vendor`). Defaults to "unknown". |
5e7ed085 | 1158 | pub vendor: StaticCow<str>, |
29967ef6 XL |
1159 | /// Default linker flavor used if `-C linker-flavor` or `-C linker` are not passed |
1160 | /// on the command line. Defaults to `LinkerFlavor::Gcc`. | |
1161 | pub linker_flavor: LinkerFlavor, | |
1162 | ||
0531ce1d | 1163 | /// Linker to invoke |
5e7ed085 | 1164 | pub linker: Option<StaticCow<str>>, |
92a42be0 | 1165 | |
ba9703b0 XL |
1166 | /// LLD flavor used if `lld` (or `rust-lld`) is specified as a linker |
1167 | /// without clarifying its flavor in any way. | |
b7449926 XL |
1168 | pub lld_flavor: LldFlavor, |
1169 | ||
94b46f34 | 1170 | /// Linker arguments that are passed *before* any user-defined libraries. |
f035d41b | 1171 | pub pre_link_args: LinkArgs, |
f9f354fc XL |
1172 | /// Objects to link before and after all other object code. |
1173 | pub pre_link_objects: CrtObjects, | |
1174 | pub post_link_objects: CrtObjects, | |
1175 | /// Same as `(pre|post)_link_objects`, but when we fail to pull the objects with help of the | |
1176 | /// target's native gcc and fall back to the "self-contained" mode and pull them manually. | |
1177 | /// See `crt_objects.rs` for some more detailed documentation. | |
1178 | pub pre_link_objects_fallback: CrtObjects, | |
1179 | pub post_link_objects_fallback: CrtObjects, | |
1180 | /// Which logic to use to determine whether to fall back to the "self-contained" mode or not. | |
1181 | pub crt_objects_fallback: Option<CrtObjectsFallback>, | |
1182 | ||
92a42be0 | 1183 | /// Linker arguments that are unconditionally passed after any |
f9f354fc | 1184 | /// user-defined but before post-link objects. Standard platform |
92a42be0 | 1185 | /// libraries that should be always be linked to, usually go here. |
cc61c64b | 1186 | pub late_link_args: LinkArgs, |
ba9703b0 XL |
1187 | /// Linker arguments used in addition to `late_link_args` if at least one |
1188 | /// Rust dependency is dynamically linked. | |
1189 | pub late_link_args_dynamic: LinkArgs, | |
5e7ed085 | 1190 | /// Linker arguments used in addition to `late_link_args` if all Rust |
ba9703b0 XL |
1191 | /// dependencies are statically linked. |
1192 | pub late_link_args_static: LinkArgs, | |
d9579d0f AL |
1193 | /// Linker arguments that are unconditionally passed *after* any |
1194 | /// user-defined libraries. | |
cc61c64b | 1195 | pub post_link_args: LinkArgs, |
f9f354fc XL |
1196 | /// Optional link script applied to `dylib` and `executable` crate types. |
1197 | /// This is a string containing the script, not a path. Can only be applied | |
1198 | /// to linkers where `linker_is_gnu` is true. | |
5e7ed085 | 1199 | pub link_script: Option<StaticCow<str>>, |
92a42be0 | 1200 | |
e1599b0c | 1201 | /// Environment variables to be set for the linker invocation. |
5e7ed085 | 1202 | pub link_env: StaticCow<[(StaticCow<str>, StaticCow<str>)]>, |
e1599b0c | 1203 | /// Environment variables to be removed for the linker invocation. |
5e7ed085 | 1204 | pub link_env_remove: StaticCow<[StaticCow<str>]>, |
041b39d2 | 1205 | |
32a655c1 | 1206 | /// Extra arguments to pass to the external assembler (when used) |
5e7ed085 | 1207 | pub asm_args: StaticCow<[StaticCow<str>]>, |
32a655c1 | 1208 | |
d9579d0f | 1209 | /// Default CPU to pass to LLVM. Corresponds to `llc -mcpu=$cpu`. Defaults |
a7813a04 | 1210 | /// to "generic". |
5e7ed085 | 1211 | pub cpu: StaticCow<str>, |
d9579d0f AL |
1212 | /// Default target features to pass to LLVM. These features will *always* be |
1213 | /// passed, and cannot be disabled even via `-C`. Corresponds to `llc | |
1214 | /// -mattr=$features`. | |
5e7ed085 | 1215 | pub features: StaticCow<str>, |
1a4d82fc JJ |
1216 | /// Whether dynamic linking is available on this target. Defaults to false. |
1217 | pub dynamic_linking: bool, | |
abe05a73 XL |
1218 | /// If dynamic linking is available, whether only cdylibs are supported. |
1219 | pub only_cdylib: bool, | |
064997fb | 1220 | /// Whether executables are available on this target. Defaults to true. |
1a4d82fc | 1221 | pub executables: bool, |
1a4d82fc | 1222 | /// Relocation model to use in object file. Corresponds to `llc |
f9f354fc XL |
1223 | /// -relocation-model=$relocation_model`. Defaults to `Pic`. |
1224 | pub relocation_model: RelocModel, | |
2c00a5a8 | 1225 | /// Code model to use. Corresponds to `llc -code-model=$code_model`. |
f9f354fc XL |
1226 | /// Defaults to `None` which means "inherited from the base LLVM target". |
1227 | pub code_model: Option<CodeModel>, | |
abe05a73 XL |
1228 | /// TLS model to use. Options are "global-dynamic" (default), "local-dynamic", "initial-exec" |
1229 | /// and "local-exec". This is similar to the -ftls-model option in GCC/Clang. | |
f9f354fc | 1230 | pub tls_model: TlsModel, |
1a4d82fc JJ |
1231 | /// Do not emit code that uses the "red zone", if the ABI has one. Defaults to false. |
1232 | pub disable_redzone: bool, | |
136023e0 XL |
1233 | /// Frame pointer mode for this target. Defaults to `MayOmit`. |
1234 | pub frame_pointer: FramePointer, | |
1a4d82fc JJ |
1235 | /// Emit each function in its own section. Defaults to true. |
1236 | pub function_sections: bool, | |
1237 | /// String to prepend to the name of every dynamic library. Defaults to "lib". | |
5e7ed085 | 1238 | pub dll_prefix: StaticCow<str>, |
1a4d82fc | 1239 | /// String to append to the name of every dynamic library. Defaults to ".so". |
5e7ed085 | 1240 | pub dll_suffix: StaticCow<str>, |
1a4d82fc | 1241 | /// String to append to the name of every executable. |
5e7ed085 | 1242 | pub exe_suffix: StaticCow<str>, |
1a4d82fc | 1243 | /// String to prepend to the name of every static library. Defaults to "lib". |
5e7ed085 | 1244 | pub staticlib_prefix: StaticCow<str>, |
1a4d82fc | 1245 | /// String to append to the name of every static library. Defaults to ".a". |
5e7ed085 | 1246 | pub staticlib_suffix: StaticCow<str>, |
17df50a5 XL |
1247 | /// Values of the `target_family` cfg set for this target. |
1248 | /// | |
1249 | /// Common options are: "unix", "windows". Defaults to no families. | |
1250 | /// | |
1251 | /// See <https://doc.rust-lang.org/reference/conditional-compilation.html#target_family>. | |
5e7ed085 | 1252 | pub families: StaticCow<[StaticCow<str>]>, |
0531ce1d XL |
1253 | /// Whether the target toolchain's ABI supports returning small structs as an integer. |
1254 | pub abi_return_struct_as_int: bool, | |
cc61c64b XL |
1255 | /// Whether the target toolchain is like macOS's. Only useful for compiling against iOS/macOS, |
1256 | /// in particular running dsymutil and some other stuff like `-dead_strip`. Defaults to false. | |
1a4d82fc | 1257 | pub is_like_osx: bool, |
7453a54e SL |
1258 | /// Whether the target toolchain is like Solaris's. |
1259 | /// Only useful for compiling against Illumos/Solaris, | |
1260 | /// as they have a different set of linker flags. Defaults to false. | |
1261 | pub is_like_solaris: bool, | |
fc512014 XL |
1262 | /// Whether the target is like Windows. |
1263 | /// This is a combination of several more specific properties represented as a single flag: | |
1264 | /// - The target uses a Windows ABI, | |
1265 | /// - uses PE/COFF as a format for object code, | |
1266 | /// - uses Windows-style dllexport/dllimport for shared libraries, | |
1267 | /// - uses import libraries and .def files for symbol exports, | |
1268 | /// - executables support setting a subsystem. | |
1a4d82fc | 1269 | pub is_like_windows: bool, |
fc512014 XL |
1270 | /// Whether the target is like MSVC. |
1271 | /// This is a combination of several more specific properties represented as a single flag: | |
1272 | /// - The target has all the properties from `is_like_windows` | |
1273 | /// (for in-tree targets "is_like_msvc ⇒ is_like_windows" is ensured by a unit test), | |
1274 | /// - has some MSVC-specific Windows ABI properties, | |
1275 | /// - uses a link.exe-like linker, | |
1276 | /// - uses CodeView/PDB for debuginfo and natvis for its visualization, | |
1277 | /// - uses SEH-based unwinding, | |
1278 | /// - supports control flow guard mechanism. | |
62682a34 | 1279 | pub is_like_msvc: bool, |
cdc7bbd5 XL |
1280 | /// Whether a target toolchain is like WASM. |
1281 | pub is_like_wasm: bool, | |
064997fb | 1282 | /// Default supported version of DWARF on this platform. |
29967ef6 | 1283 | /// Useful because some platforms (osx, bsd) only want up to DWARF2. |
064997fb | 1284 | pub default_dwarf_version: u32, |
17df50a5 | 1285 | /// Whether the linker support GNU-like arguments such as -O. Defaults to true. |
1a4d82fc | 1286 | pub linker_is_gnu: bool, |
5bcae85e | 1287 | /// The MinGW toolchain has a known issue that prevents it from correctly |
ff7c6d11 | 1288 | /// handling COFF object files with more than 2<sup>15</sup> sections. Since each weak |
5bcae85e SL |
1289 | /// symbol needs its own COMDAT section, weak linkage implies a large |
1290 | /// number sections that easily exceeds the given limit for larger | |
1291 | /// codebases. Consequently we want a way to disallow weak linkage on some | |
1292 | /// platforms. | |
1293 | pub allows_weak_linkage: bool, | |
1a4d82fc JJ |
1294 | /// Whether the linker support rpaths or not. Defaults to false. |
1295 | pub has_rpath: bool, | |
b039eaaf SL |
1296 | /// Whether to disable linking to the default libraries, typically corresponds |
1297 | /// to `-nodefaultlibs`. Defaults to true. | |
1298 | pub no_default_libraries: bool, | |
62682a34 SL |
1299 | /// Dynamically linked executables can be compiled as position independent |
1300 | /// if the default relocation model of position independent code is not | |
1301 | /// changed. This is a requirement to take advantage of ASLR, as otherwise | |
1302 | /// the functions in the executable are not randomized and can be used | |
1303 | /// during an exploit of a vulnerability in any code. | |
1a4d82fc | 1304 | pub position_independent_executables: bool, |
f9f354fc XL |
1305 | /// Executables that are both statically linked and position-independent are supported. |
1306 | pub static_position_independent_executables: bool, | |
0bf4aa26 XL |
1307 | /// Determines if the target always requires using the PLT for indirect |
1308 | /// library calls or not. This controls the default value of the `-Z plt` flag. | |
1309 | pub needs_plt: bool, | |
3b2f2976 XL |
1310 | /// Either partial, full, or off. Full RELRO makes the dynamic linker |
1311 | /// resolve all symbols at startup and marks the GOT read-only before | |
1312 | /// starting the program, preventing overwriting the GOT. | |
1313 | pub relro_level: RelroLevel, | |
c1a9b12d SL |
1314 | /// Format that archives should be emitted in. This affects whether we use |
1315 | /// LLVM to assemble an archive or fall back to the system linker, and | |
1316 | /// currently only "gnu" is used to fall into LLVM. Unknown strings cause | |
1317 | /// the system linker to be used. | |
5e7ed085 | 1318 | pub archive_format: StaticCow<str>, |
e9174d1e SL |
1319 | /// Is asm!() allowed? Defaults to true. |
1320 | pub allow_asm: bool, | |
e74abb32 XL |
1321 | /// Whether the runtime startup code requires the `main` function be passed |
1322 | /// `argc` and `argv` values. | |
1323 | pub main_needs_argc_argv: bool, | |
e9174d1e | 1324 | |
a2a8927a XL |
1325 | /// Flag indicating whether #[thread_local] is available for this target. |
1326 | pub has_thread_local: bool, | |
7453a54e SL |
1327 | // This is mainly for easy compatibility with emscripten. |
1328 | // If we give emcc .o files that are actually .bc files it | |
1329 | // will 'just work'. | |
1330 | pub obj_is_bitcode: bool, | |
f9f354fc XL |
1331 | /// Whether the target requires that emitted object code includes bitcode. |
1332 | pub forces_embed_bitcode: bool, | |
1333 | /// Content of the LLVM cmdline section associated with embedded bitcode. | |
5e7ed085 | 1334 | pub bitcode_llvm_cmdline: StaticCow<str>, |
a7813a04 | 1335 | |
32a655c1 SL |
1336 | /// Don't use this field; instead use the `.min_atomic_width()` method. |
1337 | pub min_atomic_width: Option<u64>, | |
1338 | ||
c30ab7b3 SL |
1339 | /// Don't use this field; instead use the `.max_atomic_width()` method. |
1340 | pub max_atomic_width: Option<u64>, | |
1341 | ||
8faf50e0 XL |
1342 | /// Whether the target supports atomic CAS operations natively |
1343 | pub atomic_cas: bool, | |
1344 | ||
c30ab7b3 SL |
1345 | /// Panic strategy: "unwind" or "abort" |
1346 | pub panic_strategy: PanicStrategy, | |
1347 | ||
3b2f2976 XL |
1348 | /// Whether or not linking dylibs to a static CRT is allowed. |
1349 | pub crt_static_allows_dylibs: bool, | |
476ff2be SL |
1350 | /// Whether or not the CRT is statically linked by default. |
1351 | pub crt_static_default: bool, | |
3b2f2976 XL |
1352 | /// Whether or not crt-static is respected by the compiler (or is a no-op). |
1353 | pub crt_static_respected: bool, | |
041b39d2 | 1354 | |
5869c6ff XL |
1355 | /// The implementation of stack probes to use. |
1356 | pub stack_probes: StackProbeType, | |
ea8adc8c XL |
1357 | |
1358 | /// The minimum alignment for global symbols. | |
1359 | pub min_global_align: Option<u64>, | |
abe05a73 XL |
1360 | |
1361 | /// Default number of codegen units to use in debug mode | |
1362 | pub default_codegen_units: Option<u64>, | |
1363 | ||
1364 | /// Whether to generate trap instructions in places where optimization would | |
1365 | /// otherwise produce control flow that falls through into unrelated memory. | |
1366 | pub trap_unreachable: bool, | |
1367 | ||
1368 | /// This target requires everything to be compiled with LTO to emit a final | |
1369 | /// executable, aka there is no native linker for this target. | |
1370 | pub requires_lto: bool, | |
1371 | ||
1372 | /// This target has no support for threads. | |
1373 | pub singlethread: bool, | |
1374 | ||
1375 | /// Whether library functions call lowering/optimization is disabled in LLVM | |
1376 | /// for this target unconditionally. | |
1377 | pub no_builtins: bool, | |
ff7c6d11 | 1378 | |
2c00a5a8 XL |
1379 | /// The default visibility for symbols in this target should be "hidden" |
1380 | /// rather than "default" | |
1381 | pub default_hidden_visibility: bool, | |
0531ce1d | 1382 | |
83c7162d XL |
1383 | /// Whether a .debug_gdb_scripts section will be added to the output object file |
1384 | pub emit_debug_gdb_scripts: bool, | |
1385 | ||
1386 | /// Whether or not to unconditionally `uwtable` attributes on functions, | |
1387 | /// typically because the platform needs to unwind for things like stack | |
1388 | /// unwinders. | |
1389 | pub requires_uwtable: bool, | |
0bf4aa26 | 1390 | |
cdc7bbd5 XL |
1391 | /// Whether or not to emit `uwtable` attributes on functions if `-C force-unwind-tables` |
1392 | /// is not specified and `uwtable` is not required on this target. | |
1393 | pub default_uwtable: bool, | |
1394 | ||
0bf4aa26 XL |
1395 | /// Whether or not SIMD types are passed by reference in the Rust ABI, |
1396 | /// typically required if a target can be compiled with a mixed set of | |
1397 | /// target features. This is `true` by default, and `false` for targets like | |
1398 | /// wasm32 where the whole program either has simd or not. | |
1399 | pub simd_types_indirect: bool, | |
a1dfa0c6 | 1400 | |
dc9dc135 XL |
1401 | /// Pass a list of symbol which should be exported in the dylib to the linker. |
1402 | pub limit_rdylib_exports: bool, | |
1403 | ||
a1dfa0c6 XL |
1404 | /// If set, have the linker export exactly these symbols, instead of using |
1405 | /// the usual logic to figure this out from the crate itself. | |
5e7ed085 | 1406 | pub override_export_symbols: Option<StaticCow<[StaticCow<str>]>>, |
9fa01778 XL |
1407 | |
1408 | /// Determines how or whether the MergeFunctions LLVM pass should run for | |
1409 | /// this target. Either "disabled", "trampolines", or "aliases". | |
1410 | /// The MergeFunctions pass is generally useful, but some targets may need | |
1411 | /// to opt out. The default is "aliases". | |
1412 | /// | |
29967ef6 | 1413 | /// Workaround for: <https://github.com/rust-lang/rust/issues/57356> |
532ac7d7 XL |
1414 | pub merge_functions: MergeFunctions, |
1415 | ||
1416 | /// Use platform dependent mcount function | |
5e7ed085 | 1417 | pub mcount: StaticCow<str>, |
60c5eb7d XL |
1418 | |
1419 | /// LLVM ABI name, corresponds to the '-mabi' parameter available in multilib C compilers | |
5e7ed085 | 1420 | pub llvm_abiname: StaticCow<str>, |
60c5eb7d XL |
1421 | |
1422 | /// Whether or not RelaxElfRelocation flag will be passed to the linker | |
1423 | pub relax_elf_relocations: bool, | |
dfeec247 XL |
1424 | |
1425 | /// Additional arguments to pass to LLVM, similar to the `-C llvm-args` codegen option. | |
5e7ed085 | 1426 | pub llvm_args: StaticCow<[StaticCow<str>]>, |
f9f354fc XL |
1427 | |
1428 | /// Whether to use legacy .ctors initialization hooks rather than .init_array. Defaults | |
1429 | /// to false (uses .init_array). | |
1430 | pub use_ctors_section: bool, | |
f9652781 XL |
1431 | |
1432 | /// Whether the linker is instructed to add a `GNU_EH_FRAME` ELF header | |
1433 | /// used to locate unwinding information is passed | |
1434 | /// (only has effect if the linker is `ld`-like). | |
1435 | pub eh_frame_header: bool, | |
29967ef6 XL |
1436 | |
1437 | /// Is true if the target is an ARM architecture using thumb v1 which allows for | |
1438 | /// thumb and arm interworking. | |
1439 | pub has_thumb_interworking: bool, | |
5869c6ff XL |
1440 | |
1441 | /// How to handle split debug information, if at all. Specifying `None` has | |
1442 | /// target-specific meaning. | |
1443 | pub split_debuginfo: SplitDebuginfo, | |
cdc7bbd5 XL |
1444 | |
1445 | /// The sanitizers supported by this target | |
1446 | /// | |
1447 | /// Note that the support here is at a codegen level. If the machine code with sanitizer | |
1448 | /// enabled can generated on this target, but the necessary supporting libraries are not | |
1449 | /// distributed with the target, the sanitizer should still appear in this list for the target. | |
1450 | pub supported_sanitizers: SanitizerSet, | |
1451 | ||
1452 | /// If present it's a default value to use for adjusting the C ABI. | |
1453 | pub default_adjusted_cabi: Option<Abi>, | |
94222f64 XL |
1454 | |
1455 | /// Minimum number of bits in #[repr(C)] enum. Defaults to 32. | |
1456 | pub c_enum_min_bits: u64, | |
3c0e092e XL |
1457 | |
1458 | /// Whether or not the DWARF `.debug_aranges` section should be generated. | |
1459 | pub generate_arange_section: bool, | |
1460 | ||
1461 | /// Whether the target supports stack canary checks. `true` by default, | |
1462 | /// since this is most common among tier 1 and tier 2 targets. | |
1463 | pub supports_stack_protector: bool, | |
1a4d82fc JJ |
1464 | } |
1465 | ||
064997fb FG |
1466 | /// Add arguments for the given flavor and also for its "twin" flavors |
1467 | /// that have a compatible command line interface. | |
1468 | fn add_link_args(link_args: &mut LinkArgs, flavor: LinkerFlavor, args: &[&'static str]) { | |
1469 | let mut insert = |flavor| { | |
1470 | link_args.entry(flavor).or_default().extend(args.iter().copied().map(Cow::Borrowed)) | |
1471 | }; | |
1472 | insert(flavor); | |
1473 | match flavor { | |
1474 | LinkerFlavor::Ld => insert(LinkerFlavor::Lld(LldFlavor::Ld)), | |
1475 | LinkerFlavor::Msvc => insert(LinkerFlavor::Lld(LldFlavor::Link)), | |
1476 | LinkerFlavor::Lld(LldFlavor::Wasm) => {} | |
1477 | LinkerFlavor::Lld(lld_flavor) => { | |
1478 | panic!("add_link_args: use non-LLD flavor for {:?}", lld_flavor) | |
1479 | } | |
1480 | LinkerFlavor::Gcc | |
1481 | | LinkerFlavor::Em | |
1482 | | LinkerFlavor::L4Bender | |
1483 | | LinkerFlavor::BpfLinker | |
1484 | | LinkerFlavor::PtxLinker => {} | |
1485 | } | |
1486 | } | |
1487 | ||
1488 | impl TargetOptions { | |
1489 | fn link_args(flavor: LinkerFlavor, args: &[&'static str]) -> LinkArgs { | |
1490 | let mut link_args = LinkArgs::new(); | |
1491 | add_link_args(&mut link_args, flavor, args); | |
1492 | link_args | |
1493 | } | |
1494 | ||
1495 | fn add_pre_link_args(&mut self, flavor: LinkerFlavor, args: &[&'static str]) { | |
1496 | add_link_args(&mut self.pre_link_args, flavor, args); | |
1497 | } | |
1498 | ||
1499 | fn add_post_link_args(&mut self, flavor: LinkerFlavor, args: &[&'static str]) { | |
1500 | add_link_args(&mut self.post_link_args, flavor, args); | |
1501 | } | |
1502 | } | |
1503 | ||
1a4d82fc | 1504 | impl Default for TargetOptions { |
9fa01778 | 1505 | /// Creates a set of "sane defaults" for any target. This is still |
62682a34 | 1506 | /// incomplete, and if used for compilation, will certainly not work. |
1a4d82fc JJ |
1507 | fn default() -> TargetOptions { |
1508 | TargetOptions { | |
54a0048b | 1509 | is_builtin: false, |
5869c6ff | 1510 | endian: Endian::Little, |
5e7ed085 FG |
1511 | c_int_width: "32".into(), |
1512 | os: "none".into(), | |
1513 | env: "".into(), | |
1514 | abi: "".into(), | |
1515 | vendor: "unknown".into(), | |
29967ef6 | 1516 | linker_flavor: LinkerFlavor::Gcc, |
5e7ed085 | 1517 | linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.into()), |
b7449926 | 1518 | lld_flavor: LldFlavor::Ld, |
cc61c64b XL |
1519 | pre_link_args: LinkArgs::new(), |
1520 | post_link_args: LinkArgs::new(), | |
f9f354fc | 1521 | link_script: None, |
5e7ed085 FG |
1522 | asm_args: cvs![], |
1523 | cpu: "generic".into(), | |
1524 | features: "".into(), | |
1a4d82fc | 1525 | dynamic_linking: false, |
abe05a73 | 1526 | only_cdylib: false, |
064997fb | 1527 | executables: true, |
f9f354fc | 1528 | relocation_model: RelocModel::Pic, |
2c00a5a8 | 1529 | code_model: None, |
f9f354fc | 1530 | tls_model: TlsModel::GeneralDynamic, |
1a4d82fc | 1531 | disable_redzone: false, |
136023e0 | 1532 | frame_pointer: FramePointer::MayOmit, |
1a4d82fc | 1533 | function_sections: true, |
5e7ed085 FG |
1534 | dll_prefix: "lib".into(), |
1535 | dll_suffix: ".so".into(), | |
1536 | exe_suffix: "".into(), | |
1537 | staticlib_prefix: "lib".into(), | |
1538 | staticlib_suffix: ".a".into(), | |
1539 | families: cvs![], | |
0531ce1d | 1540 | abi_return_struct_as_int: false, |
1a4d82fc | 1541 | is_like_osx: false, |
7453a54e | 1542 | is_like_solaris: false, |
1a4d82fc | 1543 | is_like_windows: false, |
62682a34 | 1544 | is_like_msvc: false, |
cdc7bbd5 | 1545 | is_like_wasm: false, |
064997fb | 1546 | default_dwarf_version: 4, |
17df50a5 | 1547 | linker_is_gnu: true, |
5bcae85e | 1548 | allows_weak_linkage: true, |
1a4d82fc | 1549 | has_rpath: false, |
b039eaaf | 1550 | no_default_libraries: true, |
1a4d82fc | 1551 | position_independent_executables: false, |
f9f354fc | 1552 | static_position_independent_executables: false, |
0bf4aa26 | 1553 | needs_plt: false, |
0531ce1d | 1554 | relro_level: RelroLevel::None, |
f9f354fc XL |
1555 | pre_link_objects: Default::default(), |
1556 | post_link_objects: Default::default(), | |
1557 | pre_link_objects_fallback: Default::default(), | |
1558 | post_link_objects_fallback: Default::default(), | |
1559 | crt_objects_fallback: None, | |
cc61c64b | 1560 | late_link_args: LinkArgs::new(), |
ba9703b0 XL |
1561 | late_link_args_dynamic: LinkArgs::new(), |
1562 | late_link_args_static: LinkArgs::new(), | |
5e7ed085 FG |
1563 | link_env: cvs![], |
1564 | link_env_remove: cvs![], | |
1565 | archive_format: "gnu".into(), | |
e74abb32 | 1566 | main_needs_argc_argv: true, |
e9174d1e | 1567 | allow_asm: true, |
a2a8927a | 1568 | has_thread_local: false, |
7453a54e | 1569 | obj_is_bitcode: false, |
f9f354fc | 1570 | forces_embed_bitcode: false, |
5e7ed085 | 1571 | bitcode_llvm_cmdline: "".into(), |
32a655c1 | 1572 | min_atomic_width: None, |
c30ab7b3 | 1573 | max_atomic_width: None, |
8faf50e0 | 1574 | atomic_cas: true, |
c30ab7b3 | 1575 | panic_strategy: PanicStrategy::Unwind, |
3b2f2976 | 1576 | crt_static_allows_dylibs: false, |
476ff2be | 1577 | crt_static_default: false, |
3b2f2976 | 1578 | crt_static_respected: false, |
5869c6ff | 1579 | stack_probes: StackProbeType::None, |
ea8adc8c | 1580 | min_global_align: None, |
abe05a73 XL |
1581 | default_codegen_units: None, |
1582 | trap_unreachable: true, | |
1583 | requires_lto: false, | |
1584 | singlethread: false, | |
1585 | no_builtins: false, | |
2c00a5a8 | 1586 | default_hidden_visibility: false, |
83c7162d XL |
1587 | emit_debug_gdb_scripts: true, |
1588 | requires_uwtable: false, | |
cdc7bbd5 | 1589 | default_uwtable: false, |
0bf4aa26 | 1590 | simd_types_indirect: true, |
dc9dc135 | 1591 | limit_rdylib_exports: true, |
a1dfa0c6 | 1592 | override_export_symbols: None, |
9fa01778 | 1593 | merge_functions: MergeFunctions::Aliases, |
5e7ed085 FG |
1594 | mcount: "mcount".into(), |
1595 | llvm_abiname: "".into(), | |
60c5eb7d | 1596 | relax_elf_relocations: false, |
5e7ed085 | 1597 | llvm_args: cvs![], |
f9f354fc | 1598 | use_ctors_section: false, |
f9652781 | 1599 | eh_frame_header: true, |
29967ef6 | 1600 | has_thumb_interworking: false, |
5869c6ff | 1601 | split_debuginfo: SplitDebuginfo::Off, |
cdc7bbd5 XL |
1602 | supported_sanitizers: SanitizerSet::empty(), |
1603 | default_adjusted_cabi: None, | |
94222f64 | 1604 | c_enum_min_bits: 32, |
3c0e092e XL |
1605 | generate_arange_section: true, |
1606 | supports_stack_protector: true, | |
1a4d82fc JJ |
1607 | } |
1608 | } | |
1609 | } | |
1610 | ||
29967ef6 XL |
1611 | /// `TargetOptions` being a separate type is basically an implementation detail of `Target` that is |
1612 | /// used for providing defaults. Perhaps there's a way to merge `TargetOptions` into `Target` so | |
1613 | /// this `Deref` implementation is no longer necessary. | |
1614 | impl Deref for Target { | |
1615 | type Target = TargetOptions; | |
1616 | ||
5099ac24 | 1617 | #[inline] |
29967ef6 XL |
1618 | fn deref(&self) -> &Self::Target { |
1619 | &self.options | |
1620 | } | |
1621 | } | |
1622 | impl DerefMut for Target { | |
5099ac24 | 1623 | #[inline] |
29967ef6 XL |
1624 | fn deref_mut(&mut self) -> &mut Self::Target { |
1625 | &mut self.options | |
1626 | } | |
1627 | } | |
1628 | ||
1a4d82fc | 1629 | impl Target { |
0bf4aa26 | 1630 | /// Given a function ABI, turn it into the correct ABI for this target. |
7453a54e | 1631 | pub fn adjust_abi(&self, abi: Abi) -> Abi { |
1a4d82fc | 1632 | match abi { |
136023e0 XL |
1633 | Abi::C { .. } => self.default_adjusted_cabi.unwrap_or(abi), |
1634 | Abi::System { unwind } if self.is_like_windows && self.arch == "x86" => { | |
1635 | Abi::Stdcall { unwind } | |
dfeec247 | 1636 | } |
136023e0 | 1637 | Abi::System { unwind } => Abi::C { unwind }, |
5099ac24 | 1638 | Abi::EfiApi if self.arch == "x86_64" => Abi::Win64 { unwind: false }, |
136023e0 | 1639 | Abi::EfiApi => Abi::C { unwind: false }, |
cdc7bbd5 | 1640 | |
136023e0 XL |
1641 | // See commentary in `is_abi_supported`. |
1642 | Abi::Stdcall { .. } | Abi::Thiscall { .. } if self.arch == "x86" => abi, | |
1643 | Abi::Stdcall { unwind } | Abi::Thiscall { unwind } => Abi::C { unwind }, | |
5099ac24 FG |
1644 | Abi::Fastcall { .. } if self.arch == "x86" => abi, |
1645 | Abi::Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => abi, | |
1646 | Abi::Fastcall { unwind } | Abi::Vectorcall { unwind } => Abi::C { unwind }, | |
cdc7bbd5 | 1647 | |
dfeec247 | 1648 | abi => abi, |
1a4d82fc JJ |
1649 | } |
1650 | } | |
1651 | ||
136023e0 XL |
1652 | /// Returns a None if the UNSUPPORTED_CALLING_CONVENTIONS lint should be emitted |
1653 | pub fn is_abi_supported(&self, abi: Abi) -> Option<bool> { | |
1654 | use Abi::*; | |
1655 | Some(match abi { | |
1656 | Rust | |
1657 | | C { .. } | |
1658 | | System { .. } | |
1659 | | RustIntrinsic | |
1660 | | RustCall | |
1661 | | PlatformIntrinsic | |
1662 | | Unadjusted | |
5099ac24 | 1663 | | Cdecl { .. } |
923072b8 FG |
1664 | | EfiApi |
1665 | | RustCold => true, | |
136023e0 | 1666 | X86Interrupt => ["x86", "x86_64"].contains(&&self.arch[..]), |
5099ac24 | 1667 | Aapcs { .. } => "arm" == self.arch, |
94222f64 | 1668 | CCmseNonSecureCall => ["arm", "aarch64"].contains(&&self.arch[..]), |
5099ac24 | 1669 | Win64 { .. } | SysV64 { .. } => self.arch == "x86_64", |
136023e0 XL |
1670 | PtxKernel => self.arch == "nvptx64", |
1671 | Msp430Interrupt => self.arch == "msp430", | |
1672 | AmdGpuKernel => self.arch == "amdgcn", | |
1673 | AvrInterrupt | AvrNonBlockingInterrupt => self.arch == "avr", | |
1674 | Wasm => ["wasm32", "wasm64"].contains(&&self.arch[..]), | |
3c0e092e | 1675 | Thiscall { .. } => self.arch == "x86", |
136023e0 XL |
1676 | // On windows these fall-back to platform native calling convention (C) when the |
1677 | // architecture is not supported. | |
1678 | // | |
1679 | // This is I believe a historical accident that has occurred as part of Microsoft | |
1680 | // striving to allow most of the code to "just" compile when support for 64-bit x86 | |
1681 | // was added and then later again, when support for ARM architectures was added. | |
1682 | // | |
1683 | // This is well documented across MSDN. Support for this in Rust has been added in | |
1684 | // #54576. This makes much more sense in context of Microsoft's C++ than it does in | |
1685 | // Rust, but there isn't much leeway remaining here to change it back at the time this | |
1686 | // comment has been written. | |
1687 | // | |
1688 | // Following are the relevant excerpts from the MSDN documentation. | |
1689 | // | |
1690 | // > The __vectorcall calling convention is only supported in native code on x86 and | |
1691 | // x64 processors that include Streaming SIMD Extensions 2 (SSE2) and above. | |
1692 | // > ... | |
1693 | // > On ARM machines, __vectorcall is accepted and ignored by the compiler. | |
1694 | // | |
1695 | // -- https://docs.microsoft.com/en-us/cpp/cpp/vectorcall?view=msvc-160 | |
1696 | // | |
1697 | // > On ARM and x64 processors, __stdcall is accepted and ignored by the compiler; | |
1698 | // | |
1699 | // -- https://docs.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-160 | |
1700 | // | |
1701 | // > In most cases, keywords or compiler switches that specify an unsupported | |
1702 | // > convention on a particular platform are ignored, and the platform default | |
1703 | // > convention is used. | |
1704 | // | |
1705 | // -- https://docs.microsoft.com/en-us/cpp/cpp/argument-passing-and-naming-conventions | |
5099ac24 | 1706 | Stdcall { .. } | Fastcall { .. } | Vectorcall { .. } if self.is_like_windows => true, |
136023e0 XL |
1707 | // Outside of Windows we want to only support these calling conventions for the |
1708 | // architectures for which these calling conventions are actually well defined. | |
5099ac24 FG |
1709 | Stdcall { .. } | Fastcall { .. } if self.arch == "x86" => true, |
1710 | Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => true, | |
136023e0 | 1711 | // Return a `None` for other cases so that we know to emit a future compat lint. |
5099ac24 | 1712 | Stdcall { .. } | Fastcall { .. } | Vectorcall { .. } => return None, |
136023e0 XL |
1713 | }) |
1714 | } | |
1715 | ||
32a655c1 SL |
1716 | /// Minimum integer size in bits that this target can perform atomic |
1717 | /// operations on. | |
1718 | pub fn min_atomic_width(&self) -> u64 { | |
29967ef6 | 1719 | self.min_atomic_width.unwrap_or(8) |
32a655c1 SL |
1720 | } |
1721 | ||
c30ab7b3 SL |
1722 | /// Maximum integer size in bits that this target can perform atomic |
1723 | /// operations on. | |
1724 | pub fn max_atomic_width(&self) -> u64 { | |
29967ef6 | 1725 | self.max_atomic_width.unwrap_or_else(|| self.pointer_width.into()) |
c30ab7b3 SL |
1726 | } |
1727 | ||
9fa01778 | 1728 | /// Loads a target descriptor from a JSON object. |
923072b8 | 1729 | pub fn from_json(obj: Json) -> Result<(Target, TargetWarnings), String> { |
5bcae85e SL |
1730 | // While ugly, this code must remain this way to retain |
1731 | // compatibility with existing JSON fields and the internal | |
1732 | // expected naming of the Target and TargetOptions structs. | |
1733 | // To ensure compatibility is retained, the built-in targets | |
1734 | // are round-tripped through this code to catch cases where | |
1735 | // the JSON parser is not updated to match the structs. | |
1a4d82fc | 1736 | |
923072b8 FG |
1737 | let mut obj = match obj { |
1738 | Value::Object(obj) => obj, | |
1739 | _ => return Err("Expected JSON object for target")?, | |
1740 | }; | |
1741 | ||
136023e0 | 1742 | let mut get_req_field = |name: &str| { |
923072b8 FG |
1743 | obj.remove(name) |
1744 | .and_then(|j| j.as_str().map(str::to_string)) | |
dfeec247 | 1745 | .ok_or_else(|| format!("Field {} in target specification is required", name)) |
1a4d82fc JJ |
1746 | }; |
1747 | ||
1748 | let mut base = Target { | |
5e7ed085 | 1749 | llvm_target: get_req_field("llvm-target")?.into(), |
29967ef6 XL |
1750 | pointer_width: get_req_field("target-pointer-width")? |
1751 | .parse::<u32>() | |
1752 | .map_err(|_| "target-pointer-width must be an integer".to_string())?, | |
5e7ed085 FG |
1753 | data_layout: get_req_field("data-layout")?.into(), |
1754 | arch: get_req_field("arch")?.into(), | |
1a4d82fc JJ |
1755 | options: Default::default(), |
1756 | }; | |
1757 | ||
136023e0 XL |
1758 | let mut incorrect_type = vec![]; |
1759 | ||
1a4d82fc JJ |
1760 | macro_rules! key { |
1761 | ($key_name:ident) => ( { | |
1762 | let name = (stringify!($key_name)).replace("_", "-"); | |
923072b8 | 1763 | if let Some(s) = obj.remove(&name).and_then(|s| s.as_str().map(str::to_string).map(Cow::from)) { |
136023e0 | 1764 | base.$key_name = s; |
29967ef6 XL |
1765 | } |
1766 | } ); | |
1767 | ($key_name:ident = $json_name:expr) => ( { | |
1768 | let name = $json_name; | |
923072b8 | 1769 | if let Some(s) = obj.remove(name).and_then(|s| s.as_str().map(str::to_string).map(Cow::from)) { |
136023e0 | 1770 | base.$key_name = s; |
f9f354fc | 1771 | } |
1a4d82fc JJ |
1772 | } ); |
1773 | ($key_name:ident, bool) => ( { | |
1774 | let name = (stringify!($key_name)).replace("_", "-"); | |
923072b8 | 1775 | if let Some(s) = obj.remove(&name).and_then(|b| b.as_bool()) { |
29967ef6 XL |
1776 | base.$key_name = s; |
1777 | } | |
1778 | } ); | |
94222f64 XL |
1779 | ($key_name:ident, u64) => ( { |
1780 | let name = (stringify!($key_name)).replace("_", "-"); | |
923072b8 | 1781 | if let Some(s) = obj.remove(&name).and_then(|j| Json::as_u64(&j)) { |
94222f64 XL |
1782 | base.$key_name = s; |
1783 | } | |
1784 | } ); | |
064997fb | 1785 | ($key_name:ident, u32) => ( { |
29967ef6 | 1786 | let name = (stringify!($key_name)).replace("_", "-"); |
923072b8 | 1787 | if let Some(s) = obj.remove(&name).and_then(|b| b.as_u64()) { |
29967ef6 | 1788 | if s < 1 || s > 5 { |
5e7ed085 | 1789 | return Err("Not a valid DWARF version number".into()); |
29967ef6 | 1790 | } |
064997fb | 1791 | base.$key_name = s as u32; |
f9f354fc | 1792 | } |
1a4d82fc | 1793 | } ); |
c30ab7b3 | 1794 | ($key_name:ident, Option<u64>) => ( { |
a7813a04 | 1795 | let name = (stringify!($key_name)).replace("_", "-"); |
923072b8 | 1796 | if let Some(s) = obj.remove(&name).and_then(|b| b.as_u64()) { |
29967ef6 | 1797 | base.$key_name = Some(s); |
f9f354fc | 1798 | } |
c30ab7b3 | 1799 | } ); |
9fa01778 XL |
1800 | ($key_name:ident, MergeFunctions) => ( { |
1801 | let name = (stringify!($key_name)).replace("_", "-"); | |
923072b8 | 1802 | obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { |
9fa01778 | 1803 | match s.parse::<MergeFunctions>() { |
29967ef6 | 1804 | Ok(mergefunc) => base.$key_name = mergefunc, |
9fa01778 XL |
1805 | _ => return Some(Err(format!("'{}' is not a valid value for \ |
1806 | merge-functions. Use 'disabled', \ | |
1807 | 'trampolines', or 'aliases'.", | |
1808 | s))), | |
1809 | } | |
1810 | Some(Ok(())) | |
1811 | })).unwrap_or(Ok(())) | |
1812 | } ); | |
f9f354fc XL |
1813 | ($key_name:ident, RelocModel) => ( { |
1814 | let name = (stringify!($key_name)).replace("_", "-"); | |
923072b8 | 1815 | obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { |
f9f354fc | 1816 | match s.parse::<RelocModel>() { |
29967ef6 | 1817 | Ok(relocation_model) => base.$key_name = relocation_model, |
f9f354fc XL |
1818 | _ => return Some(Err(format!("'{}' is not a valid relocation model. \ |
1819 | Run `rustc --print relocation-models` to \ | |
1820 | see the list of supported values.", s))), | |
1821 | } | |
1822 | Some(Ok(())) | |
1823 | })).unwrap_or(Ok(())) | |
1824 | } ); | |
1825 | ($key_name:ident, CodeModel) => ( { | |
1826 | let name = (stringify!($key_name)).replace("_", "-"); | |
923072b8 | 1827 | obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { |
f9f354fc | 1828 | match s.parse::<CodeModel>() { |
29967ef6 | 1829 | Ok(code_model) => base.$key_name = Some(code_model), |
f9f354fc XL |
1830 | _ => return Some(Err(format!("'{}' is not a valid code model. \ |
1831 | Run `rustc --print code-models` to \ | |
1832 | see the list of supported values.", s))), | |
1833 | } | |
1834 | Some(Ok(())) | |
1835 | })).unwrap_or(Ok(())) | |
1836 | } ); | |
1837 | ($key_name:ident, TlsModel) => ( { | |
1838 | let name = (stringify!($key_name)).replace("_", "-"); | |
923072b8 | 1839 | obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { |
f9f354fc | 1840 | match s.parse::<TlsModel>() { |
29967ef6 | 1841 | Ok(tls_model) => base.$key_name = tls_model, |
f9f354fc XL |
1842 | _ => return Some(Err(format!("'{}' is not a valid TLS model. \ |
1843 | Run `rustc --print tls-models` to \ | |
1844 | see the list of supported values.", s))), | |
1845 | } | |
1846 | Some(Ok(())) | |
1847 | })).unwrap_or(Ok(())) | |
1848 | } ); | |
c30ab7b3 SL |
1849 | ($key_name:ident, PanicStrategy) => ( { |
1850 | let name = (stringify!($key_name)).replace("_", "-"); | |
923072b8 | 1851 | obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { |
c30ab7b3 | 1852 | match s { |
29967ef6 XL |
1853 | "unwind" => base.$key_name = PanicStrategy::Unwind, |
1854 | "abort" => base.$key_name = PanicStrategy::Abort, | |
c30ab7b3 SL |
1855 | _ => return Some(Err(format!("'{}' is not a valid value for \ |
1856 | panic-strategy. Use 'unwind' or 'abort'.", | |
1857 | s))), | |
1858 | } | |
1859 | Some(Ok(())) | |
1860 | })).unwrap_or(Ok(())) | |
a7813a04 | 1861 | } ); |
3b2f2976 XL |
1862 | ($key_name:ident, RelroLevel) => ( { |
1863 | let name = (stringify!($key_name)).replace("_", "-"); | |
923072b8 | 1864 | obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { |
3b2f2976 | 1865 | match s.parse::<RelroLevel>() { |
29967ef6 | 1866 | Ok(level) => base.$key_name = level, |
3b2f2976 XL |
1867 | _ => return Some(Err(format!("'{}' is not a valid value for \ |
1868 | relro-level. Use 'full', 'partial, or 'off'.", | |
1869 | s))), | |
1870 | } | |
1871 | Some(Ok(())) | |
1872 | })).unwrap_or(Ok(())) | |
1873 | } ); | |
5869c6ff XL |
1874 | ($key_name:ident, SplitDebuginfo) => ( { |
1875 | let name = (stringify!($key_name)).replace("_", "-"); | |
923072b8 | 1876 | obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { |
5869c6ff XL |
1877 | match s.parse::<SplitDebuginfo>() { |
1878 | Ok(level) => base.$key_name = level, | |
1879 | _ => return Some(Err(format!("'{}' is not a valid value for \ | |
1880 | split-debuginfo. Use 'off' or 'dsymutil'.", | |
1881 | s))), | |
1882 | } | |
1883 | Some(Ok(())) | |
1884 | })).unwrap_or(Ok(())) | |
1885 | } ); | |
1a4d82fc JJ |
1886 | ($key_name:ident, list) => ( { |
1887 | let name = (stringify!($key_name)).replace("_", "-"); | |
923072b8 FG |
1888 | if let Some(j) = obj.remove(&name) { |
1889 | if let Some(v) = j.as_array() { | |
136023e0 | 1890 | base.$key_name = v.iter() |
923072b8 | 1891 | .map(|a| a.as_str().unwrap().to_string().into()) |
136023e0 XL |
1892 | .collect(); |
1893 | } else { | |
1894 | incorrect_type.push(name) | |
1895 | } | |
f9f354fc | 1896 | } |
1a4d82fc | 1897 | } ); |
a1dfa0c6 XL |
1898 | ($key_name:ident, opt_list) => ( { |
1899 | let name = (stringify!($key_name)).replace("_", "-"); | |
923072b8 FG |
1900 | if let Some(j) = obj.remove(&name) { |
1901 | if let Some(v) = j.as_array() { | |
136023e0 | 1902 | base.$key_name = Some(v.iter() |
923072b8 | 1903 | .map(|a| a.as_str().unwrap().to_string().into()) |
136023e0 XL |
1904 | .collect()); |
1905 | } else { | |
1906 | incorrect_type.push(name) | |
1907 | } | |
f9f354fc | 1908 | } |
a1dfa0c6 | 1909 | } ); |
e9174d1e SL |
1910 | ($key_name:ident, optional) => ( { |
1911 | let name = (stringify!($key_name)).replace("_", "-"); | |
923072b8 | 1912 | if let Some(o) = obj.remove(&name) { |
29967ef6 | 1913 | base.$key_name = o |
923072b8 | 1914 | .as_str() |
5e7ed085 | 1915 | .map(|s| s.to_string().into()); |
29967ef6 XL |
1916 | } |
1917 | } ); | |
b7449926 XL |
1918 | ($key_name:ident, LldFlavor) => ( { |
1919 | let name = (stringify!($key_name)).replace("_", "-"); | |
923072b8 | 1920 | obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { |
b7449926 | 1921 | if let Some(flavor) = LldFlavor::from_str(&s) { |
29967ef6 | 1922 | base.$key_name = flavor; |
b7449926 XL |
1923 | } else { |
1924 | return Some(Err(format!( | |
1925 | "'{}' is not a valid value for lld-flavor. \ | |
1926 | Use 'darwin', 'gnu', 'link' or 'wasm.", | |
1927 | s))) | |
1928 | } | |
1929 | Some(Ok(())) | |
1930 | })).unwrap_or(Ok(())) | |
1931 | } ); | |
cc61c64b XL |
1932 | ($key_name:ident, LinkerFlavor) => ( { |
1933 | let name = (stringify!($key_name)).replace("_", "-"); | |
923072b8 | 1934 | obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { |
29967ef6 XL |
1935 | match LinkerFlavor::from_str(s) { |
1936 | Some(linker_flavor) => base.$key_name = linker_flavor, | |
1937 | _ => return Some(Err(format!("'{}' is not a valid value for linker-flavor. \ | |
1938 | Use {}", s, LinkerFlavor::one_of()))), | |
1939 | } | |
1940 | Some(Ok(())) | |
cc61c64b XL |
1941 | })).unwrap_or(Ok(())) |
1942 | } ); | |
5869c6ff XL |
1943 | ($key_name:ident, StackProbeType) => ( { |
1944 | let name = (stringify!($key_name)).replace("_", "-"); | |
923072b8 | 1945 | obj.remove(&name).and_then(|o| match StackProbeType::from_json(&o) { |
5869c6ff XL |
1946 | Ok(v) => { |
1947 | base.$key_name = v; | |
1948 | Some(Ok(())) | |
1949 | }, | |
1950 | Err(s) => Some(Err( | |
1951 | format!("`{:?}` is not a valid value for `{}`: {}", o, name, s) | |
1952 | )), | |
1953 | }).unwrap_or(Ok(())) | |
1954 | } ); | |
cdc7bbd5 XL |
1955 | ($key_name:ident, SanitizerSet) => ( { |
1956 | let name = (stringify!($key_name)).replace("_", "-"); | |
923072b8 | 1957 | if let Some(o) = obj.remove(&name) { |
136023e0 XL |
1958 | if let Some(a) = o.as_array() { |
1959 | for s in a { | |
923072b8 | 1960 | base.$key_name |= match s.as_str() { |
136023e0 | 1961 | Some("address") => SanitizerSet::ADDRESS, |
3c0e092e | 1962 | Some("cfi") => SanitizerSet::CFI, |
136023e0 XL |
1963 | Some("leak") => SanitizerSet::LEAK, |
1964 | Some("memory") => SanitizerSet::MEMORY, | |
5099ac24 | 1965 | Some("memtag") => SanitizerSet::MEMTAG, |
064997fb | 1966 | Some("shadow-call-stack") => SanitizerSet::SHADOWCALLSTACK, |
136023e0 XL |
1967 | Some("thread") => SanitizerSet::THREAD, |
1968 | Some("hwaddress") => SanitizerSet::HWADDRESS, | |
1969 | Some(s) => return Err(format!("unknown sanitizer {}", s)), | |
1970 | _ => return Err(format!("not a string: {:?}", s)), | |
1971 | }; | |
1972 | } | |
1973 | } else { | |
1974 | incorrect_type.push(name) | |
cdc7bbd5 | 1975 | } |
136023e0 XL |
1976 | } |
1977 | Ok::<(), String>(()) | |
cdc7bbd5 XL |
1978 | } ); |
1979 | ||
f9f354fc XL |
1980 | ($key_name:ident, crt_objects_fallback) => ( { |
1981 | let name = (stringify!($key_name)).replace("_", "-"); | |
923072b8 | 1982 | obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { |
f9f354fc | 1983 | match s.parse::<CrtObjectsFallback>() { |
29967ef6 | 1984 | Ok(fallback) => base.$key_name = Some(fallback), |
f9f354fc XL |
1985 | _ => return Some(Err(format!("'{}' is not a valid CRT objects fallback. \ |
1986 | Use 'musl', 'mingw' or 'wasm'", s))), | |
1987 | } | |
1988 | Some(Ok(())) | |
1989 | })).unwrap_or(Ok(())) | |
1990 | } ); | |
1991 | ($key_name:ident, link_objects) => ( { | |
1992 | let name = (stringify!($key_name)).replace("_", "-"); | |
923072b8 | 1993 | if let Some(val) = obj.remove(&name) { |
f9f354fc XL |
1994 | let obj = val.as_object().ok_or_else(|| format!("{}: expected a \ |
1995 | JSON object with fields per CRT object kind.", name))?; | |
1996 | let mut args = CrtObjects::new(); | |
1997 | for (k, v) in obj { | |
1998 | let kind = LinkOutputKind::from_str(&k).ok_or_else(|| { | |
1999 | format!("{}: '{}' is not a valid value for CRT object kind. \ | |
2000 | Use '(dynamic,static)-(nopic,pic)-exe' or \ | |
5869c6ff | 2001 | '(dynamic,static)-dylib' or 'wasi-reactor-exe'", name, k) |
f9f354fc XL |
2002 | })?; |
2003 | ||
2004 | let v = v.as_array().ok_or_else(|| | |
2005 | format!("{}.{}: expected a JSON array", name, k) | |
2006 | )?.iter().enumerate() | |
2007 | .map(|(i,s)| { | |
923072b8 | 2008 | let s = s.as_str().ok_or_else(|| |
f9f354fc | 2009 | format!("{}.{}[{}]: expected a JSON string", name, k, i))?; |
5e7ed085 | 2010 | Ok(s.to_string().into()) |
f9f354fc XL |
2011 | }) |
2012 | .collect::<Result<Vec<_>, String>>()?; | |
2013 | ||
2014 | args.insert(kind, v); | |
2015 | } | |
29967ef6 | 2016 | base.$key_name = args; |
f9f354fc XL |
2017 | } |
2018 | } ); | |
cc61c64b XL |
2019 | ($key_name:ident, link_args) => ( { |
2020 | let name = (stringify!($key_name)).replace("_", "-"); | |
923072b8 | 2021 | if let Some(val) = obj.remove(&name) { |
8faf50e0 XL |
2022 | let obj = val.as_object().ok_or_else(|| format!("{}: expected a \ |
2023 | JSON object with fields per linker-flavor.", name))?; | |
cc61c64b XL |
2024 | let mut args = LinkArgs::new(); |
2025 | for (k, v) in obj { | |
8faf50e0 | 2026 | let flavor = LinkerFlavor::from_str(&k).ok_or_else(|| { |
cc61c64b XL |
2027 | format!("{}: '{}' is not a valid value for linker-flavor. \ |
2028 | Use 'em', 'gcc', 'ld' or 'msvc'", name, k) | |
2029 | })?; | |
2030 | ||
8faf50e0 XL |
2031 | let v = v.as_array().ok_or_else(|| |
2032 | format!("{}.{}: expected a JSON array", name, k) | |
2033 | )?.iter().enumerate() | |
2034 | .map(|(i,s)| { | |
923072b8 | 2035 | let s = s.as_str().ok_or_else(|| |
8faf50e0 | 2036 | format!("{}.{}[{}]: expected a JSON string", name, k, i))?; |
5e7ed085 | 2037 | Ok(s.to_string().into()) |
8faf50e0 XL |
2038 | }) |
2039 | .collect::<Result<Vec<_>, String>>()?; | |
2040 | ||
2041 | args.insert(flavor, v); | |
cc61c64b | 2042 | } |
29967ef6 | 2043 | base.$key_name = args; |
cc61c64b XL |
2044 | } |
2045 | } ); | |
041b39d2 XL |
2046 | ($key_name:ident, env) => ( { |
2047 | let name = (stringify!($key_name)).replace("_", "-"); | |
923072b8 | 2048 | if let Some(o) = obj.remove(&name) { |
136023e0 XL |
2049 | if let Some(a) = o.as_array() { |
2050 | for o in a { | |
923072b8 | 2051 | if let Some(s) = o.as_str() { |
136023e0 XL |
2052 | let p = s.split('=').collect::<Vec<_>>(); |
2053 | if p.len() == 2 { | |
2054 | let k = p[0].to_string(); | |
2055 | let v = p[1].to_string(); | |
5e7ed085 | 2056 | base.$key_name.to_mut().push((k.into(), v.into())); |
136023e0 | 2057 | } |
041b39d2 XL |
2058 | } |
2059 | } | |
136023e0 XL |
2060 | } else { |
2061 | incorrect_type.push(name) | |
041b39d2 XL |
2062 | } |
2063 | } | |
2064 | } ); | |
cdc7bbd5 XL |
2065 | ($key_name:ident, Option<Abi>) => ( { |
2066 | let name = (stringify!($key_name)).replace("_", "-"); | |
923072b8 | 2067 | obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { |
cdc7bbd5 XL |
2068 | match lookup_abi(s) { |
2069 | Some(abi) => base.$key_name = Some(abi), | |
2070 | _ => return Some(Err(format!("'{}' is not a valid value for abi", s))), | |
2071 | } | |
2072 | Some(Ok(())) | |
2073 | })).unwrap_or(Ok(())) | |
2074 | } ); | |
17df50a5 | 2075 | ($key_name:ident, TargetFamilies) => ( { |
923072b8 FG |
2076 | if let Some(value) = obj.remove("target-family") { |
2077 | if let Some(v) = value.as_array() { | |
136023e0 | 2078 | base.$key_name = v.iter() |
923072b8 | 2079 | .map(|a| a.as_str().unwrap().to_string().into()) |
136023e0 | 2080 | .collect(); |
923072b8 | 2081 | } else if let Some(v) = value.as_str() { |
5e7ed085 | 2082 | base.$key_name = vec![v.to_string().into()].into(); |
136023e0 | 2083 | } |
17df50a5 XL |
2084 | } |
2085 | } ); | |
1a4d82fc JJ |
2086 | } |
2087 | ||
923072b8 FG |
2088 | if let Some(j) = obj.remove("target-endian") { |
2089 | if let Some(s) = j.as_str() { | |
136023e0 XL |
2090 | base.endian = s.parse()?; |
2091 | } else { | |
5e7ed085 | 2092 | incorrect_type.push("target-endian".into()) |
136023e0 | 2093 | } |
5869c6ff | 2094 | } |
136023e0 | 2095 | |
923072b8 FG |
2096 | if let Some(fp) = obj.remove("frame-pointer") { |
2097 | if let Some(s) = fp.as_str() { | |
136023e0 XL |
2098 | base.frame_pointer = s |
2099 | .parse() | |
2100 | .map_err(|()| format!("'{}' is not a valid value for frame-pointer", s))?; | |
2101 | } else { | |
5e7ed085 | 2102 | incorrect_type.push("frame-pointer".into()) |
136023e0 XL |
2103 | } |
2104 | } | |
2105 | ||
5bcae85e | 2106 | key!(is_builtin, bool); |
fc512014 | 2107 | key!(c_int_width = "target-c-int-width"); |
29967ef6 XL |
2108 | key!(os); |
2109 | key!(env); | |
136023e0 | 2110 | key!(abi); |
29967ef6 XL |
2111 | key!(vendor); |
2112 | key!(linker_flavor, LinkerFlavor)?; | |
0531ce1d | 2113 | key!(linker, optional); |
a1dfa0c6 | 2114 | key!(lld_flavor, LldFlavor)?; |
f9f354fc XL |
2115 | key!(pre_link_objects, link_objects); |
2116 | key!(post_link_objects, link_objects); | |
2117 | key!(pre_link_objects_fallback, link_objects); | |
2118 | key!(post_link_objects_fallback, link_objects); | |
2119 | key!(crt_objects_fallback, crt_objects_fallback)?; | |
cc61c64b | 2120 | key!(pre_link_args, link_args); |
cc61c64b | 2121 | key!(late_link_args, link_args); |
ba9703b0 XL |
2122 | key!(late_link_args_dynamic, link_args); |
2123 | key!(late_link_args_static, link_args); | |
cc61c64b | 2124 | key!(post_link_args, link_args); |
f9f354fc | 2125 | key!(link_script, optional); |
041b39d2 | 2126 | key!(link_env, env); |
e1599b0c | 2127 | key!(link_env_remove, list); |
32a655c1 | 2128 | key!(asm_args, list); |
5bcae85e SL |
2129 | key!(cpu); |
2130 | key!(features); | |
2131 | key!(dynamic_linking, bool); | |
abe05a73 | 2132 | key!(only_cdylib, bool); |
5bcae85e | 2133 | key!(executables, bool); |
f9f354fc XL |
2134 | key!(relocation_model, RelocModel)?; |
2135 | key!(code_model, CodeModel)?; | |
2136 | key!(tls_model, TlsModel)?; | |
5bcae85e | 2137 | key!(disable_redzone, bool); |
5bcae85e | 2138 | key!(function_sections, bool); |
1a4d82fc JJ |
2139 | key!(dll_prefix); |
2140 | key!(dll_suffix); | |
2141 | key!(exe_suffix); | |
2142 | key!(staticlib_prefix); | |
2143 | key!(staticlib_suffix); | |
17df50a5 | 2144 | key!(families, TargetFamilies); |
0531ce1d | 2145 | key!(abi_return_struct_as_int, bool); |
1a4d82fc | 2146 | key!(is_like_osx, bool); |
5bcae85e | 2147 | key!(is_like_solaris, bool); |
1a4d82fc | 2148 | key!(is_like_windows, bool); |
a7813a04 | 2149 | key!(is_like_msvc, bool); |
cdc7bbd5 | 2150 | key!(is_like_wasm, bool); |
064997fb | 2151 | key!(default_dwarf_version, u32); |
1a4d82fc | 2152 | key!(linker_is_gnu, bool); |
5bcae85e | 2153 | key!(allows_weak_linkage, bool); |
1a4d82fc | 2154 | key!(has_rpath, bool); |
b039eaaf | 2155 | key!(no_default_libraries, bool); |
5bcae85e | 2156 | key!(position_independent_executables, bool); |
f9f354fc | 2157 | key!(static_position_independent_executables, bool); |
0bf4aa26 | 2158 | key!(needs_plt, bool); |
a1dfa0c6 | 2159 | key!(relro_level, RelroLevel)?; |
92a42be0 | 2160 | key!(archive_format); |
e9174d1e | 2161 | key!(allow_asm, bool); |
e74abb32 | 2162 | key!(main_needs_argc_argv, bool); |
a2a8927a | 2163 | key!(has_thread_local, bool); |
5bcae85e | 2164 | key!(obj_is_bitcode, bool); |
f9f354fc XL |
2165 | key!(forces_embed_bitcode, bool); |
2166 | key!(bitcode_llvm_cmdline); | |
c30ab7b3 | 2167 | key!(max_atomic_width, Option<u64>); |
32a655c1 | 2168 | key!(min_atomic_width, Option<u64>); |
8faf50e0 | 2169 | key!(atomic_cas, bool); |
a1dfa0c6 | 2170 | key!(panic_strategy, PanicStrategy)?; |
3b2f2976 | 2171 | key!(crt_static_allows_dylibs, bool); |
476ff2be | 2172 | key!(crt_static_default, bool); |
3b2f2976 | 2173 | key!(crt_static_respected, bool); |
5869c6ff | 2174 | key!(stack_probes, StackProbeType)?; |
ea8adc8c | 2175 | key!(min_global_align, Option<u64>); |
abe05a73 XL |
2176 | key!(default_codegen_units, Option<u64>); |
2177 | key!(trap_unreachable, bool); | |
2178 | key!(requires_lto, bool); | |
2179 | key!(singlethread, bool); | |
2180 | key!(no_builtins, bool); | |
2c00a5a8 | 2181 | key!(default_hidden_visibility, bool); |
83c7162d XL |
2182 | key!(emit_debug_gdb_scripts, bool); |
2183 | key!(requires_uwtable, bool); | |
cdc7bbd5 | 2184 | key!(default_uwtable, bool); |
0bf4aa26 | 2185 | key!(simd_types_indirect, bool); |
dc9dc135 | 2186 | key!(limit_rdylib_exports, bool); |
a1dfa0c6 | 2187 | key!(override_export_symbols, opt_list); |
9fa01778 | 2188 | key!(merge_functions, MergeFunctions)?; |
fc512014 | 2189 | key!(mcount = "target-mcount"); |
60c5eb7d XL |
2190 | key!(llvm_abiname); |
2191 | key!(relax_elf_relocations, bool); | |
dfeec247 | 2192 | key!(llvm_args, list); |
f9f354fc | 2193 | key!(use_ctors_section, bool); |
f9652781 | 2194 | key!(eh_frame_header, bool); |
29967ef6 | 2195 | key!(has_thumb_interworking, bool); |
5869c6ff | 2196 | key!(split_debuginfo, SplitDebuginfo)?; |
cdc7bbd5 XL |
2197 | key!(supported_sanitizers, SanitizerSet)?; |
2198 | key!(default_adjusted_cabi, Option<Abi>)?; | |
94222f64 | 2199 | key!(c_enum_min_bits, u64); |
3c0e092e XL |
2200 | key!(generate_arange_section, bool); |
2201 | key!(supports_stack_protector, bool); | |
c30ab7b3 | 2202 | |
136023e0 XL |
2203 | if base.is_builtin { |
2204 | // This can cause unfortunate ICEs later down the line. | |
5e7ed085 | 2205 | return Err("may not set is_builtin for targets not built-in".into()); |
c30ab7b3 | 2206 | } |
923072b8 FG |
2207 | // Each field should have been read using `Json::remove` so any keys remaining are unused. |
2208 | let remaining_keys = obj.keys(); | |
136023e0 XL |
2209 | Ok(( |
2210 | base, | |
2211 | TargetWarnings { unused_fields: remaining_keys.cloned().collect(), incorrect_type }, | |
2212 | )) | |
1a4d82fc JJ |
2213 | } |
2214 | ||
5e7ed085 FG |
2215 | /// Load a built-in target |
2216 | pub fn expect_builtin(target_triple: &TargetTriple) -> Target { | |
2217 | match *target_triple { | |
2218 | TargetTriple::TargetTriple(ref target_triple) => { | |
2219 | load_builtin(target_triple).expect("built-in target") | |
2220 | } | |
923072b8 | 2221 | TargetTriple::TargetJson { .. } => { |
5e7ed085 FG |
2222 | panic!("built-in targets doens't support target-paths") |
2223 | } | |
2224 | } | |
2225 | } | |
2226 | ||
17df50a5 XL |
2227 | /// Search for a JSON file specifying the given target triple. |
2228 | /// | |
2229 | /// If none is found in `$RUST_TARGET_PATH`, look for a file called `target.json` inside the | |
2230 | /// sysroot under the target-triple's `rustlib` directory. Note that it could also just be a | |
2231 | /// bare filename already, so also check for that. If one of the hardcoded targets we know | |
2232 | /// about, just return it directly. | |
1a4d82fc | 2233 | /// |
17df50a5 XL |
2234 | /// The error string could come from any of the APIs called, including filesystem access and |
2235 | /// JSON decoding. | |
136023e0 XL |
2236 | pub fn search( |
2237 | target_triple: &TargetTriple, | |
3c0e092e | 2238 | sysroot: &Path, |
136023e0 | 2239 | ) -> Result<(Target, TargetWarnings), String> { |
85aaf69f | 2240 | use std::env; |
2c00a5a8 | 2241 | use std::fs; |
1a4d82fc | 2242 | |
136023e0 | 2243 | fn load_file(path: &Path) -> Result<(Target, TargetWarnings), String> { |
5099ac24 | 2244 | let contents = fs::read_to_string(path).map_err(|e| e.to_string())?; |
923072b8 | 2245 | let obj = serde_json::from_str(&contents).map_err(|e| e.to_string())?; |
5bcae85e | 2246 | Target::from_json(obj) |
1a4d82fc JJ |
2247 | } |
2248 | ||
b7449926 XL |
2249 | match *target_triple { |
2250 | TargetTriple::TargetTriple(ref target_triple) => { | |
29967ef6 XL |
2251 | // check if triple is in list of built-in targets |
2252 | if let Some(t) = load_builtin(target_triple) { | |
136023e0 | 2253 | return Ok((t, TargetWarnings::empty())); |
0531ce1d | 2254 | } |
1a4d82fc | 2255 | |
0531ce1d XL |
2256 | // search for a file named `target_triple`.json in RUST_TARGET_PATH |
2257 | let path = { | |
2258 | let mut target = target_triple.to_string(); | |
2259 | target.push_str(".json"); | |
2260 | PathBuf::from(target) | |
2261 | }; | |
1a4d82fc | 2262 | |
b7449926 | 2263 | let target_path = env::var_os("RUST_TARGET_PATH").unwrap_or_default(); |
1a4d82fc | 2264 | |
0531ce1d | 2265 | for dir in env::split_paths(&target_path) { |
dfeec247 | 2266 | let p = dir.join(&path); |
0531ce1d XL |
2267 | if p.is_file() { |
2268 | return load_file(&p); | |
2269 | } | |
2270 | } | |
17df50a5 XL |
2271 | |
2272 | // Additionally look in the sysroot under `lib/rustlib/<triple>/target.json` | |
2273 | // as a fallback. | |
2274 | let rustlib_path = crate::target_rustlib_path(&sysroot, &target_triple); | |
a2a8927a | 2275 | let p = PathBuf::from_iter([ |
17df50a5 XL |
2276 | Path::new(sysroot), |
2277 | Path::new(&rustlib_path), | |
2278 | Path::new("target.json"), | |
a2a8927a | 2279 | ]); |
17df50a5 XL |
2280 | if p.is_file() { |
2281 | return load_file(&p); | |
2282 | } | |
2283 | ||
0531ce1d XL |
2284 | Err(format!("Could not find specification for target {:?}", target_triple)) |
2285 | } | |
923072b8 FG |
2286 | TargetTriple::TargetJson { ref contents, .. } => { |
2287 | let obj = serde_json::from_str(contents).map_err(|e| e.to_string())?; | |
2288 | Target::from_json(obj) | |
1a4d82fc JJ |
2289 | } |
2290 | } | |
1a4d82fc JJ |
2291 | } |
2292 | } | |
e9174d1e | 2293 | |
5bcae85e SL |
2294 | impl ToJson for Target { |
2295 | fn to_json(&self) -> Json { | |
923072b8 | 2296 | let mut d = serde_json::Map::new(); |
5bcae85e SL |
2297 | let default: TargetOptions = Default::default(); |
2298 | ||
2299 | macro_rules! target_val { | |
dfeec247 | 2300 | ($attr:ident) => {{ |
5bcae85e | 2301 | let name = (stringify!($attr)).replace("_", "-"); |
0bf4aa26 | 2302 | d.insert(name, self.$attr.to_json()); |
dfeec247 | 2303 | }}; |
5bcae85e SL |
2304 | } |
2305 | ||
2306 | macro_rules! target_option_val { | |
dfeec247 | 2307 | ($attr:ident) => {{ |
5bcae85e | 2308 | let name = (stringify!($attr)).replace("_", "-"); |
29967ef6 XL |
2309 | if default.$attr != self.$attr { |
2310 | d.insert(name, self.$attr.to_json()); | |
5bcae85e | 2311 | } |
dfeec247 XL |
2312 | }}; |
2313 | ($attr:ident, $key_name:expr) => {{ | |
5bcae85e | 2314 | let name = $key_name; |
29967ef6 | 2315 | if default.$attr != self.$attr { |
5e7ed085 | 2316 | d.insert(name.into(), self.$attr.to_json()); |
5bcae85e | 2317 | } |
dfeec247 XL |
2318 | }}; |
2319 | (link_args - $attr:ident) => {{ | |
cc61c64b | 2320 | let name = (stringify!($attr)).replace("_", "-"); |
29967ef6 | 2321 | if default.$attr != self.$attr { |
dfeec247 | 2322 | let obj = self |
dfeec247 | 2323 | .$attr |
cc61c64b | 2324 | .iter() |
5e7ed085 | 2325 | .map(|(k, v)| (k.desc().to_string(), v.clone())) |
cc61c64b | 2326 | .collect::<BTreeMap<_, _>>(); |
0bf4aa26 | 2327 | d.insert(name, obj.to_json()); |
cc61c64b | 2328 | } |
dfeec247 XL |
2329 | }}; |
2330 | (env - $attr:ident) => {{ | |
041b39d2 | 2331 | let name = (stringify!($attr)).replace("_", "-"); |
29967ef6 | 2332 | if default.$attr != self.$attr { |
dfeec247 | 2333 | let obj = self |
dfeec247 | 2334 | .$attr |
041b39d2 | 2335 | .iter() |
5e7ed085 | 2336 | .map(|&(ref k, ref v)| format!("{k}={v}")) |
041b39d2 | 2337 | .collect::<Vec<_>>(); |
0bf4aa26 | 2338 | d.insert(name, obj.to_json()); |
041b39d2 | 2339 | } |
dfeec247 | 2340 | }}; |
5bcae85e SL |
2341 | } |
2342 | ||
2343 | target_val!(llvm_target); | |
29967ef6 | 2344 | d.insert("target-pointer-width".to_string(), self.pointer_width.to_string().to_json()); |
5bcae85e | 2345 | target_val!(arch); |
5bcae85e SL |
2346 | target_val!(data_layout); |
2347 | ||
2348 | target_option_val!(is_builtin); | |
fc512014 XL |
2349 | target_option_val!(endian, "target-endian"); |
2350 | target_option_val!(c_int_width, "target-c-int-width"); | |
29967ef6 XL |
2351 | target_option_val!(os); |
2352 | target_option_val!(env); | |
136023e0 | 2353 | target_option_val!(abi); |
29967ef6 XL |
2354 | target_option_val!(vendor); |
2355 | target_option_val!(linker_flavor); | |
5bcae85e | 2356 | target_option_val!(linker); |
b7449926 | 2357 | target_option_val!(lld_flavor); |
f9f354fc XL |
2358 | target_option_val!(pre_link_objects); |
2359 | target_option_val!(post_link_objects); | |
2360 | target_option_val!(pre_link_objects_fallback); | |
2361 | target_option_val!(post_link_objects_fallback); | |
2362 | target_option_val!(crt_objects_fallback); | |
cc61c64b | 2363 | target_option_val!(link_args - pre_link_args); |
cc61c64b | 2364 | target_option_val!(link_args - late_link_args); |
ba9703b0 XL |
2365 | target_option_val!(link_args - late_link_args_dynamic); |
2366 | target_option_val!(link_args - late_link_args_static); | |
cc61c64b | 2367 | target_option_val!(link_args - post_link_args); |
f9f354fc | 2368 | target_option_val!(link_script); |
041b39d2 | 2369 | target_option_val!(env - link_env); |
e1599b0c | 2370 | target_option_val!(link_env_remove); |
32a655c1 | 2371 | target_option_val!(asm_args); |
5bcae85e SL |
2372 | target_option_val!(cpu); |
2373 | target_option_val!(features); | |
2374 | target_option_val!(dynamic_linking); | |
abe05a73 | 2375 | target_option_val!(only_cdylib); |
5bcae85e SL |
2376 | target_option_val!(executables); |
2377 | target_option_val!(relocation_model); | |
2378 | target_option_val!(code_model); | |
abe05a73 | 2379 | target_option_val!(tls_model); |
5bcae85e | 2380 | target_option_val!(disable_redzone); |
136023e0 | 2381 | target_option_val!(frame_pointer); |
5bcae85e SL |
2382 | target_option_val!(function_sections); |
2383 | target_option_val!(dll_prefix); | |
2384 | target_option_val!(dll_suffix); | |
2385 | target_option_val!(exe_suffix); | |
2386 | target_option_val!(staticlib_prefix); | |
2387 | target_option_val!(staticlib_suffix); | |
17df50a5 | 2388 | target_option_val!(families, "target-family"); |
0531ce1d | 2389 | target_option_val!(abi_return_struct_as_int); |
5bcae85e SL |
2390 | target_option_val!(is_like_osx); |
2391 | target_option_val!(is_like_solaris); | |
2392 | target_option_val!(is_like_windows); | |
2393 | target_option_val!(is_like_msvc); | |
cdc7bbd5 | 2394 | target_option_val!(is_like_wasm); |
064997fb | 2395 | target_option_val!(default_dwarf_version); |
5bcae85e SL |
2396 | target_option_val!(linker_is_gnu); |
2397 | target_option_val!(allows_weak_linkage); | |
2398 | target_option_val!(has_rpath); | |
5bcae85e SL |
2399 | target_option_val!(no_default_libraries); |
2400 | target_option_val!(position_independent_executables); | |
f9f354fc | 2401 | target_option_val!(static_position_independent_executables); |
0bf4aa26 | 2402 | target_option_val!(needs_plt); |
3b2f2976 | 2403 | target_option_val!(relro_level); |
5bcae85e SL |
2404 | target_option_val!(archive_format); |
2405 | target_option_val!(allow_asm); | |
e74abb32 | 2406 | target_option_val!(main_needs_argc_argv); |
a2a8927a | 2407 | target_option_val!(has_thread_local); |
5bcae85e | 2408 | target_option_val!(obj_is_bitcode); |
f9f354fc XL |
2409 | target_option_val!(forces_embed_bitcode); |
2410 | target_option_val!(bitcode_llvm_cmdline); | |
32a655c1 | 2411 | target_option_val!(min_atomic_width); |
5bcae85e | 2412 | target_option_val!(max_atomic_width); |
8faf50e0 | 2413 | target_option_val!(atomic_cas); |
c30ab7b3 | 2414 | target_option_val!(panic_strategy); |
3b2f2976 | 2415 | target_option_val!(crt_static_allows_dylibs); |
476ff2be | 2416 | target_option_val!(crt_static_default); |
3b2f2976 | 2417 | target_option_val!(crt_static_respected); |
041b39d2 | 2418 | target_option_val!(stack_probes); |
ea8adc8c | 2419 | target_option_val!(min_global_align); |
abe05a73 XL |
2420 | target_option_val!(default_codegen_units); |
2421 | target_option_val!(trap_unreachable); | |
2422 | target_option_val!(requires_lto); | |
2423 | target_option_val!(singlethread); | |
2424 | target_option_val!(no_builtins); | |
2c00a5a8 | 2425 | target_option_val!(default_hidden_visibility); |
83c7162d XL |
2426 | target_option_val!(emit_debug_gdb_scripts); |
2427 | target_option_val!(requires_uwtable); | |
cdc7bbd5 | 2428 | target_option_val!(default_uwtable); |
0bf4aa26 | 2429 | target_option_val!(simd_types_indirect); |
dc9dc135 | 2430 | target_option_val!(limit_rdylib_exports); |
a1dfa0c6 | 2431 | target_option_val!(override_export_symbols); |
9fa01778 | 2432 | target_option_val!(merge_functions); |
fc512014 | 2433 | target_option_val!(mcount, "target-mcount"); |
60c5eb7d XL |
2434 | target_option_val!(llvm_abiname); |
2435 | target_option_val!(relax_elf_relocations); | |
dfeec247 | 2436 | target_option_val!(llvm_args); |
f9f354fc | 2437 | target_option_val!(use_ctors_section); |
f9652781 | 2438 | target_option_val!(eh_frame_header); |
29967ef6 | 2439 | target_option_val!(has_thumb_interworking); |
5869c6ff | 2440 | target_option_val!(split_debuginfo); |
cdc7bbd5 | 2441 | target_option_val!(supported_sanitizers); |
94222f64 | 2442 | target_option_val!(c_enum_min_bits); |
3c0e092e XL |
2443 | target_option_val!(generate_arange_section); |
2444 | target_option_val!(supports_stack_protector); | |
cdc7bbd5 XL |
2445 | |
2446 | if let Some(abi) = self.default_adjusted_cabi { | |
5e7ed085 | 2447 | d.insert("default-adjusted-cabi".into(), Abi::name(abi).to_json()); |
cdc7bbd5 | 2448 | } |
c30ab7b3 | 2449 | |
5bcae85e SL |
2450 | Json::Object(d) |
2451 | } | |
2452 | } | |
2453 | ||
0531ce1d | 2454 | /// Either a target triple string or a path to a JSON file. |
923072b8 | 2455 | #[derive(Clone, Debug)] |
0531ce1d XL |
2456 | pub enum TargetTriple { |
2457 | TargetTriple(String), | |
923072b8 FG |
2458 | TargetJson { |
2459 | /// Warning: This field may only be used by rustdoc. Using it anywhere else will lead to | |
2460 | /// inconsistencies as it is discarded during serialization. | |
2461 | path_for_rustdoc: PathBuf, | |
2462 | triple: String, | |
2463 | contents: String, | |
2464 | }, | |
2465 | } | |
2466 | ||
2467 | // Use a manual implementation to ignore the path field | |
2468 | impl PartialEq for TargetTriple { | |
2469 | fn eq(&self, other: &Self) -> bool { | |
2470 | match (self, other) { | |
2471 | (Self::TargetTriple(l0), Self::TargetTriple(r0)) => l0 == r0, | |
2472 | ( | |
2473 | Self::TargetJson { path_for_rustdoc: _, triple: l_triple, contents: l_contents }, | |
2474 | Self::TargetJson { path_for_rustdoc: _, triple: r_triple, contents: r_contents }, | |
2475 | ) => l_triple == r_triple && l_contents == r_contents, | |
2476 | _ => false, | |
2477 | } | |
2478 | } | |
2479 | } | |
2480 | ||
2481 | // Use a manual implementation to ignore the path field | |
2482 | impl Hash for TargetTriple { | |
2483 | fn hash<H: Hasher>(&self, state: &mut H) -> () { | |
2484 | match self { | |
2485 | TargetTriple::TargetTriple(triple) => { | |
2486 | 0u8.hash(state); | |
2487 | triple.hash(state) | |
2488 | } | |
2489 | TargetTriple::TargetJson { path_for_rustdoc: _, triple, contents } => { | |
2490 | 1u8.hash(state); | |
2491 | triple.hash(state); | |
2492 | contents.hash(state) | |
2493 | } | |
2494 | } | |
2495 | } | |
2496 | } | |
2497 | ||
2498 | // Use a manual implementation to prevent encoding the target json file path in the crate metadata | |
2499 | impl<S: Encoder> Encodable<S> for TargetTriple { | |
2500 | fn encode(&self, s: &mut S) { | |
2501 | match self { | |
2502 | TargetTriple::TargetTriple(triple) => s.emit_enum_variant(0, |s| s.emit_str(triple)), | |
2503 | TargetTriple::TargetJson { path_for_rustdoc: _, triple, contents } => s | |
2504 | .emit_enum_variant(1, |s| { | |
2505 | s.emit_str(triple); | |
2506 | s.emit_str(contents) | |
2507 | }), | |
2508 | } | |
2509 | } | |
2510 | } | |
2511 | ||
2512 | impl<D: Decoder> Decodable<D> for TargetTriple { | |
2513 | fn decode(d: &mut D) -> Self { | |
2514 | match d.read_usize() { | |
2515 | 0 => TargetTriple::TargetTriple(d.read_str().to_owned()), | |
2516 | 1 => TargetTriple::TargetJson { | |
2517 | path_for_rustdoc: PathBuf::new(), | |
2518 | triple: d.read_str().to_owned(), | |
2519 | contents: d.read_str().to_owned(), | |
2520 | }, | |
2521 | _ => { | |
2522 | panic!("invalid enum variant tag while decoding `TargetTriple`, expected 0..2"); | |
2523 | } | |
2524 | } | |
2525 | } | |
0531ce1d XL |
2526 | } |
2527 | ||
2528 | impl TargetTriple { | |
2529 | /// Creates a target triple from the passed target triple string. | |
2530 | pub fn from_triple(triple: &str) -> Self { | |
5e7ed085 | 2531 | TargetTriple::TargetTriple(triple.into()) |
0531ce1d XL |
2532 | } |
2533 | ||
2534 | /// Creates a target triple from the passed target path. | |
2535 | pub fn from_path(path: &Path) -> Result<Self, io::Error> { | |
2536 | let canonicalized_path = path.canonicalize()?; | |
923072b8 FG |
2537 | let contents = std::fs::read_to_string(&canonicalized_path).map_err(|err| { |
2538 | io::Error::new( | |
2539 | io::ErrorKind::InvalidInput, | |
2540 | format!("target path {:?} is not a valid file: {}", canonicalized_path, err), | |
2541 | ) | |
2542 | })?; | |
2543 | let triple = canonicalized_path | |
2544 | .file_stem() | |
2545 | .expect("target path must not be empty") | |
2546 | .to_str() | |
2547 | .expect("target path must be valid unicode") | |
2548 | .to_owned(); | |
2549 | Ok(TargetTriple::TargetJson { path_for_rustdoc: canonicalized_path, triple, contents }) | |
0531ce1d XL |
2550 | } |
2551 | ||
2552 | /// Returns a string triple for this target. | |
2553 | /// | |
2554 | /// If this target is a path, the file name (without extension) is returned. | |
2555 | pub fn triple(&self) -> &str { | |
b7449926 | 2556 | match *self { |
923072b8 FG |
2557 | TargetTriple::TargetTriple(ref triple) |
2558 | | TargetTriple::TargetJson { ref triple, .. } => triple, | |
0531ce1d XL |
2559 | } |
2560 | } | |
2561 | ||
2562 | /// Returns an extended string triple for this target. | |
2563 | /// | |
2564 | /// If this target is a path, a hash of the path is appended to the triple returned | |
2565 | /// by `triple()`. | |
2566 | pub fn debug_triple(&self) -> String { | |
0531ce1d | 2567 | use std::collections::hash_map::DefaultHasher; |
923072b8 FG |
2568 | |
2569 | match self { | |
2570 | TargetTriple::TargetTriple(triple) => triple.to_owned(), | |
2571 | TargetTriple::TargetJson { path_for_rustdoc: _, triple, contents: content } => { | |
2572 | let mut hasher = DefaultHasher::new(); | |
2573 | content.hash(&mut hasher); | |
2574 | let hash = hasher.finish(); | |
2575 | format!("{}-{}", triple, hash) | |
2576 | } | |
0531ce1d XL |
2577 | } |
2578 | } | |
2579 | } | |
2580 | ||
2581 | impl fmt::Display for TargetTriple { | |
9fa01778 | 2582 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
0531ce1d XL |
2583 | write!(f, "{}", self.debug_triple()) |
2584 | } | |
2585 | } |