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