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