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