rustc_target/spec/
json.rs

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