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_fentry: bool,
336 #[serde(default, skip_serializing_if = "ops::Not::not")]
337 pub supports_xray: bool,
338 #[serde(skip_serializing_if = "Option::is_none")]
339 pub simd_types_indirect: Option<bool>,
340 #[serde(default, skip_serializing_if = "ops::Not::not")]
341 pub singlethread: bool,
342 #[serde(default, skip_serializing_if = "TargetEndian::is_little")]
343 pub target_endian: TargetEndian,
344 #[serde(default, skip_serializing_if = "Vec::is_empty")]
345 pub target_family: Vec<TargetFamily>,
346 #[serde(skip_serializing_if = "Option::is_none")]
347 pub target_mcount: Option<String>,
348 #[serde(skip_serializing_if = "Option::is_none")]
350 pub target_c_int_width: Option<u32>,
351 pub target_pointer_width: u32,
353 #[serde(skip_serializing_if = "Option::is_none")]
354 pub tls_model: Option<String>,
355 #[serde(skip_serializing_if = "Option::is_none")]
356 pub trap_unreachable: Option<bool>,
357 #[serde(default, skip_serializing_if = "Vec::is_empty")]
358 pub unsupported_cpus: Vec<String>,
359 #[serde(skip_serializing_if = "Option::is_none")]
360 pub use_ctors_section: Option<bool>,
361 #[serde(skip_serializing_if = "Option::is_none")]
362 pub vendor: Option<String>,
363}
364
365#[derive(Debug, Clone, Serialize, Deserialize)]
366#[cfg_attr(test, serde(deny_unknown_fields))]
367#[non_exhaustive]
368pub struct Metadata {
369 pub description: Option<String>,
370 pub host_tools: Option<bool>,
371 pub std: Option<bool>,
372 pub tier: Option<u32>,
373}
374
375#[derive(Debug, Clone, Serialize, Deserialize)]
376#[serde(rename_all = "kebab-case")]
377#[cfg_attr(test, serde(deny_unknown_fields))]
378#[non_exhaustive]
379pub struct StackProbes {
380 pub kind: String,
381 #[serde(skip_serializing_if = "Option::is_none")]
382 pub min_llvm_version_for_inline: Option<(u32, u32, u32)>,
383}
384
385fn default_true() -> bool {
386 true
387}
388
389pub fn target_spec_json(rustc: Command, target: &str) -> Result<TargetSpec> {
391 let raw = ProcessBuilder::from_std(rustc)
392 .args(["-Z", "unstable-options", "--print", "target-spec-json", "--target", target])
393 .read()?;
394 serde_json::from_str(&raw).map_err(Error::new)
395}
396
397pub fn all_target_specs_json(rustc: Command) -> Result<AllTargetSpecs> {
399 let raw = ProcessBuilder::from_std(rustc)
400 .args(["-Z", "unstable-options", "--print", "all-target-specs-json"])
401 .read()?;
402 serde_json::from_str(&raw).map_err(Error::new)
403}
404
405#[cfg(test)]
406mod tests {
407 use std::eprintln;
408
409 use super::*;
410
411 fn target_spec_json(target: &str) -> Result<(TargetSpec, String)> {
412 let mut cmd = cmd!(
413 "rustc",
414 "-Z",
415 "unstable-options",
416 "--print",
417 "target-spec-json",
418 "--target",
419 target
420 );
421 if !rustversion::cfg!(nightly) {
422 cmd.env("RUSTC_BOOTSTRAP", "1");
423 }
424 let raw = cmd.read()?;
425 Ok((serde_json::from_str(&raw).map_err(Error::new)?, raw))
426 }
427
428 fn all_target_specs_json() -> Result<(AllTargetSpecs, String)> {
429 let mut cmd = cmd!("rustc", "-Z", "unstable-options", "--print", "all-target-specs-json");
430 if !rustversion::cfg!(nightly) {
431 cmd.env("RUSTC_BOOTSTRAP", "1");
432 }
433 let raw = cmd.read()?;
434 Ok((serde_json::from_str(&raw).map_err(Error::new)?, raw))
435 }
436
437 #[rustversion::attr(before(1.91), ignore)]
439 #[test]
440 #[cfg_attr(miri, ignore)] fn parse_target_spec_json() {
442 for target in cmd!("rustc", "--print", "target-list").read().unwrap().lines() {
444 eprintln!("target={target}:");
445 let (parsed, raw) = target_spec_json(target).unwrap();
446 let deserialized = serde_json::to_string(&parsed).unwrap();
447 assert_eq!(
448 serde_json::from_str::<serde_json::Value>(&raw).unwrap(),
449 serde_json::from_str::<serde_json::Value>(&deserialized).unwrap()
450 );
451 }
452 eprintln!("all-targets:");
453 let (parsed, raw) = all_target_specs_json().unwrap();
454 let deserialized = serde_json::to_string(&parsed).unwrap();
455 assert_eq!(
456 serde_json::from_str::<serde_json::Value>(&raw).unwrap(),
457 serde_json::from_str::<serde_json::Value>(&deserialized).unwrap()
458 );
459 }
466}