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