1use std::collections::BTreeMap;
2use std::str::FromStr;
3
4use rustc_abi::{Align, AlignFromBytesError};
5
6use super::crt_objects::CrtObjects;
7use super::{
8 BinaryFormat, CodeModel, DebuginfoKind, FloatAbi, FramePointer, LinkArgsCli,
9 LinkSelfContainedComponents, LinkSelfContainedDefault, LinkerFlavorCli, LldFlavor,
10 MergeFunctions, PanicStrategy, RelocModel, RelroLevel, RustcAbi, SanitizerSet,
11 SmallDataThresholdSupport, SplitDebuginfo, StackProbeType, StaticCow, SymbolVisibility, Target,
12 TargetKind, TargetOptions, TargetWarnings, TlsModel,
13};
14use crate::json::{Json, ToJson};
15use crate::spec::AbiMap;
16
17impl Target {
18 pub fn from_json(json: &str) -> Result<(Target, TargetWarnings), String> {
20 let json_deserializer = &mut serde_json::Deserializer::from_str(json);
21
22 let json: TargetSpecJson =
23 serde_path_to_error::deserialize(json_deserializer).map_err(|err| err.to_string())?;
24
25 let mut base = Target {
26 llvm_target: json.llvm_target,
27 metadata: Default::default(),
28 pointer_width: json
29 .target_pointer_width
30 .parse()
31 .map_err(|err| format!("invalid target-pointer-width: {err}"))?,
32 data_layout: json.data_layout,
33 arch: json.arch,
34 options: Default::default(),
35 };
36
37 if let Some(metadata) = json.metadata {
41 base.metadata.description = metadata.description;
42 base.metadata.tier = metadata.tier.filter(|tier| (1..=3).contains(tier));
43 base.metadata.host_tools = metadata.host_tools;
44 base.metadata.std = metadata.std;
45 }
46
47 let alignment_error = |field_name: &str, error: AlignFromBytesError| -> String {
48 let msg = match error {
49 AlignFromBytesError::NotPowerOfTwo(_) => "not a power of 2 number of bytes",
50 AlignFromBytesError::TooLarge(_) => "too large",
51 };
52 format!("`{}` bits is not a valid value for {field_name}: {msg}", error.align() * 8)
53 };
54
55 macro_rules! forward {
56 ($name:ident) => {
57 if let Some($name) = json.$name {
58 base.$name = $name;
59 }
60 };
61 }
62 macro_rules! forward_opt {
63 ($name:ident) => {
64 if let Some($name) = json.$name {
65 base.$name = Some($name);
66 }
67 };
68 }
69
70 if let Some(target_endian) = json.target_endian {
71 base.endian = target_endian.0;
72 }
73
74 forward!(frame_pointer);
75 forward!(c_int_width);
76 forward_opt!(c_enum_min_bits); forward!(os);
78 forward!(env);
79 forward!(abi);
80 forward!(vendor);
81 forward_opt!(linker);
82 forward!(linker_flavor_json);
83 forward!(lld_flavor_json);
84 forward!(linker_is_gnu_json);
85 forward!(pre_link_objects);
86 forward!(post_link_objects);
87 forward!(pre_link_objects_self_contained);
88 forward!(post_link_objects_self_contained);
89
90 if let Some(link_self_contained) = json.link_self_contained_backwards_compatible {
92 base.link_self_contained = link_self_contained;
93 }
94 if let Some(link_self_contained) = json.link_self_contained {
96 let components = link_self_contained
97 .components
98 .into_iter()
99 .fold(LinkSelfContainedComponents::empty(), |a, b| a | b);
100 base.link_self_contained = LinkSelfContainedDefault::WithComponents(components);
101 }
102
103 forward!(pre_link_args_json);
104 forward!(late_link_args_json);
105 forward!(late_link_args_dynamic_json);
106 forward!(late_link_args_static_json);
107 forward!(post_link_args_json);
108 forward_opt!(link_script);
109
110 if let Some(link_env) = json.link_env {
111 for s in link_env {
112 if let [k, v] = *s.split('=').collect::<Vec<_>>() {
113 base.link_env.to_mut().push((k.to_string().into(), v.to_string().into()))
114 } else {
115 return Err(format!("link-env value '{s}' must be of the pattern 'KEY=VALUE'"));
116 }
117 }
118 }
119
120 forward!(link_env_remove);
121 forward!(asm_args);
122 forward!(cpu);
123 forward!(need_explicit_cpu);
124 forward!(features);
125 forward!(dynamic_linking);
126 forward_opt!(direct_access_external_data);
127 forward!(dll_tls_export);
128 forward!(only_cdylib);
129 forward!(executables);
130 forward!(relocation_model);
131 forward_opt!(code_model);
132 forward!(tls_model);
133 forward!(disable_redzone);
134 forward!(function_sections);
135 forward!(dll_prefix);
136 forward!(dll_suffix);
137 forward!(exe_suffix);
138 forward!(staticlib_prefix);
139 forward!(staticlib_suffix);
140
141 if let Some(target_family) = json.target_family {
142 match target_family {
143 TargetFamiliesJson::Array(families) => base.families = families,
144 TargetFamiliesJson::String(family) => base.families = vec![family].into(),
145 }
146 }
147
148 forward!(abi_return_struct_as_int);
149 forward!(is_like_aix);
150 forward!(is_like_darwin);
151 forward!(is_like_solaris);
152 forward!(is_like_windows);
153 forward!(is_like_msvc);
154 forward!(is_like_wasm);
155 forward!(is_like_android);
156 forward!(is_like_vexos);
157 forward!(binary_format);
158 forward!(default_dwarf_version);
159 forward!(allows_weak_linkage);
160 forward!(has_rpath);
161 forward!(no_default_libraries);
162 forward!(position_independent_executables);
163 forward!(static_position_independent_executables);
164 forward!(plt_by_default);
165 forward!(relro_level);
166 forward!(archive_format);
167 forward!(allow_asm);
168 forward!(main_needs_argc_argv);
169 forward!(has_thread_local);
170 forward!(obj_is_bitcode);
171 forward!(bitcode_llvm_cmdline);
172 forward_opt!(max_atomic_width);
173 forward_opt!(min_atomic_width);
174 forward!(atomic_cas);
175 forward!(panic_strategy);
176 forward!(crt_static_allows_dylibs);
177 forward!(crt_static_default);
178 forward!(crt_static_respected);
179 forward!(stack_probes);
180
181 if let Some(min_global_align) = json.min_global_align {
182 match Align::from_bits(min_global_align) {
183 Ok(align) => base.min_global_align = Some(align),
184 Err(e) => return Err(alignment_error("min-global-align", e)),
185 }
186 }
187
188 forward_opt!(default_codegen_units);
189 forward_opt!(default_codegen_backend);
190 forward!(trap_unreachable);
191 forward!(requires_lto);
192 forward!(singlethread);
193 forward!(no_builtins);
194 forward_opt!(default_visibility);
195 forward!(emit_debug_gdb_scripts);
196 forward!(requires_uwtable);
197 forward!(default_uwtable);
198 forward!(simd_types_indirect);
199 forward!(limit_rdylib_exports);
200 forward_opt!(override_export_symbols);
201 forward!(merge_functions);
202 forward!(mcount);
203 forward_opt!(llvm_mcount_intrinsic);
204 forward!(llvm_abiname);
205 forward_opt!(llvm_floatabi);
206 forward_opt!(rustc_abi);
207 forward!(relax_elf_relocations);
208 forward!(llvm_args);
209 forward!(use_ctors_section);
210 forward!(eh_frame_header);
211 forward!(has_thumb_interworking);
212 forward!(debuginfo_kind);
213 forward!(split_debuginfo);
214 forward!(supported_split_debuginfo);
215
216 if let Some(supported_sanitizers) = json.supported_sanitizers {
217 base.supported_sanitizers =
218 supported_sanitizers.into_iter().fold(SanitizerSet::empty(), |a, b| a | b);
219 }
220
221 forward!(generate_arange_section);
222 forward!(supports_stack_protector);
223 forward!(small_data_threshold_support);
224 forward!(entry_name);
225 forward!(supports_xray);
226
227 let abi_map = AbiMap::from_target(&base);
230 if let Some(entry_abi) = json.entry_abi {
231 base.options.entry_abi = abi_map.canonize_abi(entry_abi.0, false).unwrap();
232 }
233
234 base.update_from_cli();
235 base.check_consistency(TargetKind::Json)?;
236
237 Ok((base, TargetWarnings { unused_fields: vec![] }))
238 }
239}
240
241impl ToJson for Target {
242 fn to_json(&self) -> Json {
243 let mut d = serde_json::Map::new();
244 let default: TargetOptions = Default::default();
245 let mut target = self.clone();
246 target.update_to_cli();
247
248 macro_rules! target_val {
249 ($attr:ident) => {{
250 let name = (stringify!($attr)).replace("_", "-");
251 d.insert(name, target.$attr.to_json());
252 }};
253 }
254
255 macro_rules! target_option_val {
256 ($attr:ident) => {{
257 let name = (stringify!($attr)).replace("_", "-");
258 if default.$attr != target.$attr {
259 d.insert(name, target.$attr.to_json());
260 }
261 }};
262 ($attr:ident, $json_name:expr) => {{
263 let name = $json_name;
264 if default.$attr != target.$attr {
265 d.insert(name.into(), target.$attr.to_json());
266 }
267 }};
268 (link_args - $attr:ident, $json_name:expr) => {{
269 let name = $json_name;
270 if default.$attr != target.$attr {
271 let obj = target
272 .$attr
273 .iter()
274 .map(|(k, v)| (k.desc().to_string(), v.clone()))
275 .collect::<BTreeMap<_, _>>();
276 d.insert(name.to_string(), obj.to_json());
277 }
278 }};
279 (env - $attr:ident) => {{
280 let name = (stringify!($attr)).replace("_", "-");
281 if default.$attr != target.$attr {
282 let obj = target
283 .$attr
284 .iter()
285 .map(|&(ref k, ref v)| format!("{k}={v}"))
286 .collect::<Vec<_>>();
287 d.insert(name, obj.to_json());
288 }
289 }};
290 }
291
292 target_val!(llvm_target);
293 target_val!(metadata);
294 d.insert("target-pointer-width".to_string(), self.pointer_width.to_string().to_json());
295 target_val!(arch);
296 target_val!(data_layout);
297
298 target_option_val!(endian, "target-endian");
299 target_option_val!(c_int_width, "target-c-int-width");
300 target_option_val!(os);
301 target_option_val!(env);
302 target_option_val!(abi);
303 target_option_val!(vendor);
304 target_option_val!(linker);
305 target_option_val!(linker_flavor_json, "linker-flavor");
306 target_option_val!(lld_flavor_json, "lld-flavor");
307 target_option_val!(linker_is_gnu_json, "linker-is-gnu");
308 target_option_val!(pre_link_objects);
309 target_option_val!(post_link_objects);
310 target_option_val!(pre_link_objects_self_contained, "pre-link-objects-fallback");
311 target_option_val!(post_link_objects_self_contained, "post-link-objects-fallback");
312 target_option_val!(link_args - pre_link_args_json, "pre-link-args");
313 target_option_val!(link_args - late_link_args_json, "late-link-args");
314 target_option_val!(link_args - late_link_args_dynamic_json, "late-link-args-dynamic");
315 target_option_val!(link_args - late_link_args_static_json, "late-link-args-static");
316 target_option_val!(link_args - post_link_args_json, "post-link-args");
317 target_option_val!(link_script);
318 target_option_val!(env - link_env);
319 target_option_val!(link_env_remove);
320 target_option_val!(asm_args);
321 target_option_val!(cpu);
322 target_option_val!(need_explicit_cpu);
323 target_option_val!(features);
324 target_option_val!(dynamic_linking);
325 target_option_val!(direct_access_external_data);
326 target_option_val!(dll_tls_export);
327 target_option_val!(only_cdylib);
328 target_option_val!(executables);
329 target_option_val!(relocation_model);
330 target_option_val!(code_model);
331 target_option_val!(tls_model);
332 target_option_val!(disable_redzone);
333 target_option_val!(frame_pointer);
334 target_option_val!(function_sections);
335 target_option_val!(dll_prefix);
336 target_option_val!(dll_suffix);
337 target_option_val!(exe_suffix);
338 target_option_val!(staticlib_prefix);
339 target_option_val!(staticlib_suffix);
340 target_option_val!(families, "target-family");
341 target_option_val!(abi_return_struct_as_int);
342 target_option_val!(is_like_aix);
343 target_option_val!(is_like_darwin);
344 target_option_val!(is_like_solaris);
345 target_option_val!(is_like_windows);
346 target_option_val!(is_like_msvc);
347 target_option_val!(is_like_wasm);
348 target_option_val!(is_like_android);
349 target_option_val!(is_like_vexos);
350 target_option_val!(binary_format);
351 target_option_val!(default_dwarf_version);
352 target_option_val!(allows_weak_linkage);
353 target_option_val!(has_rpath);
354 target_option_val!(no_default_libraries);
355 target_option_val!(position_independent_executables);
356 target_option_val!(static_position_independent_executables);
357 target_option_val!(plt_by_default);
358 target_option_val!(relro_level);
359 target_option_val!(archive_format);
360 target_option_val!(allow_asm);
361 target_option_val!(main_needs_argc_argv);
362 target_option_val!(has_thread_local);
363 target_option_val!(obj_is_bitcode);
364 target_option_val!(bitcode_llvm_cmdline);
365 target_option_val!(min_atomic_width);
366 target_option_val!(max_atomic_width);
367 target_option_val!(atomic_cas);
368 target_option_val!(panic_strategy);
369 target_option_val!(crt_static_allows_dylibs);
370 target_option_val!(crt_static_default);
371 target_option_val!(crt_static_respected);
372 target_option_val!(stack_probes);
373 target_option_val!(min_global_align);
374 target_option_val!(default_codegen_units);
375 target_option_val!(default_codegen_backend);
376 target_option_val!(trap_unreachable);
377 target_option_val!(requires_lto);
378 target_option_val!(singlethread);
379 target_option_val!(no_builtins);
380 target_option_val!(default_visibility);
381 target_option_val!(emit_debug_gdb_scripts);
382 target_option_val!(requires_uwtable);
383 target_option_val!(default_uwtable);
384 target_option_val!(simd_types_indirect);
385 target_option_val!(limit_rdylib_exports);
386 target_option_val!(override_export_symbols);
387 target_option_val!(merge_functions);
388 target_option_val!(mcount, "target-mcount");
389 target_option_val!(llvm_mcount_intrinsic);
390 target_option_val!(llvm_abiname);
391 target_option_val!(llvm_floatabi);
392 target_option_val!(rustc_abi);
393 target_option_val!(relax_elf_relocations);
394 target_option_val!(llvm_args);
395 target_option_val!(use_ctors_section);
396 target_option_val!(eh_frame_header);
397 target_option_val!(has_thumb_interworking);
398 target_option_val!(debuginfo_kind);
399 target_option_val!(split_debuginfo);
400 target_option_val!(supported_split_debuginfo);
401 target_option_val!(supported_sanitizers);
402 target_option_val!(c_enum_min_bits);
403 target_option_val!(generate_arange_section);
404 target_option_val!(supports_stack_protector);
405 target_option_val!(small_data_threshold_support);
406 target_option_val!(entry_name);
407 target_option_val!(entry_abi);
408 target_option_val!(supports_xray);
409
410 d.insert(self.link_self_contained.json_key().into(), self.link_self_contained.to_json());
413
414 Json::Object(d)
415 }
416}
417
418#[derive(serde_derive::Deserialize)]
419struct LinkSelfContainedComponentsWrapper {
420 components: Vec<LinkSelfContainedComponents>,
421}
422
423#[derive(serde_derive::Deserialize)]
424#[serde(untagged)]
425enum TargetFamiliesJson {
426 Array(StaticCow<[StaticCow<str>]>),
427 String(StaticCow<str>),
428}
429
430struct EndianWrapper(rustc_abi::Endian);
432impl FromStr for EndianWrapper {
433 type Err = String;
434 fn from_str(s: &str) -> Result<Self, Self::Err> {
435 rustc_abi::Endian::from_str(s).map(Self)
436 }
437}
438crate::json::serde_deserialize_from_str!(EndianWrapper);
439
440struct ExternAbiWrapper(rustc_abi::ExternAbi);
442impl FromStr for ExternAbiWrapper {
443 type Err = String;
444 fn from_str(s: &str) -> Result<Self, Self::Err> {
445 rustc_abi::ExternAbi::from_str(s)
446 .map(Self)
447 .map_err(|_| format!("{s} is not a valid extern ABI"))
448 }
449}
450crate::json::serde_deserialize_from_str!(ExternAbiWrapper);
451
452#[derive(serde_derive::Deserialize)]
453struct TargetSpecJsonMetadata {
454 description: Option<StaticCow<str>>,
455 tier: Option<u64>,
456 host_tools: Option<bool>,
457 std: Option<bool>,
458}
459
460#[derive(serde_derive::Deserialize)]
461#[serde(rename_all = "kebab-case")]
462#[serde(deny_unknown_fields)]
466struct TargetSpecJson {
467 llvm_target: StaticCow<str>,
468 target_pointer_width: String,
469 data_layout: StaticCow<str>,
470 arch: StaticCow<str>,
471
472 metadata: Option<TargetSpecJsonMetadata>,
473
474 target_endian: Option<EndianWrapper>,
476 frame_pointer: Option<FramePointer>,
477 #[serde(rename = "target-c-int-width")]
478 c_int_width: Option<u16>,
479 c_enum_min_bits: Option<u64>,
480 os: Option<StaticCow<str>>,
481 env: Option<StaticCow<str>>,
482 abi: Option<StaticCow<str>>,
483 vendor: Option<StaticCow<str>>,
484 linker: Option<StaticCow<str>>,
485 #[serde(rename = "linker-flavor")]
486 linker_flavor_json: Option<LinkerFlavorCli>,
487 #[serde(rename = "lld-flavor")]
488 lld_flavor_json: Option<LldFlavor>,
489 #[serde(rename = "linker-is-gnu")]
490 linker_is_gnu_json: Option<bool>,
491 #[serde(rename = "pre-link-objects")]
492 pre_link_objects: Option<CrtObjects>,
493 #[serde(rename = "post-link-objects")]
494 post_link_objects: Option<CrtObjects>,
495 #[serde(rename = "pre-link-objects-fallback")]
496 pre_link_objects_self_contained: Option<CrtObjects>,
497 #[serde(rename = "post-link-objects-fallback")]
498 post_link_objects_self_contained: Option<CrtObjects>,
499 #[serde(rename = "crt-objects-fallback")]
500 link_self_contained_backwards_compatible: Option<LinkSelfContainedDefault>,
501 link_self_contained: Option<LinkSelfContainedComponentsWrapper>,
502 #[serde(rename = "pre-link-args")]
503 pre_link_args_json: Option<LinkArgsCli>,
504 #[serde(rename = "late-link-args")]
505 late_link_args_json: Option<LinkArgsCli>,
506 #[serde(rename = "late-link-args-dynamic")]
507 late_link_args_dynamic_json: Option<LinkArgsCli>,
508 #[serde(rename = "late-link-args-static")]
509 late_link_args_static_json: Option<LinkArgsCli>,
510 #[serde(rename = "post-link-args")]
511 post_link_args_json: Option<LinkArgsCli>,
512 link_script: Option<StaticCow<str>>,
513 link_env: Option<Vec<StaticCow<str>>>,
514 link_env_remove: Option<StaticCow<[StaticCow<str>]>>,
515 asm_args: Option<StaticCow<[StaticCow<str>]>>,
516 cpu: Option<StaticCow<str>>,
517 need_explicit_cpu: Option<bool>,
518 features: Option<StaticCow<str>>,
519 dynamic_linking: Option<bool>,
520 direct_access_external_data: Option<bool>,
521 dll_tls_export: Option<bool>,
522 only_cdylib: Option<bool>,
523 executables: Option<bool>,
524 relocation_model: Option<RelocModel>,
525 code_model: Option<CodeModel>,
526 tls_model: Option<TlsModel>,
527 disable_redzone: Option<bool>,
528 function_sections: Option<bool>,
529 dll_prefix: Option<StaticCow<str>>,
530 dll_suffix: Option<StaticCow<str>>,
531 exe_suffix: Option<StaticCow<str>>,
532 staticlib_prefix: Option<StaticCow<str>>,
533 staticlib_suffix: Option<StaticCow<str>>,
534 target_family: Option<TargetFamiliesJson>,
535 abi_return_struct_as_int: Option<bool>,
536 is_like_aix: Option<bool>,
537 is_like_darwin: Option<bool>,
538 is_like_solaris: Option<bool>,
539 is_like_windows: Option<bool>,
540 is_like_msvc: Option<bool>,
541 is_like_wasm: Option<bool>,
542 is_like_android: Option<bool>,
543 is_like_vexos: Option<bool>,
544 binary_format: Option<BinaryFormat>,
545 default_dwarf_version: Option<u32>,
546 allows_weak_linkage: Option<bool>,
547 has_rpath: Option<bool>,
548 no_default_libraries: Option<bool>,
549 position_independent_executables: Option<bool>,
550 static_position_independent_executables: Option<bool>,
551 plt_by_default: Option<bool>,
552 relro_level: Option<RelroLevel>,
553 archive_format: Option<StaticCow<str>>,
554 allow_asm: Option<bool>,
555 main_needs_argc_argv: Option<bool>,
556 has_thread_local: Option<bool>,
557 obj_is_bitcode: Option<bool>,
558 bitcode_llvm_cmdline: Option<StaticCow<str>>,
559 max_atomic_width: Option<u64>,
560 min_atomic_width: Option<u64>,
561 atomic_cas: Option<bool>,
562 panic_strategy: Option<PanicStrategy>,
563 crt_static_allows_dylibs: Option<bool>,
564 crt_static_default: Option<bool>,
565 crt_static_respected: Option<bool>,
566 stack_probes: Option<StackProbeType>,
567 min_global_align: Option<u64>,
568 default_codegen_units: Option<u64>,
569 default_codegen_backend: Option<StaticCow<str>>,
570 trap_unreachable: Option<bool>,
571 requires_lto: Option<bool>,
572 singlethread: Option<bool>,
573 no_builtins: Option<bool>,
574 default_visibility: Option<SymbolVisibility>,
575 emit_debug_gdb_scripts: Option<bool>,
576 requires_uwtable: Option<bool>,
577 default_uwtable: Option<bool>,
578 simd_types_indirect: Option<bool>,
579 limit_rdylib_exports: Option<bool>,
580 override_export_symbols: Option<StaticCow<[StaticCow<str>]>>,
581 merge_functions: Option<MergeFunctions>,
582 #[serde(rename = "target-mcount")]
583 mcount: Option<StaticCow<str>>,
584 llvm_mcount_intrinsic: Option<StaticCow<str>>,
585 llvm_abiname: Option<StaticCow<str>>,
586 llvm_floatabi: Option<FloatAbi>,
587 rustc_abi: Option<RustcAbi>,
588 relax_elf_relocations: Option<bool>,
589 llvm_args: Option<StaticCow<[StaticCow<str>]>>,
590 use_ctors_section: Option<bool>,
591 eh_frame_header: Option<bool>,
592 has_thumb_interworking: Option<bool>,
593 debuginfo_kind: Option<DebuginfoKind>,
594 split_debuginfo: Option<SplitDebuginfo>,
595 supported_split_debuginfo: Option<StaticCow<[SplitDebuginfo]>>,
596 supported_sanitizers: Option<Vec<SanitizerSet>>,
597 generate_arange_section: Option<bool>,
598 supports_stack_protector: Option<bool>,
599 small_data_threshold_support: Option<SmallDataThresholdSupport>,
600 entry_name: Option<StaticCow<str>>,
601 supports_xray: Option<bool>,
602 entry_abi: Option<ExternAbiWrapper>,
603}