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 pub fn from_json(obj: Json) -> Result<(Target, TargetWarnings), String> {
15 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 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 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 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>); 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 key!(
556 link_self_contained = "crt-objects-fallback",
557 link_self_contained_backwards_compatible
558 )?;
559 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 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 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 d.insert(self.link_self_contained.json_key().into(), self.link_self_contained.to_json());
853
854 Json::Object(d)
855 }
856}