1#![no_std]
52#![doc(test(
53 no_crate_inject,
54 attr(allow(
55 dead_code,
56 unused_variables,
57 clippy::undocumented_unsafe_blocks,
58 clippy::unused_trait_names,
59 ))
60))]
61#![forbid(unsafe_code)]
62#![warn(
63 missing_debug_implementations,
65 clippy::alloc_instead_of_core,
67 clippy::exhaustive_enums,
68 clippy::exhaustive_structs,
69 clippy::impl_trait_in_params,
70 clippy::std_instead_of_alloc,
71 clippy::std_instead_of_core,
72 )]
74
75extern crate alloc;
76extern crate std;
77
78#[cfg(test)]
79#[path = "gen/tests/assert_impl.rs"]
80mod assert_impl;
81#[cfg(test)]
82#[path = "gen/tests/track_size.rs"]
83mod track_size;
84
85#[path = "gen/target_spec.rs"]
86mod target_spec;
87pub use self::target_spec::{
88 Arch, BinaryFormat, Env, Os, PanicStrategy, Sanitizer, TargetEndian, TargetFamily,
89};
90
91#[macro_use]
92mod process;
93
94mod error;
95
96use alloc::{collections::BTreeMap, string::String, vec::Vec};
97use core::ops;
98use std::process::Command;
99
100use serde_derive::{Deserialize, Serialize};
101
102pub use self::error::Error;
103use self::{error::Result, process::ProcessBuilder};
104
105pub type AllTargetSpecs = BTreeMap<String, TargetSpec>;
106
107#[derive(Debug, Clone, Serialize, Deserialize)]
113#[serde(rename_all = "kebab-case")]
114#[cfg_attr(test, serde(deny_unknown_fields))]
115#[non_exhaustive]
116pub struct TargetSpec {
117 #[serde(skip_serializing_if = "Option::is_none")]
118 pub abi_return_struct_as_int: Option<bool>,
119 #[serde(skip_serializing_if = "Option::is_none")]
120 pub abi: Option<String>,
121 #[serde(skip_serializing_if = "Option::is_none")]
122 pub allows_weak_linkage: Option<bool>,
123 pub arch: Arch,
124 #[serde(skip_serializing_if = "Option::is_none")]
125 pub archive_format: Option<String>,
126 #[serde(skip_serializing_if = "Option::is_none")]
127 pub asm_args: Option<Vec<String>>,
128 #[serde(default = "default_true", skip_serializing_if = "Clone::clone")]
129 pub atomic_cas: bool,
130 #[serde(default, skip_serializing_if = "BinaryFormat::is_elf")]
131 pub binary_format: BinaryFormat,
132 #[serde(skip_serializing_if = "Option::is_none")]
133 pub bitcode_llvm_cmdline: Option<String>,
134 #[serde(skip_serializing_if = "Option::is_none")]
135 pub c_enum_min_bits: Option<u32>,
136 #[serde(skip_serializing_if = "Option::is_none")]
137 pub code_model: Option<String>,
138 #[serde(skip_serializing_if = "Option::is_none")]
139 pub cpu: Option<String>,
140 #[serde(skip_serializing_if = "Option::is_none")]
141 pub crt_objects_fallback: Option<String>,
142 #[serde(skip_serializing_if = "Option::is_none")]
143 pub crt_static_allows_dylibs: Option<bool>,
144 #[serde(skip_serializing_if = "Option::is_none")]
145 pub crt_static_default: Option<bool>,
146 #[serde(skip_serializing_if = "Option::is_none")]
147 pub crt_static_respected: Option<bool>,
148 pub data_layout: String,
149 #[serde(skip_serializing_if = "Option::is_none")]
150 pub debuginfo_kind: Option<String>,
151 #[serde(skip_serializing_if = "Option::is_none")]
152 pub default_adjusted_cabi: Option<String>,
153 #[serde(skip_serializing_if = "Option::is_none")]
154 pub default_codegen_units: Option<u32>,
155 #[serde(skip_serializing_if = "Option::is_none")]
156 pub default_dwarf_version: Option<u32>,
157 #[serde(skip_serializing_if = "Option::is_none")]
158 pub default_hidden_visibility: Option<bool>,
159 #[serde(skip_serializing_if = "Option::is_none")]
160 pub default_sanitizers: Option<Vec<Sanitizer>>,
161 #[serde(skip_serializing_if = "Option::is_none")]
162 pub default_uwtable: Option<bool>,
163 #[serde(skip_serializing_if = "Option::is_none")]
164 pub direct_access_external_data: Option<bool>,
165 #[serde(skip_serializing_if = "Option::is_none")]
166 pub disable_redzone: Option<bool>,
167 #[serde(skip_serializing_if = "Option::is_none")]
168 pub dll_prefix: Option<String>,
169 #[serde(skip_serializing_if = "Option::is_none")]
170 pub dll_suffix: Option<String>,
171 #[serde(skip_serializing_if = "Option::is_none")]
172 pub dll_tls_export: Option<bool>,
173 #[serde(skip_serializing_if = "Option::is_none")]
174 pub dynamic_linking: Option<bool>,
175 #[serde(skip_serializing_if = "Option::is_none")]
176 pub eh_frame_header: Option<bool>,
177 #[serde(skip_serializing_if = "Option::is_none")]
178 pub emit_debug_gdb_scripts: Option<bool>,
179 #[serde(skip_serializing_if = "Option::is_none")]
180 pub entry_abi: Option<String>,
181 #[serde(skip_serializing_if = "Option::is_none")]
182 pub entry_name: Option<String>,
183 #[serde(default, skip_serializing_if = "Env::is_none")]
184 pub env: Env,
185 #[serde(skip_serializing_if = "Option::is_none")]
186 pub executables: Option<bool>,
187 #[serde(skip_serializing_if = "Option::is_none")]
188 pub exe_suffix: Option<String>,
189 #[serde(skip_serializing_if = "Option::is_none")]
190 pub features: Option<String>,
191 #[serde(skip_serializing_if = "Option::is_none")]
192 pub force_emulated_tls: Option<bool>,
193 #[serde(skip_serializing_if = "Option::is_none")]
194 pub forces_embed_bitcode: Option<bool>,
195 #[serde(skip_serializing_if = "Option::is_none")]
196 pub frame_pointer: Option<String>,
197 #[serde(skip_serializing_if = "Option::is_none")]
198 pub function_sections: Option<bool>,
199 #[serde(skip_serializing_if = "Option::is_none")]
200 pub generate_arange_section: Option<bool>,
201 #[serde(skip_serializing_if = "Option::is_none")]
202 pub has_rpath: Option<bool>,
203 #[serde(skip_serializing_if = "Option::is_none")]
204 pub has_thread_local: Option<bool>,
205 #[serde(default, skip_serializing_if = "ops::Not::not")]
206 pub has_thumb_interworking: bool,
207 #[serde(default, skip_serializing_if = "ops::Not::not")]
208 pub is_builtin: bool,
209 #[serde(default, skip_serializing_if = "ops::Not::not")]
210 pub is_like_android: bool,
211 #[serde(default, skip_serializing_if = "ops::Not::not")]
212 pub is_like_aix: bool,
213 #[serde(default, skip_serializing_if = "ops::Not::not")]
214 pub is_like_darwin: bool,
215 #[serde(default, skip_serializing_if = "ops::Not::not")]
216 pub is_like_gpu: bool,
217 #[serde(default, skip_serializing_if = "ops::Not::not")]
219 pub is_like_osx: bool,
220 #[serde(default, skip_serializing_if = "ops::Not::not")]
221 pub is_like_solaris: bool,
222 #[serde(default, skip_serializing_if = "ops::Not::not")]
223 pub is_like_msvc: bool,
224 #[serde(default, skip_serializing_if = "ops::Not::not")]
225 pub is_like_vexos: bool,
226 #[serde(default, skip_serializing_if = "ops::Not::not")]
227 pub is_like_wasm: bool,
228 #[serde(default, skip_serializing_if = "ops::Not::not")]
229 pub is_like_windows: bool,
230 #[serde(skip_serializing_if = "Option::is_none")]
231 pub late_link_args: Option<BTreeMap<String, Vec<String>>>,
232 #[serde(skip_serializing_if = "Option::is_none")]
233 pub late_link_args_dynamic: Option<BTreeMap<String, Vec<String>>>,
234 #[serde(skip_serializing_if = "Option::is_none")]
235 pub late_link_args_static: Option<BTreeMap<String, Vec<String>>>,
236 #[serde(skip_serializing_if = "Option::is_none")]
237 pub limit_rdylib_exports: Option<bool>,
238 #[serde(skip_serializing_if = "Option::is_none")]
239 pub link_env: Option<Vec<String>>,
240 #[serde(skip_serializing_if = "Option::is_none")]
241 pub link_env_remove: Option<Vec<String>>,
242 #[serde(skip_serializing_if = "Option::is_none")]
243 pub link_self_contained: Option<BTreeMap<String, Vec<String>>>,
244 #[serde(skip_serializing_if = "Option::is_none")]
245 pub link_script: Option<String>,
246 #[serde(skip_serializing_if = "Option::is_none")]
247 pub linker: Option<String>,
248 #[serde(skip_serializing_if = "Option::is_none")]
249 pub linker_flavor: Option<String>,
250 #[serde(skip_serializing_if = "Option::is_none")]
251 pub linker_is_gnu: Option<bool>,
252 #[serde(skip_serializing_if = "Option::is_none")]
253 pub lld_flavor: Option<String>,
254 #[serde(skip_serializing_if = "Option::is_none")]
255 pub llvm_abiname: Option<String>,
256 #[serde(skip_serializing_if = "Option::is_none")]
257 pub llvm_args: Option<Vec<String>>,
258 #[serde(skip_serializing_if = "Option::is_none")]
259 pub llvm_floatabi: Option<String>,
260 #[serde(skip_serializing_if = "Option::is_none")]
261 pub llvm_mcount_intrinsic: Option<String>,
262 pub llvm_target: String,
263 #[serde(skip_serializing_if = "Option::is_none")]
264 pub main_needs_argc_argv: Option<bool>,
265 #[serde(skip_serializing_if = "Option::is_none")]
266 pub max_atomic_width: Option<u32>,
267 #[serde(skip_serializing_if = "Option::is_none")]
268 pub merge_functions: Option<String>,
269 pub metadata: Option<Metadata>,
270 #[serde(skip_serializing_if = "Option::is_none")]
271 pub min_atomic_width: Option<u32>,
272 #[serde(skip_serializing_if = "Option::is_none")]
273 pub min_global_align: Option<u32>,
274 #[serde(skip_serializing_if = "Option::is_none")]
275 pub need_explicit_cpu: Option<bool>,
276 #[serde(skip_serializing_if = "Option::is_none")]
277 pub needs_plt: Option<bool>,
278 #[serde(skip_serializing_if = "Option::is_none")]
279 pub no_builtins: Option<bool>,
280 #[serde(skip_serializing_if = "Option::is_none")]
281 pub no_default_libraries: Option<bool>,
282 #[serde(default, skip_serializing_if = "Os::is_none")]
283 pub os: Os,
284 #[serde(skip_serializing_if = "Option::is_none")]
285 pub obj_is_bitcode: Option<bool>,
286 #[serde(skip_serializing_if = "Option::is_none")]
287 pub only_cdylib: Option<bool>,
288 #[serde(skip_serializing_if = "Option::is_none")]
289 pub override_export_symbols: Option<Vec<String>>,
290 #[serde(default, skip_serializing_if = "PanicStrategy::is_unwind")]
291 pub panic_strategy: PanicStrategy,
292 #[serde(skip_serializing_if = "Option::is_none")]
293 pub plt_by_default: Option<bool>,
294 #[serde(skip_serializing_if = "Option::is_none")]
295 pub position_independent_executables: Option<bool>,
296 #[serde(skip_serializing_if = "Option::is_none")]
297 pub post_link_args: Option<BTreeMap<String, Vec<String>>>,
298 #[serde(skip_serializing_if = "Option::is_none")]
299 pub post_link_objects: Option<BTreeMap<String, Vec<String>>>,
300 #[serde(skip_serializing_if = "Option::is_none")]
301 pub post_link_objects_fallback: Option<BTreeMap<String, Vec<String>>>,
302 #[serde(skip_serializing_if = "Option::is_none")]
303 pub pre_link_args: Option<BTreeMap<String, Vec<String>>>,
304 #[serde(skip_serializing_if = "Option::is_none")]
305 pub pre_link_objects: Option<BTreeMap<String, Vec<String>>>,
306 #[serde(skip_serializing_if = "Option::is_none")]
307 pub pre_link_objects_fallback: Option<BTreeMap<String, Vec<String>>>,
308 #[serde(skip_serializing_if = "Option::is_none")]
309 pub relax_elf_relocations: Option<bool>,
310 #[serde(skip_serializing_if = "Option::is_none")]
311 pub relocation_model: Option<String>,
312 #[serde(skip_serializing_if = "Option::is_none")]
313 pub relro_level: Option<String>,
314 #[serde(skip_serializing_if = "Option::is_none")]
315 pub requires_consistent_cpu: Option<bool>,
316 #[serde(skip_serializing_if = "Option::is_none")]
317 pub requires_lto: Option<bool>,
318 #[serde(skip_serializing_if = "Option::is_none")]
319 pub requires_uwtable: Option<bool>,
320 #[serde(skip_serializing_if = "Option::is_none")]
321 pub rustc_abi: Option<String>,
322 #[serde(skip_serializing_if = "Option::is_none")]
323 pub split_debuginfo: Option<String>,
324 #[serde(skip_serializing_if = "Option::is_none")]
325 pub stack_probes: Option<StackProbes>,
326 #[serde(skip_serializing_if = "Option::is_none")]
327 pub static_initializer_must_be_acyclic: Option<bool>,
328 #[serde(skip_serializing_if = "Option::is_none")]
329 pub static_position_independent_executables: Option<bool>,
330 #[serde(skip_serializing_if = "Option::is_none")]
331 pub staticlib_prefix: Option<String>,
332 #[serde(skip_serializing_if = "Option::is_none")]
333 pub staticlib_suffix: Option<String>,
334 #[serde(default, skip_serializing_if = "Vec::is_empty")]
335 pub supported_sanitizers: Vec<Sanitizer>,
336 #[serde(default, skip_serializing_if = "Vec::is_empty")]
337 pub supported_split_debuginfo: Vec<String>,
338 #[serde(default = "default_true", skip_serializing_if = "Clone::clone")]
339 pub supports_stack_protector: bool,
340 #[serde(default, skip_serializing_if = "ops::Not::not")]
341 pub supports_fentry: bool,
342 #[serde(default, skip_serializing_if = "ops::Not::not")]
343 pub supports_xray: bool,
344 #[serde(skip_serializing_if = "Option::is_none")]
345 pub simd_types_indirect: Option<bool>,
346 #[serde(default, skip_serializing_if = "ops::Not::not")]
347 pub singlethread: bool,
348 #[serde(default, skip_serializing_if = "TargetEndian::is_little")]
349 pub target_endian: TargetEndian,
350 #[serde(default, skip_serializing_if = "Vec::is_empty")]
351 pub target_family: Vec<TargetFamily>,
352 #[serde(skip_serializing_if = "Option::is_none")]
353 pub target_mcount: Option<String>,
354 #[serde(skip_serializing_if = "Option::is_none")]
356 pub target_c_int_width: Option<u32>,
357 pub target_pointer_width: u32,
359 #[serde(skip_serializing_if = "Option::is_none")]
360 pub tls_model: Option<String>,
361 #[serde(skip_serializing_if = "Option::is_none")]
362 pub trap_unreachable: Option<bool>,
363 #[serde(default, skip_serializing_if = "Vec::is_empty")]
364 pub unsupported_cpus: Vec<String>,
365 #[serde(skip_serializing_if = "Option::is_none")]
366 pub use_ctors_section: Option<bool>,
367 #[serde(skip_serializing_if = "Option::is_none")]
368 pub vendor: Option<String>,
369}
370
371#[derive(Debug, Clone, Serialize, Deserialize)]
372#[cfg_attr(test, serde(deny_unknown_fields))]
373#[non_exhaustive]
374pub struct Metadata {
375 pub description: Option<String>,
376 pub host_tools: Option<bool>,
377 pub std: Option<bool>,
378 pub tier: Option<u32>,
379}
380
381#[derive(Debug, Clone, Serialize, Deserialize)]
382#[serde(rename_all = "kebab-case")]
383#[cfg_attr(test, serde(deny_unknown_fields))]
384#[non_exhaustive]
385pub struct StackProbes {
386 pub kind: String,
387 #[serde(skip_serializing_if = "Option::is_none")]
388 pub min_llvm_version_for_inline: Option<(u32, u32, u32)>,
389}
390
391fn default_true() -> bool {
392 true
393}
394
395pub fn target_spec_json(rustc: Command, target: &str) -> Result<TargetSpec> {
397 let raw = ProcessBuilder::from_std(rustc)
398 .args(["-Z", "unstable-options", "--print", "target-spec-json", "--target", target])
399 .read()?;
400 serde_json::from_str(&raw).map_err(Error::new)
401}
402
403pub fn all_target_specs_json(rustc: Command) -> Result<AllTargetSpecs> {
405 let raw = ProcessBuilder::from_std(rustc)
406 .args(["-Z", "unstable-options", "--print", "all-target-specs-json"])
407 .read()?;
408 serde_json::from_str(&raw).map_err(Error::new)
409}
410
411#[cfg(test)]
412mod tests {
413 use std::eprintln;
414
415 use super::*;
416
417 fn target_spec_json(target: &str) -> Result<(TargetSpec, String)> {
418 let mut cmd = cmd!(
419 "rustc",
420 "-Z",
421 "unstable-options",
422 "--print",
423 "target-spec-json",
424 "--target",
425 target
426 );
427 if !rustversion::cfg!(nightly) {
428 cmd.env("RUSTC_BOOTSTRAP", "1");
429 }
430 let raw = cmd.read()?;
431 Ok((serde_json::from_str(&raw).map_err(Error::new)?, raw))
432 }
433
434 fn all_target_specs_json() -> Result<(AllTargetSpecs, String)> {
435 let mut cmd = cmd!("rustc", "-Z", "unstable-options", "--print", "all-target-specs-json");
436 if !rustversion::cfg!(nightly) {
437 cmd.env("RUSTC_BOOTSTRAP", "1");
438 }
439 let raw = cmd.read()?;
440 Ok((serde_json::from_str(&raw).map_err(Error::new)?, raw))
441 }
442
443 #[rustversion::attr(before(1.91), ignore)]
445 #[test]
446 #[cfg_attr(miri, ignore)] fn parse_target_spec_json() {
448 for target in cmd!("rustc", "--print", "target-list").read().unwrap().lines() {
450 eprintln!("target={target}:");
451 let (parsed, raw) = target_spec_json(target).unwrap();
452 let deserialized = serde_json::to_string(&parsed).unwrap();
453 assert_eq!(
454 serde_json::from_str::<serde_json::Value>(&raw).unwrap(),
455 serde_json::from_str::<serde_json::Value>(&deserialized).unwrap()
456 );
457 }
458 eprintln!("all-targets:");
459 let (parsed, raw) = all_target_specs_json().unwrap();
460 let deserialized = serde_json::to_string(&parsed).unwrap();
461 assert_eq!(
462 serde_json::from_str::<serde_json::Value>(&raw).unwrap(),
463 serde_json::from_str::<serde_json::Value>(&deserialized).unwrap()
464 );
465 }
472}