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 pub fn from_json(obj: Json) -> Result<(Target, TargetWarnings), String> {
13 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 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 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 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>); 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 key!(
566 link_self_contained = "crt-objects-fallback",
567 link_self_contained_backwards_compatible
568 )?;
569 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 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 d.insert(self.link_self_contained.json_key().into(), self.link_self_contained.to_json());
849
850 Json::Object(d)
851 }
852}