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