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