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