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