bootstrap/core/build_steps/
run.rs

1//! Build-and-run steps for in-repo tools
2//!
3//! A bit of a hodge-podge as e.g. if a tool's a test fixture it should be in `build_steps::test`.
4//! If it can be reached from `./x.py run` it can go here.
5
6use std::path::PathBuf;
7
8use crate::Mode;
9use crate::core::build_steps::dist::distdir;
10use crate::core::build_steps::test;
11use crate::core::build_steps::tool::{self, SourceType, Tool};
12use crate::core::build_steps::vendor::{Vendor, default_paths_to_vendor};
13use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
14use crate::core::config::TargetSelection;
15use crate::core::config::flags::get_completion;
16use crate::utils::exec::command;
17
18#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
19pub struct BuildManifest;
20
21impl Step for BuildManifest {
22    type Output = ();
23    const ONLY_HOSTS: bool = true;
24
25    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
26        run.path("src/tools/build-manifest")
27    }
28
29    fn make_run(run: RunConfig<'_>) {
30        run.builder.ensure(BuildManifest);
31    }
32
33    fn run(self, builder: &Builder<'_>) {
34        // This gets called by `promote-release`
35        // (https://github.com/rust-lang/promote-release).
36        let mut cmd = builder.tool_cmd(Tool::BuildManifest);
37        let sign = builder.config.dist_sign_folder.as_ref().unwrap_or_else(|| {
38            panic!("\n\nfailed to specify `dist.sign-folder` in `config.toml`\n\n")
39        });
40        let addr = builder.config.dist_upload_addr.as_ref().unwrap_or_else(|| {
41            panic!("\n\nfailed to specify `dist.upload-addr` in `config.toml`\n\n")
42        });
43
44        let today = command("date").arg("+%Y-%m-%d").run_capture_stdout(builder).stdout();
45
46        cmd.arg(sign);
47        cmd.arg(distdir(builder));
48        cmd.arg(today.trim());
49        cmd.arg(addr);
50        cmd.arg(&builder.config.channel);
51
52        builder.create_dir(&distdir(builder));
53        cmd.run(builder);
54    }
55}
56
57#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
58pub struct BumpStage0;
59
60impl Step for BumpStage0 {
61    type Output = ();
62    const ONLY_HOSTS: bool = true;
63
64    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
65        run.path("src/tools/bump-stage0")
66    }
67
68    fn make_run(run: RunConfig<'_>) {
69        run.builder.ensure(BumpStage0);
70    }
71
72    fn run(self, builder: &Builder<'_>) -> Self::Output {
73        let mut cmd = builder.tool_cmd(Tool::BumpStage0);
74        cmd.args(builder.config.args());
75        cmd.run(builder);
76    }
77}
78
79#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
80pub struct ReplaceVersionPlaceholder;
81
82impl Step for ReplaceVersionPlaceholder {
83    type Output = ();
84    const ONLY_HOSTS: bool = true;
85
86    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
87        run.path("src/tools/replace-version-placeholder")
88    }
89
90    fn make_run(run: RunConfig<'_>) {
91        run.builder.ensure(ReplaceVersionPlaceholder);
92    }
93
94    fn run(self, builder: &Builder<'_>) -> Self::Output {
95        let mut cmd = builder.tool_cmd(Tool::ReplaceVersionPlaceholder);
96        cmd.arg(&builder.src);
97        cmd.run(builder);
98    }
99}
100
101#[derive(Debug, Clone, PartialEq, Eq, Hash)]
102pub struct Miri {
103    target: TargetSelection,
104}
105
106impl Step for Miri {
107    type Output = ();
108    const ONLY_HOSTS: bool = false;
109
110    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
111        run.path("src/tools/miri")
112    }
113
114    fn make_run(run: RunConfig<'_>) {
115        run.builder.ensure(Miri { target: run.target });
116    }
117
118    fn run(self, builder: &Builder<'_>) {
119        let host = builder.build.build;
120        let target = self.target;
121        let stage = builder.top_stage;
122        if stage == 0 {
123            eprintln!("miri cannot be run at stage 0");
124            std::process::exit(1);
125        }
126
127        // This compiler runs on the host, we'll just use it for the target.
128        let target_compiler = builder.compiler(stage, host);
129        // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise
130        // we'd have stageN/bin/rustc and stageN/bin/rustdoc be effectively different stage
131        // compilers, which isn't what we want. Rustdoc should be linked in the same way as the
132        // rustc compiler it's paired with, so it must be built with the previous stage compiler.
133        let host_compiler = builder.compiler(stage - 1, host);
134
135        // Get a target sysroot for Miri.
136        let miri_sysroot = test::Miri::build_miri_sysroot(builder, target_compiler, target);
137
138        // # Run miri.
139        // Running it via `cargo run` as that figures out the right dylib path.
140        // add_rustc_lib_path does not add the path that contains librustc_driver-<...>.so.
141        let mut miri = tool::prepare_tool_cargo(
142            builder,
143            host_compiler,
144            Mode::ToolRustc,
145            host,
146            Kind::Run,
147            "src/tools/miri",
148            SourceType::InTree,
149            &[],
150        );
151        miri.add_rustc_lib_path(builder);
152        miri.arg("--").arg("--target").arg(target.rustc_target_arg());
153
154        // miri tests need to know about the stage sysroot
155        miri.arg("--sysroot").arg(miri_sysroot);
156
157        // Forward arguments. This may contain further arguments to the program
158        // after another --, so this must be at the end.
159        miri.args(builder.config.args());
160
161        miri.into_cmd().run(builder);
162    }
163}
164
165#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
166pub struct CollectLicenseMetadata;
167
168impl Step for CollectLicenseMetadata {
169    type Output = PathBuf;
170    const ONLY_HOSTS: bool = true;
171
172    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
173        run.path("src/tools/collect-license-metadata")
174    }
175
176    fn make_run(run: RunConfig<'_>) {
177        run.builder.ensure(CollectLicenseMetadata);
178    }
179
180    fn run(self, builder: &Builder<'_>) -> Self::Output {
181        let Some(reuse) = &builder.config.reuse else {
182            panic!("REUSE is required to collect the license metadata");
183        };
184
185        let dest = builder.src.join("license-metadata.json");
186
187        let mut cmd = builder.tool_cmd(Tool::CollectLicenseMetadata);
188        cmd.env("REUSE_EXE", reuse);
189        cmd.env("DEST", &dest);
190        cmd.run(builder);
191
192        dest
193    }
194}
195
196#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
197pub struct GenerateCopyright;
198
199impl Step for GenerateCopyright {
200    type Output = Vec<PathBuf>;
201    const ONLY_HOSTS: bool = true;
202
203    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
204        run.path("src/tools/generate-copyright")
205    }
206
207    fn make_run(run: RunConfig<'_>) {
208        run.builder.ensure(GenerateCopyright);
209    }
210
211    fn run(self, builder: &Builder<'_>) -> Self::Output {
212        let license_metadata = builder.src.join("license-metadata.json");
213        let dest = builder.out.join("COPYRIGHT.html");
214        let dest_libstd = builder.out.join("COPYRIGHT-library.html");
215
216        let paths_to_vendor = default_paths_to_vendor(builder);
217        for (_, submodules) in &paths_to_vendor {
218            for submodule in submodules {
219                builder.build.require_submodule(submodule, None);
220            }
221        }
222        let cargo_manifests = paths_to_vendor
223            .into_iter()
224            .map(|(path, _submodules)| path.to_str().unwrap().to_string())
225            .inspect(|path| assert!(!path.contains(','), "{path} contains a comma in its name"))
226            .collect::<Vec<_>>()
227            .join(",");
228
229        let vendored_sources = if let Some(path) = builder.vendored_crates_path() {
230            path
231        } else {
232            let cache_dir = builder.out.join("tmp").join("generate-copyright-vendor");
233            builder.ensure(Vendor {
234                sync_args: Vec::new(),
235                versioned_dirs: true,
236                root_dir: builder.src.clone(),
237                output_dir: cache_dir.clone(),
238            });
239            cache_dir
240        };
241
242        let mut cmd = builder.tool_cmd(Tool::GenerateCopyright);
243        cmd.env("CARGO_MANIFESTS", &cargo_manifests);
244        cmd.env("LICENSE_METADATA", &license_metadata);
245        cmd.env("DEST", &dest);
246        cmd.env("DEST_LIBSTD", &dest_libstd);
247        cmd.env("SRC_DIR", &builder.src);
248        cmd.env("VENDOR_DIR", &vendored_sources);
249        cmd.env("CARGO", &builder.initial_cargo);
250        // it is important that generate-copyright runs from the root of the
251        // source tree, because it uses relative paths
252        cmd.current_dir(&builder.src);
253        cmd.run(builder);
254
255        vec![dest, dest_libstd]
256    }
257}
258
259#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
260pub struct GenerateWindowsSys;
261
262impl Step for GenerateWindowsSys {
263    type Output = ();
264    const ONLY_HOSTS: bool = true;
265
266    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
267        run.path("src/tools/generate-windows-sys")
268    }
269
270    fn make_run(run: RunConfig<'_>) {
271        run.builder.ensure(GenerateWindowsSys);
272    }
273
274    fn run(self, builder: &Builder<'_>) {
275        let mut cmd = builder.tool_cmd(Tool::GenerateWindowsSys);
276        cmd.arg(&builder.src);
277        cmd.run(builder);
278    }
279}
280
281#[derive(Debug, Clone, PartialEq, Eq, Hash)]
282pub struct GenerateCompletions;
283
284macro_rules! generate_completions {
285    ( $( ( $shell:ident, $filename:expr ) ),* ) => {
286        $(
287            if let Some(comp) = get_completion($shell, &$filename) {
288                std::fs::write(&$filename, comp).expect(&format!("writing {} completion", stringify!($shell)));
289            }
290        )*
291    };
292}
293
294impl Step for GenerateCompletions {
295    type Output = ();
296
297    /// Uses `clap_complete` to generate shell completions.
298    fn run(self, builder: &Builder<'_>) {
299        use clap_complete::shells::{Bash, Fish, PowerShell, Zsh};
300
301        generate_completions!(
302            (Bash, builder.src.join("src/etc/completions/x.py.sh")),
303            (Zsh, builder.src.join("src/etc/completions/x.py.zsh")),
304            (Fish, builder.src.join("src/etc/completions/x.py.fish")),
305            (PowerShell, builder.src.join("src/etc/completions/x.py.ps1")),
306            (Bash, builder.src.join("src/etc/completions/x.sh")),
307            (Zsh, builder.src.join("src/etc/completions/x.zsh")),
308            (Fish, builder.src.join("src/etc/completions/x.fish")),
309            (PowerShell, builder.src.join("src/etc/completions/x.ps1"))
310        );
311    }
312
313    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
314        run.alias("generate-completions")
315    }
316
317    fn make_run(run: RunConfig<'_>) {
318        run.builder.ensure(GenerateCompletions);
319    }
320}
321
322#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
323pub struct UnicodeTableGenerator;
324
325impl Step for UnicodeTableGenerator {
326    type Output = ();
327    const ONLY_HOSTS: bool = true;
328
329    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
330        run.path("src/tools/unicode-table-generator")
331    }
332
333    fn make_run(run: RunConfig<'_>) {
334        run.builder.ensure(UnicodeTableGenerator);
335    }
336
337    fn run(self, builder: &Builder<'_>) {
338        let mut cmd = builder.tool_cmd(Tool::UnicodeTableGenerator);
339        cmd.arg(builder.src.join("library/core/src/unicode/unicode_data.rs"));
340        cmd.run(builder);
341    }
342}
343
344#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)]
345pub struct FeaturesStatusDump;
346
347impl Step for FeaturesStatusDump {
348    type Output = ();
349    const ONLY_HOSTS: bool = true;
350
351    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
352        run.path("src/tools/features-status-dump")
353    }
354
355    fn make_run(run: RunConfig<'_>) {
356        run.builder.ensure(FeaturesStatusDump);
357    }
358
359    fn run(self, builder: &Builder<'_>) {
360        let mut cmd = builder.tool_cmd(Tool::FeaturesStatusDump);
361
362        cmd.arg("--library-path");
363        cmd.arg(builder.src.join("library"));
364
365        cmd.arg("--compiler-path");
366        cmd.arg(builder.src.join("compiler"));
367
368        cmd.arg("--output-path");
369        cmd.arg(builder.out.join("features-status-dump.json"));
370
371        cmd.run(builder);
372    }
373}