rustc_target/spec/
json.rs

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