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