• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! In some cases, parts of bootstrap need to change part of a target spec just for one or a few
2 //! steps. Adding these targets to rustc proper would "leak" this implementation detail of
3 //! bootstrap, and would make it more complex to apply additional changes if the need arises.
4 //!
5 //! To address that problem, this module implements support for "synthetic targets". Synthetic
6 //! targets are custom target specs generated using builtin target specs as their base. You can use
7 //! one of the target specs already defined in this module, or create new ones by adding a new step
8 //! that calls create_synthetic_target.
9 
10 use crate::builder::{Builder, ShouldRun, Step};
11 use crate::config::TargetSelection;
12 use crate::Compiler;
13 use std::process::{Command, Stdio};
14 
15 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
16 pub(crate) struct MirOptPanicAbortSyntheticTarget {
17     pub(crate) compiler: Compiler,
18     pub(crate) base: TargetSelection,
19 }
20 
21 impl Step for MirOptPanicAbortSyntheticTarget {
22     type Output = TargetSelection;
23     const DEFAULT: bool = true;
24     const ONLY_HOSTS: bool = false;
25 
should_run(run: ShouldRun<'_>) -> ShouldRun<'_>26     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
27         run.never()
28     }
29 
run(self, builder: &Builder<'_>) -> Self::Output30     fn run(self, builder: &Builder<'_>) -> Self::Output {
31         create_synthetic_target(builder, self.compiler, "miropt-abort", self.base, |spec| {
32             spec.insert("panic-strategy".into(), "abort".into());
33         })
34     }
35 }
36 
create_synthetic_target( builder: &Builder<'_>, compiler: Compiler, suffix: &str, base: TargetSelection, customize: impl FnOnce(&mut serde_json::Map<String, serde_json::Value>), ) -> TargetSelection37 fn create_synthetic_target(
38     builder: &Builder<'_>,
39     compiler: Compiler,
40     suffix: &str,
41     base: TargetSelection,
42     customize: impl FnOnce(&mut serde_json::Map<String, serde_json::Value>),
43 ) -> TargetSelection {
44     if base.contains("synthetic") {
45         // This check is not strictly needed, but nothing currently needs recursive synthetic
46         // targets. If the need arises, removing this in the future *SHOULD* be safe.
47         panic!("cannot create synthetic targets with other synthetic targets as their base");
48     }
49 
50     let name = format!("{base}-synthetic-{suffix}");
51     let path = builder.out.join("synthetic-target-specs").join(format!("{name}.json"));
52     std::fs::create_dir_all(path.parent().unwrap()).unwrap();
53 
54     if builder.config.dry_run() {
55         std::fs::write(&path, b"dry run\n").unwrap();
56         return TargetSelection::create_synthetic(&name, path.to_str().unwrap());
57     }
58 
59     let mut cmd = Command::new(builder.rustc(compiler));
60     cmd.arg("--target").arg(base.rustc_target_arg());
61     cmd.args(["-Zunstable-options", "--print", "target-spec-json"]);
62     cmd.stdout(Stdio::piped());
63 
64     let output = cmd.spawn().unwrap().wait_with_output().unwrap();
65     if !output.status.success() {
66         panic!("failed to gather the target spec for {base}");
67     }
68 
69     let mut spec: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap();
70     let spec_map = spec.as_object_mut().unwrap();
71 
72     // The `is-builtin` attribute of a spec needs to be removed, otherwise rustc will complain.
73     spec_map.remove("is-builtin");
74 
75     customize(spec_map);
76 
77     std::fs::write(&path, &serde_json::to_vec_pretty(&spec).unwrap()).unwrap();
78     let target = TargetSelection::create_synthetic(&name, path.to_str().unwrap());
79     crate::cc_detect::find_target(builder, target);
80 
81     target
82 }
83