rustc_target/spec/
json.rs

1use std::borrow::Cow;
2use std::collections::BTreeMap;
3use std::str::FromStr;
4
5use rustc_abi::{Align, AlignFromBytesError, ExternAbi};
6use serde_json::Value;
7
8use super::{Target, TargetKind, TargetOptions, TargetWarnings};
9use crate::json::{Json, ToJson};
10use crate::spec::AbiMap;
11
12impl Target {
13    /// Loads a target descriptor from a JSON object.
14    pub fn from_json(obj: Json) -> Result<(Target, TargetWarnings), String> {
15        // While ugly, this code must remain this way to retain
16        // compatibility with existing JSON fields and the internal
17        // expected naming of the Target and TargetOptions structs.
18        // To ensure compatibility is retained, the built-in targets
19        // are round-tripped through this code to catch cases where
20        // the JSON parser is not updated to match the structs.
21
22        let mut obj = match obj {
23            Value::Object(obj) => obj,
24            _ => return Err("Expected JSON object for target")?,
25        };
26
27        let mut get_req_field = |name: &str| {
28            obj.remove(name)
29                .and_then(|j| j.as_str().map(str::to_string))
30                .ok_or_else(|| format!("Field {name} in target specification is required"))
31        };
32
33        let mut base = Target {
34            llvm_target: get_req_field("llvm-target")?.into(),
35            metadata: Default::default(),
36            pointer_width: get_req_field("target-pointer-width")?
37                .parse::<u32>()
38                .map_err(|_| "target-pointer-width must be an integer".to_string())?,
39            data_layout: get_req_field("data-layout")?.into(),
40            arch: get_req_field("arch")?.into(),
41            options: Default::default(),
42        };
43
44        // FIXME: This doesn't properly validate anything and just ignores the data if it's invalid.
45        // That's okay for now, the only use of this is when generating docs, which we don't do for
46        // custom targets.
47        if let Some(Json::Object(mut metadata)) = obj.remove("metadata") {
48            base.metadata.description = metadata
49                .remove("description")
50                .and_then(|desc| desc.as_str().map(|desc| desc.to_owned().into()));
51            base.metadata.tier = metadata
52                .remove("tier")
53                .and_then(|tier| tier.as_u64())
54                .filter(|tier| (1..=3).contains(tier));
55            base.metadata.host_tools =
56                metadata.remove("host_tools").and_then(|host| host.as_bool());
57            base.metadata.std = metadata.remove("std").and_then(|host| host.as_bool());
58        }
59
60        let alignment_error = |field_name: &str, error: AlignFromBytesError| -> String {
61            let msg = match error {
62                AlignFromBytesError::NotPowerOfTwo(_) => "not a power of 2 number of bytes",
63                AlignFromBytesError::TooLarge(_) => "too large",
64            };
65            format!("`{}` bits is not a valid value for {field_name}: {msg}", error.align() * 8)
66        };
67
68        let mut incorrect_type = vec![];
69
70        macro_rules! key {
71            ($key_name:ident) => ( {
72                let name = (stringify!($key_name)).replace("_", "-");
73                if let Some(s) = obj.remove(&name).and_then(|s| s.as_str().map(str::to_string).map(Cow::from)) {
74                    base.$key_name = s;
75                }
76            } );
77            ($key_name:ident = $json_name:expr) => ( {
78                let name = $json_name;
79                if let Some(s) = obj.remove(name).and_then(|s| s.as_str().map(str::to_string).map(Cow::from)) {
80                    base.$key_name = s;
81                }
82            } );
83            ($key_name:ident = $json_name:expr, u64 as $int_ty:ty) => ( {
84                let name = $json_name;
85                if let Some(s) = obj.remove(name).and_then(|b| b.as_u64()) {
86                    base.$key_name = s as $int_ty;
87                }
88            } );
89            ($key_name:ident, bool) => ( {
90                let name = (stringify!($key_name)).replace("_", "-");
91                if let Some(s) = obj.remove(&name).and_then(|b| b.as_bool()) {
92                    base.$key_name = s;
93                }
94            } );
95            ($key_name:ident = $json_name:expr, bool) => ( {
96                let name = $json_name;
97                if let Some(s) = obj.remove(name).and_then(|b| b.as_bool()) {
98                    base.$key_name = s;
99                }
100            } );
101            ($key_name:ident, u32) => ( {
102                let name = (stringify!($key_name)).replace("_", "-");
103                if let Some(s) = obj.remove(&name).and_then(|b| b.as_u64()) {
104                    if s < 1 || s > 5 {
105                        return Err("Not a valid DWARF version number".into());
106                    }
107                    base.$key_name = s as u32;
108                }
109            } );
110            ($key_name:ident, Option<bool>) => ( {
111                let name = (stringify!($key_name)).replace("_", "-");
112                if let Some(s) = obj.remove(&name).and_then(|b| b.as_bool()) {
113                    base.$key_name = Some(s);
114                }
115            } );
116            ($key_name:ident, Option<u64>) => ( {
117                let name = (stringify!($key_name)).replace("_", "-");
118                if let Some(s) = obj.remove(&name).and_then(|b| b.as_u64()) {
119                    base.$key_name = Some(s);
120                }
121            } );
122            ($key_name:ident, Option<StaticCow<str>>) => ( {
123                let name = (stringify!($key_name)).replace("_", "-");
124                if let Some(s) = obj.remove(&name).and_then(|b| Some(b.as_str()?.to_string())) {
125                    base.$key_name = Some(s.into());
126                }
127            } );
128            ($key_name:ident, Option<Align>) => ( {
129                let name = (stringify!($key_name)).replace("_", "-");
130                if let Some(b) = obj.remove(&name).and_then(|b| b.as_u64()) {
131                    match Align::from_bits(b) {
132                        Ok(align) => base.$key_name = Some(align),
133                        Err(e) => return Err(alignment_error(&name, e)),
134                    }
135                }
136            } );
137            ($key_name:ident, BinaryFormat) => ( {
138                let name = (stringify!($key_name)).replace("_", "-");
139                obj.remove(&name).and_then(|f| f.as_str().and_then(|s| {
140                    match s.parse::<super::BinaryFormat>() {
141                        Ok(binary_format) => base.$key_name = binary_format,
142                        _ => return Some(Err(format!(
143                            "'{s}' is not a valid value for binary_format. \
144                            Use 'coff', 'elf', 'mach-o', 'wasm' or 'xcoff' "
145                        ))),
146                    }
147                    Some(Ok(()))
148                })).unwrap_or(Ok(()))
149            } );
150            ($key_name:ident, MergeFunctions) => ( {
151                let name = (stringify!($key_name)).replace("_", "-");
152                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
153                    match s.parse::<super::MergeFunctions>() {
154                        Ok(mergefunc) => base.$key_name = mergefunc,
155                        _ => return Some(Err(format!("'{}' is not a valid value for \
156                                                      merge-functions. Use 'disabled', \
157                                                      'trampolines', or 'aliases'.",
158                                                      s))),
159                    }
160                    Some(Ok(()))
161                })).unwrap_or(Ok(()))
162            } );
163            ($key_name:ident, FloatAbi) => ( {
164                let name = (stringify!($key_name)).replace("_", "-");
165                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
166                    match s.parse::<super::FloatAbi>() {
167                        Ok(float_abi) => base.$key_name = Some(float_abi),
168                        _ => return Some(Err(format!("'{}' is not a valid value for \
169                                                      llvm-floatabi. Use 'soft' or 'hard'.",
170                                                      s))),
171                    }
172                    Some(Ok(()))
173                })).unwrap_or(Ok(()))
174            } );
175            ($key_name:ident, RustcAbi) => ( {
176                let name = (stringify!($key_name)).replace("_", "-");
177                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
178                    match s.parse::<super::RustcAbi>() {
179                        Ok(rustc_abi) => base.$key_name = Some(rustc_abi),
180                        _ => return Some(Err(format!(
181                            "'{s}' is not a valid value for rustc-abi. \
182                            Use 'x86-softfloat' or leave the field unset."
183                        ))),
184                    }
185                    Some(Ok(()))
186                })).unwrap_or(Ok(()))
187            } );
188            ($key_name:ident, RelocModel) => ( {
189                let name = (stringify!($key_name)).replace("_", "-");
190                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
191                    match s.parse::<super::RelocModel>() {
192                        Ok(relocation_model) => base.$key_name = relocation_model,
193                        _ => return Some(Err(format!("'{}' is not a valid relocation model. \
194                                                      Run `rustc --print relocation-models` to \
195                                                      see the list of supported values.", s))),
196                    }
197                    Some(Ok(()))
198                })).unwrap_or(Ok(()))
199            } );
200            ($key_name:ident, CodeModel) => ( {
201                let name = (stringify!($key_name)).replace("_", "-");
202                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
203                    match s.parse::<super::CodeModel>() {
204                        Ok(code_model) => base.$key_name = Some(code_model),
205                        _ => return Some(Err(format!("'{}' is not a valid code model. \
206                                                      Run `rustc --print code-models` to \
207                                                      see the list of supported values.", s))),
208                    }
209                    Some(Ok(()))
210                })).unwrap_or(Ok(()))
211            } );
212            ($key_name:ident, TlsModel) => ( {
213                let name = (stringify!($key_name)).replace("_", "-");
214                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
215                    match s.parse::<super::TlsModel>() {
216                        Ok(tls_model) => base.$key_name = tls_model,
217                        _ => return Some(Err(format!("'{}' is not a valid TLS model. \
218                                                      Run `rustc --print tls-models` to \
219                                                      see the list of supported values.", s))),
220                    }
221                    Some(Ok(()))
222                })).unwrap_or(Ok(()))
223            } );
224            ($key_name:ident, SmallDataThresholdSupport) => ( {
225                obj.remove("small-data-threshold-support").and_then(|o| o.as_str().and_then(|s| {
226                    match s.parse::<super::SmallDataThresholdSupport>() {
227                        Ok(support) => base.small_data_threshold_support = support,
228                        _ => return Some(Err(format!("'{s}' is not a valid value for small-data-threshold-support."))),
229                    }
230                    Some(Ok(()))
231                })).unwrap_or(Ok(()))
232            } );
233            ($key_name:ident, PanicStrategy) => ( {
234                let name = (stringify!($key_name)).replace("_", "-");
235                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
236                    match s {
237                        "unwind" => base.$key_name = super::PanicStrategy::Unwind,
238                        "abort" => base.$key_name = super::PanicStrategy::Abort,
239                        _ => return Some(Err(format!("'{}' is not a valid value for \
240                                                      panic-strategy. Use 'unwind' or 'abort'.",
241                                                     s))),
242                }
243                Some(Ok(()))
244            })).unwrap_or(Ok(()))
245            } );
246            ($key_name:ident, RelroLevel) => ( {
247                let name = (stringify!($key_name)).replace("_", "-");
248                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
249                    match s.parse::<super::RelroLevel>() {
250                        Ok(level) => base.$key_name = level,
251                        _ => return Some(Err(format!("'{}' is not a valid value for \
252                                                      relro-level. Use 'full', 'partial, or 'off'.",
253                                                      s))),
254                    }
255                    Some(Ok(()))
256                })).unwrap_or(Ok(()))
257            } );
258            ($key_name:ident, Option<SymbolVisibility>) => ( {
259                let name = (stringify!($key_name)).replace("_", "-");
260                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
261                    match s.parse::<super::SymbolVisibility>() {
262                        Ok(level) => base.$key_name = Some(level),
263                        _ => return Some(Err(format!("'{}' is not a valid value for \
264                                                      symbol-visibility. Use 'hidden', 'protected, or 'interposable'.",
265                                                      s))),
266                    }
267                    Some(Ok(()))
268                })).unwrap_or(Ok(()))
269            } );
270            ($key_name:ident, DebuginfoKind) => ( {
271                let name = (stringify!($key_name)).replace("_", "-");
272                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
273                    match s.parse::<super::DebuginfoKind>() {
274                        Ok(level) => base.$key_name = level,
275                        _ => return Some(Err(
276                            format!("'{s}' is not a valid value for debuginfo-kind. Use 'dwarf', \
277                                  'dwarf-dsym' or 'pdb'.")
278                        )),
279                    }
280                    Some(Ok(()))
281                })).unwrap_or(Ok(()))
282            } );
283            ($key_name:ident, SplitDebuginfo) => ( {
284                let name = (stringify!($key_name)).replace("_", "-");
285                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
286                    match s.parse::<super::SplitDebuginfo>() {
287                        Ok(level) => base.$key_name = level,
288                        _ => return Some(Err(format!("'{}' is not a valid value for \
289                                                      split-debuginfo. Use 'off' or 'dsymutil'.",
290                                                      s))),
291                    }
292                    Some(Ok(()))
293                })).unwrap_or(Ok(()))
294            } );
295            ($key_name:ident, list) => ( {
296                let name = (stringify!($key_name)).replace("_", "-");
297                if let Some(j) = obj.remove(&name) {
298                    if let Some(v) = j.as_array() {
299                        base.$key_name = v.iter()
300                            .map(|a| a.as_str().unwrap().to_string().into())
301                            .collect();
302                    } else {
303                        incorrect_type.push(name)
304                    }
305                }
306            } );
307            ($key_name:ident, opt_list) => ( {
308                let name = (stringify!($key_name)).replace("_", "-");
309                if let Some(j) = obj.remove(&name) {
310                    if let Some(v) = j.as_array() {
311                        base.$key_name = Some(v.iter()
312                            .map(|a| a.as_str().unwrap().to_string().into())
313                            .collect());
314                    } else {
315                        incorrect_type.push(name)
316                    }
317                }
318            } );
319            ($key_name:ident, fallible_list) => ( {
320                let name = (stringify!($key_name)).replace("_", "-");
321                obj.remove(&name).and_then(|j| {
322                    if let Some(v) = j.as_array() {
323                        match v.iter().map(|a| FromStr::from_str(a.as_str().unwrap())).collect() {
324                            Ok(l) => { base.$key_name = l },
325                            // FIXME: `fallible_list` can't re-use the `key!` macro for list
326                            // elements and the error messages from that macro, so it has a bad
327                            // generic message instead
328                            Err(_) => return Some(Err(
329                                format!("`{:?}` is not a valid value for `{}`", j, name)
330                            )),
331                        }
332                    } else {
333                        incorrect_type.push(name)
334                    }
335                    Some(Ok(()))
336                }).unwrap_or(Ok(()))
337            } );
338            ($key_name:ident, optional) => ( {
339                let name = (stringify!($key_name)).replace("_", "-");
340                if let Some(o) = obj.remove(&name) {
341                    base.$key_name = o
342                        .as_str()
343                        .map(|s| s.to_string().into());
344                }
345            } );
346            ($key_name:ident = $json_name:expr, LldFlavor) => ( {
347                let name = $json_name;
348                obj.remove(name).and_then(|o| o.as_str().and_then(|s| {
349                    if let Some(flavor) = super::LldFlavor::from_str(&s) {
350                        base.$key_name = flavor;
351                    } else {
352                        return Some(Err(format!(
353                            "'{}' is not a valid value for lld-flavor. \
354                             Use 'darwin', 'gnu', 'link' or 'wasm'.",
355                            s)))
356                    }
357                    Some(Ok(()))
358                })).unwrap_or(Ok(()))
359            } );
360            ($key_name:ident = $json_name:expr, LinkerFlavorCli) => ( {
361                let name = $json_name;
362                obj.remove(name).and_then(|o| o.as_str().and_then(|s| {
363                    match super::LinkerFlavorCli::from_str(s) {
364                        Some(linker_flavor) => base.$key_name = linker_flavor,
365                        _ => return Some(Err(format!("'{}' is not a valid value for linker-flavor. \
366                                                      Use {}", s, super::LinkerFlavorCli::one_of()))),
367                    }
368                    Some(Ok(()))
369                })).unwrap_or(Ok(()))
370            } );
371            ($key_name:ident, StackProbeType) => ( {
372                let name = (stringify!($key_name)).replace("_", "-");
373                obj.remove(&name).and_then(|o| match super::StackProbeType::from_json(&o) {
374                    Ok(v) => {
375                        base.$key_name = v;
376                        Some(Ok(()))
377                    },
378                    Err(s) => Some(Err(
379                        format!("`{:?}` is not a valid value for `{}`: {}", o, name, s)
380                    )),
381                }).unwrap_or(Ok(()))
382            } );
383            ($key_name:ident, SanitizerSet) => ( {
384                let name = (stringify!($key_name)).replace("_", "-");
385                if let Some(o) = obj.remove(&name) {
386                    if let Some(a) = o.as_array() {
387                        for s in a {
388                            use super::SanitizerSet;
389                            base.$key_name |= match s.as_str() {
390                                Some("address") => SanitizerSet::ADDRESS,
391                                Some("cfi") => SanitizerSet::CFI,
392                                Some("dataflow") => SanitizerSet::DATAFLOW,
393                                Some("kcfi") => SanitizerSet::KCFI,
394                                Some("kernel-address") => SanitizerSet::KERNELADDRESS,
395                                Some("leak") => SanitizerSet::LEAK,
396                                Some("memory") => SanitizerSet::MEMORY,
397                                Some("memtag") => SanitizerSet::MEMTAG,
398                                Some("safestack") => SanitizerSet::SAFESTACK,
399                                Some("shadow-call-stack") => SanitizerSet::SHADOWCALLSTACK,
400                                Some("thread") => SanitizerSet::THREAD,
401                                Some("hwaddress") => SanitizerSet::HWADDRESS,
402                                Some(s) => return Err(format!("unknown sanitizer {}", s)),
403                                _ => return Err(format!("not a string: {:?}", s)),
404                            };
405                        }
406                    } else {
407                        incorrect_type.push(name)
408                    }
409                }
410                Ok::<(), String>(())
411            } );
412            ($key_name:ident, link_self_contained_components) => ( {
413                // Skeleton of what needs to be parsed:
414                //
415                // ```
416                // $name: {
417                //     "components": [
418                //         <array of strings>
419                //     ]
420                // }
421                // ```
422                let name = (stringify!($key_name)).replace("_", "-");
423                if let Some(o) = obj.remove(&name) {
424                    if let Some(o) = o.as_object() {
425                        let component_array = o.get("components")
426                            .ok_or_else(|| format!("{name}: expected a \
427                                JSON object with a `components` field."))?;
428                        let component_array = component_array.as_array()
429                            .ok_or_else(|| format!("{name}.components: expected a JSON array"))?;
430                        let mut components = super::LinkSelfContainedComponents::empty();
431                        for s in component_array {
432                            components |= match s.as_str() {
433                                Some(s) => {
434                                    super::LinkSelfContainedComponents::from_str(s)
435                                        .ok_or_else(|| format!("unknown \
436                                        `-Clink-self-contained` component: {s}"))?
437                                },
438                                _ => return Err(format!("not a string: {:?}", s)),
439                            };
440                        }
441                        base.$key_name = super::LinkSelfContainedDefault::WithComponents(components);
442                    } else {
443                        incorrect_type.push(name)
444                    }
445                }
446                Ok::<(), String>(())
447            } );
448            ($key_name:ident = $json_name:expr, link_self_contained_backwards_compatible) => ( {
449                let name = $json_name;
450                obj.remove(name).and_then(|o| o.as_str().and_then(|s| {
451                    match s.parse::<super::LinkSelfContainedDefault>() {
452                        Ok(lsc_default) => base.$key_name = lsc_default,
453                        _ => return Some(Err(format!("'{}' is not a valid `-Clink-self-contained` default. \
454                                                      Use 'false', 'true', 'musl' or 'mingw'", s))),
455                    }
456                    Some(Ok(()))
457                })).unwrap_or(Ok(()))
458            } );
459            ($key_name:ident = $json_name:expr, link_objects) => ( {
460                let name = $json_name;
461                if let Some(val) = obj.remove(name) {
462                    let obj = val.as_object().ok_or_else(|| format!("{}: expected a \
463                        JSON object with fields per CRT object kind.", name))?;
464                    let mut args = super::CrtObjects::new();
465                    for (k, v) in obj {
466                        let kind = super::LinkOutputKind::from_str(&k).ok_or_else(|| {
467                            format!("{}: '{}' is not a valid value for CRT object kind. \
468                                     Use '(dynamic,static)-(nopic,pic)-exe' or \
469                                     '(dynamic,static)-dylib' or 'wasi-reactor-exe'", name, k)
470                        })?;
471
472                        let v = v.as_array().ok_or_else(||
473                            format!("{}.{}: expected a JSON array", name, k)
474                        )?.iter().enumerate()
475                            .map(|(i,s)| {
476                                let s = s.as_str().ok_or_else(||
477                                    format!("{}.{}[{}]: expected a JSON string", name, k, i))?;
478                                Ok(s.to_string().into())
479                            })
480                            .collect::<Result<Vec<_>, String>>()?;
481
482                        args.insert(kind, v);
483                    }
484                    base.$key_name = args;
485                }
486            } );
487            ($key_name:ident = $json_name:expr, link_args) => ( {
488                let name = $json_name;
489                if let Some(val) = obj.remove(name) {
490                    let obj = val.as_object().ok_or_else(|| format!("{}: expected a \
491                        JSON object with fields per linker-flavor.", name))?;
492                    let mut args = super::LinkArgsCli::new();
493                    for (k, v) in obj {
494                        let flavor = super::LinkerFlavorCli::from_str(&k).ok_or_else(|| {
495                            format!("{}: '{}' is not a valid value for linker-flavor. \
496                                     Use 'em', 'gcc', 'ld' or 'msvc'", name, k)
497                        })?;
498
499                        let v = v.as_array().ok_or_else(||
500                            format!("{}.{}: expected a JSON array", name, k)
501                        )?.iter().enumerate()
502                            .map(|(i,s)| {
503                                let s = s.as_str().ok_or_else(||
504                                    format!("{}.{}[{}]: expected a JSON string", name, k, i))?;
505                                Ok(s.to_string().into())
506                            })
507                            .collect::<Result<Vec<_>, String>>()?;
508
509                        args.insert(flavor, v);
510                    }
511                    base.$key_name = args;
512                }
513            } );
514            ($key_name:ident, env) => ( {
515                let name = (stringify!($key_name)).replace("_", "-");
516                if let Some(o) = obj.remove(&name) {
517                    if let Some(a) = o.as_array() {
518                        for o in a {
519                            if let Some(s) = o.as_str() {
520                                if let [k, v] = *s.split('=').collect::<Vec<_>>() {
521                                    base.$key_name
522                                        .to_mut()
523                                        .push((k.to_string().into(), v.to_string().into()))
524                                }
525                            }
526                        }
527                    } else {
528                        incorrect_type.push(name)
529                    }
530                }
531            } );
532            ($key_name:ident, target_families) => ( {
533                if let Some(value) = obj.remove("target-family") {
534                    if let Some(v) = value.as_array() {
535                        base.$key_name = v.iter()
536                            .map(|a| a.as_str().unwrap().to_string().into())
537                            .collect();
538                    } else if let Some(v) = value.as_str() {
539                        base.$key_name = vec![v.to_string().into()].into();
540                    }
541                }
542            } );
543        }
544
545        if let Some(j) = obj.remove("target-endian") {
546            if let Some(s) = j.as_str() {
547                base.endian = s.parse()?;
548            } else {
549                incorrect_type.push("target-endian".into())
550            }
551        }
552
553        if let Some(fp) = obj.remove("frame-pointer") {
554            if let Some(s) = fp.as_str() {
555                base.frame_pointer = s
556                    .parse()
557                    .map_err(|()| format!("'{s}' is not a valid value for frame-pointer"))?;
558            } else {
559                incorrect_type.push("frame-pointer".into())
560            }
561        }
562
563        key!(c_int_width = "target-c-int-width", u64 as u16);
564        key!(c_enum_min_bits, Option<u64>); // if None, matches c_int_width
565        key!(os);
566        key!(env);
567        key!(abi);
568        key!(vendor);
569        key!(linker, optional);
570        key!(linker_flavor_json = "linker-flavor", LinkerFlavorCli)?;
571        key!(lld_flavor_json = "lld-flavor", LldFlavor)?;
572        key!(linker_is_gnu_json = "linker-is-gnu", bool);
573        key!(pre_link_objects = "pre-link-objects", link_objects);
574        key!(post_link_objects = "post-link-objects", link_objects);
575        key!(pre_link_objects_self_contained = "pre-link-objects-fallback", link_objects);
576        key!(post_link_objects_self_contained = "post-link-objects-fallback", link_objects);
577        // Deserializes the backwards-compatible variants of `-Clink-self-contained`
578        key!(
579            link_self_contained = "crt-objects-fallback",
580            link_self_contained_backwards_compatible
581        )?;
582        // Deserializes the components variant of `-Clink-self-contained`
583        key!(link_self_contained, link_self_contained_components)?;
584        key!(pre_link_args_json = "pre-link-args", link_args);
585        key!(late_link_args_json = "late-link-args", link_args);
586        key!(late_link_args_dynamic_json = "late-link-args-dynamic", link_args);
587        key!(late_link_args_static_json = "late-link-args-static", link_args);
588        key!(post_link_args_json = "post-link-args", link_args);
589        key!(link_script, optional);
590        key!(link_env, env);
591        key!(link_env_remove, list);
592        key!(asm_args, list);
593        key!(cpu);
594        key!(need_explicit_cpu, bool);
595        key!(features);
596        key!(dynamic_linking, bool);
597        key!(direct_access_external_data, Option<bool>);
598        key!(dll_tls_export, bool);
599        key!(only_cdylib, bool);
600        key!(executables, bool);
601        key!(relocation_model, RelocModel)?;
602        key!(code_model, CodeModel)?;
603        key!(tls_model, TlsModel)?;
604        key!(disable_redzone, bool);
605        key!(function_sections, bool);
606        key!(dll_prefix);
607        key!(dll_suffix);
608        key!(exe_suffix);
609        key!(staticlib_prefix);
610        key!(staticlib_suffix);
611        key!(families, target_families);
612        key!(abi_return_struct_as_int, bool);
613        key!(is_like_aix, bool);
614        key!(is_like_darwin, bool);
615        key!(is_like_solaris, bool);
616        key!(is_like_windows, bool);
617        key!(is_like_msvc, bool);
618        key!(is_like_wasm, bool);
619        key!(is_like_android, bool);
620        key!(binary_format, BinaryFormat)?;
621        key!(default_dwarf_version, u32);
622        key!(allows_weak_linkage, bool);
623        key!(has_rpath, bool);
624        key!(no_default_libraries, bool);
625        key!(position_independent_executables, bool);
626        key!(static_position_independent_executables, bool);
627        key!(plt_by_default, bool);
628        key!(relro_level, RelroLevel)?;
629        key!(archive_format);
630        key!(allow_asm, bool);
631        key!(main_needs_argc_argv, bool);
632        key!(has_thread_local, bool);
633        key!(obj_is_bitcode, bool);
634        key!(bitcode_llvm_cmdline);
635        key!(max_atomic_width, Option<u64>);
636        key!(min_atomic_width, Option<u64>);
637        key!(atomic_cas, bool);
638        key!(panic_strategy, PanicStrategy)?;
639        key!(crt_static_allows_dylibs, bool);
640        key!(crt_static_default, bool);
641        key!(crt_static_respected, bool);
642        key!(stack_probes, StackProbeType)?;
643        key!(min_global_align, Option<Align>);
644        key!(default_codegen_units, Option<u64>);
645        key!(default_codegen_backend, Option<StaticCow<str>>);
646        key!(trap_unreachable, bool);
647        key!(requires_lto, bool);
648        key!(singlethread, bool);
649        key!(no_builtins, bool);
650        key!(default_visibility, Option<SymbolVisibility>)?;
651        key!(emit_debug_gdb_scripts, bool);
652        key!(requires_uwtable, bool);
653        key!(default_uwtable, bool);
654        key!(simd_types_indirect, bool);
655        key!(limit_rdylib_exports, bool);
656        key!(override_export_symbols, opt_list);
657        key!(merge_functions, MergeFunctions)?;
658        key!(mcount = "target-mcount");
659        key!(llvm_mcount_intrinsic, optional);
660        key!(llvm_abiname);
661        key!(llvm_floatabi, FloatAbi)?;
662        key!(rustc_abi, RustcAbi)?;
663        key!(relax_elf_relocations, bool);
664        key!(llvm_args, list);
665        key!(use_ctors_section, bool);
666        key!(eh_frame_header, bool);
667        key!(has_thumb_interworking, bool);
668        key!(debuginfo_kind, DebuginfoKind)?;
669        key!(split_debuginfo, SplitDebuginfo)?;
670        key!(supported_split_debuginfo, fallible_list)?;
671        key!(supported_sanitizers, SanitizerSet)?;
672        key!(generate_arange_section, bool);
673        key!(supports_stack_protector, bool);
674        key!(small_data_threshold_support, SmallDataThresholdSupport)?;
675        key!(entry_name);
676        key!(supports_xray, bool);
677
678        // we're going to run `update_from_cli`, but that won't change the target's AbiMap
679        // FIXME: better factor the Target definition so we enforce this on a type level
680        let abi_map = AbiMap::from_target(&base);
681
682        if let Some(abi_str) = obj.remove("entry-abi") {
683            if let Json::String(abi_str) = abi_str {
684                match abi_str.parse::<ExternAbi>() {
685                    Ok(abi) => base.options.entry_abi = abi_map.canonize_abi(abi, false).unwrap(),
686                    Err(_) => return Err(format!("{abi_str} is not a valid ExternAbi")),
687                }
688            } else {
689                incorrect_type.push("entry-abi".to_owned())
690            }
691        }
692
693        base.update_from_cli();
694        base.check_consistency(TargetKind::Json)?;
695
696        // Each field should have been read using `Json::remove` so any keys remaining are unused.
697        let remaining_keys = obj.keys();
698        Ok((
699            base,
700            TargetWarnings { unused_fields: remaining_keys.cloned().collect(), incorrect_type },
701        ))
702    }
703}
704
705impl ToJson for Target {
706    fn to_json(&self) -> Json {
707        let mut d = serde_json::Map::new();
708        let default: TargetOptions = Default::default();
709        let mut target = self.clone();
710        target.update_to_cli();
711
712        macro_rules! target_val {
713            ($attr:ident) => {{
714                let name = (stringify!($attr)).replace("_", "-");
715                d.insert(name, target.$attr.to_json());
716            }};
717        }
718
719        macro_rules! target_option_val {
720            ($attr:ident) => {{
721                let name = (stringify!($attr)).replace("_", "-");
722                if default.$attr != target.$attr {
723                    d.insert(name, target.$attr.to_json());
724                }
725            }};
726            ($attr:ident, $json_name:expr) => {{
727                let name = $json_name;
728                if default.$attr != target.$attr {
729                    d.insert(name.into(), target.$attr.to_json());
730                }
731            }};
732            (link_args - $attr:ident, $json_name:expr) => {{
733                let name = $json_name;
734                if default.$attr != target.$attr {
735                    let obj = target
736                        .$attr
737                        .iter()
738                        .map(|(k, v)| (k.desc().to_string(), v.clone()))
739                        .collect::<BTreeMap<_, _>>();
740                    d.insert(name.to_string(), obj.to_json());
741                }
742            }};
743            (env - $attr:ident) => {{
744                let name = (stringify!($attr)).replace("_", "-");
745                if default.$attr != target.$attr {
746                    let obj = target
747                        .$attr
748                        .iter()
749                        .map(|&(ref k, ref v)| format!("{k}={v}"))
750                        .collect::<Vec<_>>();
751                    d.insert(name, obj.to_json());
752                }
753            }};
754        }
755
756        target_val!(llvm_target);
757        target_val!(metadata);
758        d.insert("target-pointer-width".to_string(), self.pointer_width.to_string().to_json());
759        target_val!(arch);
760        target_val!(data_layout);
761
762        target_option_val!(endian, "target-endian");
763        target_option_val!(c_int_width, "target-c-int-width");
764        target_option_val!(os);
765        target_option_val!(env);
766        target_option_val!(abi);
767        target_option_val!(vendor);
768        target_option_val!(linker);
769        target_option_val!(linker_flavor_json, "linker-flavor");
770        target_option_val!(lld_flavor_json, "lld-flavor");
771        target_option_val!(linker_is_gnu_json, "linker-is-gnu");
772        target_option_val!(pre_link_objects);
773        target_option_val!(post_link_objects);
774        target_option_val!(pre_link_objects_self_contained, "pre-link-objects-fallback");
775        target_option_val!(post_link_objects_self_contained, "post-link-objects-fallback");
776        target_option_val!(link_args - pre_link_args_json, "pre-link-args");
777        target_option_val!(link_args - late_link_args_json, "late-link-args");
778        target_option_val!(link_args - late_link_args_dynamic_json, "late-link-args-dynamic");
779        target_option_val!(link_args - late_link_args_static_json, "late-link-args-static");
780        target_option_val!(link_args - post_link_args_json, "post-link-args");
781        target_option_val!(link_script);
782        target_option_val!(env - link_env);
783        target_option_val!(link_env_remove);
784        target_option_val!(asm_args);
785        target_option_val!(cpu);
786        target_option_val!(need_explicit_cpu);
787        target_option_val!(features);
788        target_option_val!(dynamic_linking);
789        target_option_val!(direct_access_external_data);
790        target_option_val!(dll_tls_export);
791        target_option_val!(only_cdylib);
792        target_option_val!(executables);
793        target_option_val!(relocation_model);
794        target_option_val!(code_model);
795        target_option_val!(tls_model);
796        target_option_val!(disable_redzone);
797        target_option_val!(frame_pointer);
798        target_option_val!(function_sections);
799        target_option_val!(dll_prefix);
800        target_option_val!(dll_suffix);
801        target_option_val!(exe_suffix);
802        target_option_val!(staticlib_prefix);
803        target_option_val!(staticlib_suffix);
804        target_option_val!(families, "target-family");
805        target_option_val!(abi_return_struct_as_int);
806        target_option_val!(is_like_aix);
807        target_option_val!(is_like_darwin);
808        target_option_val!(is_like_solaris);
809        target_option_val!(is_like_windows);
810        target_option_val!(is_like_msvc);
811        target_option_val!(is_like_wasm);
812        target_option_val!(is_like_android);
813        target_option_val!(binary_format);
814        target_option_val!(default_dwarf_version);
815        target_option_val!(allows_weak_linkage);
816        target_option_val!(has_rpath);
817        target_option_val!(no_default_libraries);
818        target_option_val!(position_independent_executables);
819        target_option_val!(static_position_independent_executables);
820        target_option_val!(plt_by_default);
821        target_option_val!(relro_level);
822        target_option_val!(archive_format);
823        target_option_val!(allow_asm);
824        target_option_val!(main_needs_argc_argv);
825        target_option_val!(has_thread_local);
826        target_option_val!(obj_is_bitcode);
827        target_option_val!(bitcode_llvm_cmdline);
828        target_option_val!(min_atomic_width);
829        target_option_val!(max_atomic_width);
830        target_option_val!(atomic_cas);
831        target_option_val!(panic_strategy);
832        target_option_val!(crt_static_allows_dylibs);
833        target_option_val!(crt_static_default);
834        target_option_val!(crt_static_respected);
835        target_option_val!(stack_probes);
836        target_option_val!(min_global_align);
837        target_option_val!(default_codegen_units);
838        target_option_val!(default_codegen_backend);
839        target_option_val!(trap_unreachable);
840        target_option_val!(requires_lto);
841        target_option_val!(singlethread);
842        target_option_val!(no_builtins);
843        target_option_val!(default_visibility);
844        target_option_val!(emit_debug_gdb_scripts);
845        target_option_val!(requires_uwtable);
846        target_option_val!(default_uwtable);
847        target_option_val!(simd_types_indirect);
848        target_option_val!(limit_rdylib_exports);
849        target_option_val!(override_export_symbols);
850        target_option_val!(merge_functions);
851        target_option_val!(mcount, "target-mcount");
852        target_option_val!(llvm_mcount_intrinsic);
853        target_option_val!(llvm_abiname);
854        target_option_val!(llvm_floatabi);
855        target_option_val!(rustc_abi);
856        target_option_val!(relax_elf_relocations);
857        target_option_val!(llvm_args);
858        target_option_val!(use_ctors_section);
859        target_option_val!(eh_frame_header);
860        target_option_val!(has_thumb_interworking);
861        target_option_val!(debuginfo_kind);
862        target_option_val!(split_debuginfo);
863        target_option_val!(supported_split_debuginfo);
864        target_option_val!(supported_sanitizers);
865        target_option_val!(c_enum_min_bits);
866        target_option_val!(generate_arange_section);
867        target_option_val!(supports_stack_protector);
868        target_option_val!(small_data_threshold_support);
869        target_option_val!(entry_name);
870        target_option_val!(entry_abi);
871        target_option_val!(supports_xray);
872
873        // Serializing `-Clink-self-contained` needs a dynamic key to support the
874        // backwards-compatible variants.
875        d.insert(self.link_self_contained.json_key().into(), self.link_self_contained.to_json());
876
877        Json::Object(d)
878    }
879}