bootstrap/core/build_steps/
run.rs1use std::path::PathBuf;
7
8use build_helper::exit;
9use build_helper::git::get_git_untracked_files;
10use clap_complete::{Generator, shells};
11
12use crate::core::build_steps::dist::distdir;
13use crate::core::build_steps::test;
14use crate::core::build_steps::tool::{self, RustcPrivateCompilers, SourceType, Tool};
15use crate::core::build_steps::vendor::{Vendor, default_paths_to_vendor};
16use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step, StepMetadata};
17use crate::core::config::TargetSelection;
18use crate::core::config::flags::{get_completion, top_level_help};
19use crate::utils::exec::command;
20use crate::{Mode, t};
21
22#[derive(Debug, Clone, Hash, PartialEq, Eq)]
23pub struct BuildManifest;
24
25impl Step for BuildManifest {
26 type Output = ();
27 const IS_HOST: bool = true;
28
29 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
30 run.path("src/tools/build-manifest")
31 }
32
33 fn make_run(run: RunConfig<'_>) {
34 run.builder.ensure(BuildManifest);
35 }
36
37 fn run(self, builder: &Builder<'_>) {
38 let mut cmd = command(
41 builder.ensure(tool::BuildManifest::new(builder, builder.config.host_target)).tool_path,
42 );
43 let sign = builder.config.dist_sign_folder.as_ref().unwrap_or_else(|| {
44 panic!("\n\nfailed to specify `dist.sign-folder` in `bootstrap.toml`\n\n")
45 });
46 let addr = builder.config.dist_upload_addr.as_ref().unwrap_or_else(|| {
47 panic!("\n\nfailed to specify `dist.upload-addr` in `bootstrap.toml`\n\n")
48 });
49
50 let today = command("date").arg("+%Y-%m-%d").run_capture_stdout(builder).stdout();
51
52 cmd.arg(sign);
53 cmd.arg(distdir(builder));
54 cmd.arg(today.trim());
55 cmd.arg(addr);
56 cmd.arg(&builder.config.channel);
57
58 builder.create_dir(&distdir(builder));
59 cmd.run(builder);
60 }
61}
62
63#[derive(Debug, Clone, Hash, PartialEq, Eq)]
64pub struct BumpStage0;
65
66impl Step for BumpStage0 {
67 type Output = ();
68 const IS_HOST: bool = true;
69
70 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
71 run.path("src/tools/bump-stage0")
72 }
73
74 fn make_run(run: RunConfig<'_>) {
75 run.builder.ensure(BumpStage0);
76 }
77
78 fn run(self, builder: &Builder<'_>) -> Self::Output {
79 let mut cmd = builder.tool_cmd(Tool::BumpStage0);
80 cmd.args(builder.config.args());
81 cmd.run(builder);
82 }
83}
84
85#[derive(Debug, Clone, Hash, PartialEq, Eq)]
86pub struct ReplaceVersionPlaceholder;
87
88impl Step for ReplaceVersionPlaceholder {
89 type Output = ();
90 const IS_HOST: bool = true;
91
92 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
93 run.path("src/tools/replace-version-placeholder")
94 }
95
96 fn make_run(run: RunConfig<'_>) {
97 run.builder.ensure(ReplaceVersionPlaceholder);
98 }
99
100 fn run(self, builder: &Builder<'_>) -> Self::Output {
101 let mut cmd = builder.tool_cmd(Tool::ReplaceVersionPlaceholder);
102 cmd.arg(&builder.src);
103 cmd.run(builder);
104 }
105}
106
107#[derive(Debug, Clone, PartialEq, Eq, Hash)]
114pub struct Miri {
115 compilers: RustcPrivateCompilers,
117 target: TargetSelection,
119}
120
121impl Step for Miri {
122 type Output = ();
123
124 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
125 run.path("src/tools/miri")
126 }
127
128 fn make_run(run: RunConfig<'_>) {
129 let builder = run.builder;
130
131 let stage = if builder.config.is_explicit_stage() || builder.top_stage >= 1 {
134 builder.top_stage
135 } else {
136 1
137 };
138
139 if stage == 0 {
140 eprintln!("ERROR: miri cannot be run at stage 0");
141 exit!(1);
142 }
143
144 let compilers = RustcPrivateCompilers::new(builder, stage, builder.host_target);
146
147 run.builder.ensure(Miri { compilers, target: run.target });
148 }
149
150 fn run(self, builder: &Builder<'_>) {
151 let host = builder.build.host_target;
152 let compilers = self.compilers;
153 let target = self.target;
154
155 builder.ensure(tool::Miri::from_compilers(compilers));
156
157 let miri_sysroot =
159 test::Miri::build_miri_sysroot(builder, compilers.target_compiler(), target);
160
161 let mut miri = tool::prepare_tool_cargo(
165 builder,
166 compilers.build_compiler(),
167 Mode::ToolRustcPrivate,
168 host,
169 Kind::Run,
170 "src/tools/miri",
171 SourceType::InTree,
172 &[],
173 );
174 miri.add_rustc_lib_path(builder);
175 miri.arg("--").arg("--target").arg(target.rustc_target_arg());
176
177 miri.arg("--sysroot").arg(miri_sysroot);
179
180 miri.args(builder.config.args());
183
184 miri.into_cmd().run(builder);
185 }
186
187 fn metadata(&self) -> Option<StepMetadata> {
188 Some(StepMetadata::run("miri", self.target).built_by(self.compilers.build_compiler()))
189 }
190}
191
192#[derive(Debug, Clone, Hash, PartialEq, Eq)]
193pub struct CollectLicenseMetadata;
194
195impl Step for CollectLicenseMetadata {
196 type Output = PathBuf;
197 const IS_HOST: bool = true;
198
199 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
200 run.path("src/tools/collect-license-metadata")
201 }
202
203 fn make_run(run: RunConfig<'_>) {
204 run.builder.ensure(CollectLicenseMetadata);
205 }
206
207 fn run(self, builder: &Builder<'_>) -> Self::Output {
208 let Some(reuse) = &builder.config.reuse else {
209 panic!("REUSE is required to collect the license metadata");
210 };
211
212 let dest = builder.src.join("license-metadata.json");
213
214 if !builder.config.dry_run() {
215 builder.require_and_update_all_submodules();
216 if let Ok(Some(untracked)) = get_git_untracked_files(None) {
217 eprintln!(
218 "Warning: {} untracked files may cause the license report to be incorrect.",
219 untracked.len()
220 );
221 }
222 }
223
224 let mut cmd = builder.tool_cmd(Tool::CollectLicenseMetadata);
225 cmd.env("REUSE_EXE", reuse);
226 cmd.env("DEST", &dest);
227 cmd.run(builder);
228
229 dest
230 }
231}
232
233#[derive(Debug, Clone, Hash, PartialEq, Eq)]
234pub struct GenerateCopyright;
235
236impl Step for GenerateCopyright {
237 type Output = Vec<PathBuf>;
238 const IS_HOST: bool = true;
239
240 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
241 run.path("src/tools/generate-copyright")
242 }
243
244 fn make_run(run: RunConfig<'_>) {
245 run.builder.ensure(GenerateCopyright);
246 }
247
248 fn run(self, builder: &Builder<'_>) -> Self::Output {
249 let license_metadata = builder.src.join("license-metadata.json");
250 let dest = builder.out.join("COPYRIGHT.html");
251 let dest_libstd = builder.out.join("COPYRIGHT-library.html");
252
253 let paths_to_vendor = default_paths_to_vendor(builder);
254 for (_, submodules) in &paths_to_vendor {
255 for submodule in submodules {
256 builder.build.require_submodule(submodule, None);
257 }
258 }
259 let cargo_manifests = paths_to_vendor
260 .into_iter()
261 .map(|(path, _submodules)| path.to_str().unwrap().to_string())
262 .inspect(|path| assert!(!path.contains(','), "{path} contains a comma in its name"))
263 .collect::<Vec<_>>()
264 .join(",");
265
266 let vendored_sources = if let Some(path) = builder.vendored_crates_path() {
267 path
268 } else {
269 let cache_dir = builder.out.join("tmp").join("generate-copyright-vendor");
270 builder.ensure(Vendor {
271 sync_args: Vec::new(),
272 versioned_dirs: true,
273 root_dir: builder.src.clone(),
274 output_dir: cache_dir.clone(),
275 });
276 cache_dir
277 };
278
279 let _guard = builder.group("generate-copyright");
280
281 let mut cmd = builder.tool_cmd(Tool::GenerateCopyright);
282 cmd.env("CARGO_MANIFESTS", &cargo_manifests);
283 cmd.env("LICENSE_METADATA", &license_metadata);
284 cmd.env("DEST", &dest);
285 cmd.env("DEST_LIBSTD", &dest_libstd);
286 cmd.env("SRC_DIR", &builder.src);
287 cmd.env("VENDOR_DIR", &vendored_sources);
288 cmd.env("CARGO", &builder.initial_cargo);
289 cmd.env("CARGO_HOME", t!(home::cargo_home()));
290 cmd.current_dir(&builder.src);
293 cmd.run(builder);
294
295 vec![dest, dest_libstd]
296 }
297}
298
299#[derive(Debug, Clone, Hash, PartialEq, Eq)]
300pub struct GenerateWindowsSys;
301
302impl Step for GenerateWindowsSys {
303 type Output = ();
304 const IS_HOST: bool = true;
305
306 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
307 run.path("src/tools/generate-windows-sys")
308 }
309
310 fn make_run(run: RunConfig<'_>) {
311 run.builder.ensure(GenerateWindowsSys);
312 }
313
314 fn run(self, builder: &Builder<'_>) {
315 let mut cmd = builder.tool_cmd(Tool::GenerateWindowsSys);
316 cmd.arg(&builder.src);
317 cmd.run(builder);
318 }
319}
320
321pub fn get_completion_paths(builder: &Builder<'_>) -> Vec<(&'static dyn Generator, PathBuf)> {
323 vec![
324 (&shells::Bash as &'static dyn Generator, builder.src.join("src/etc/completions/x.py.sh")),
325 (&shells::Zsh, builder.src.join("src/etc/completions/x.py.zsh")),
326 (&shells::Fish, builder.src.join("src/etc/completions/x.py.fish")),
327 (&shells::PowerShell, builder.src.join("src/etc/completions/x.py.ps1")),
328 (&shells::Bash, builder.src.join("src/etc/completions/x.sh")),
329 (&shells::Zsh, builder.src.join("src/etc/completions/x.zsh")),
330 (&shells::Fish, builder.src.join("src/etc/completions/x.fish")),
331 (&shells::PowerShell, builder.src.join("src/etc/completions/x.ps1")),
332 ]
333}
334
335#[derive(Debug, Clone, PartialEq, Eq, Hash)]
336pub struct GenerateCompletions;
337
338impl Step for GenerateCompletions {
339 type Output = ();
340
341 fn run(self, builder: &Builder<'_>) {
343 for (shell, path) in get_completion_paths(builder) {
344 if let Some(comp) = get_completion(shell, &path) {
345 std::fs::write(&path, comp).unwrap_or_else(|e| {
346 panic!("writing completion into {} failed: {e:?}", path.display())
347 });
348 }
349 }
350 }
351
352 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
353 run.alias("generate-completions")
354 }
355
356 fn make_run(run: RunConfig<'_>) {
357 run.builder.ensure(GenerateCompletions);
358 }
359}
360
361#[derive(Debug, Clone, Hash, PartialEq, Eq)]
364pub struct UnicodeTableGenerator;
365
366impl Step for UnicodeTableGenerator {
367 type Output = ();
368 const IS_HOST: bool = true;
369
370 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
371 run.path("src/tools/unicode-table-generator")
372 }
373
374 fn make_run(run: RunConfig<'_>) {
375 run.builder.ensure(UnicodeTableGenerator);
376 }
377
378 fn run(self, builder: &Builder<'_>) {
379 let mut cmd = builder.tool_cmd(Tool::UnicodeTableGenerator);
380 cmd.arg(builder.src.join("library/core/src/unicode/unicode_data.rs"));
382 cmd.arg(builder.src.join("library/coretests/tests/unicode/test_data.rs"));
383 cmd.run(builder);
384 }
385}
386
387#[derive(Debug, Clone, Hash, PartialEq, Eq)]
388pub struct FeaturesStatusDump;
389
390impl Step for FeaturesStatusDump {
391 type Output = ();
392 const IS_HOST: bool = true;
393
394 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
395 run.path("src/tools/features-status-dump")
396 }
397
398 fn make_run(run: RunConfig<'_>) {
399 run.builder.ensure(FeaturesStatusDump);
400 }
401
402 fn run(self, builder: &Builder<'_>) {
403 let mut cmd = builder.tool_cmd(Tool::FeaturesStatusDump);
404
405 cmd.arg("--library-path");
406 cmd.arg(builder.src.join("library"));
407
408 cmd.arg("--compiler-path");
409 cmd.arg(builder.src.join("compiler"));
410
411 cmd.arg("--output-path");
412 cmd.arg(builder.out.join("features-status-dump.json"));
413
414 cmd.run(builder);
415 }
416}
417
418#[derive(Clone, Debug, PartialEq, Eq, Hash)]
421pub struct CyclicStep {
422 n: u32,
423}
424
425impl Step for CyclicStep {
426 type Output = ();
427
428 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
429 run.alias("cyclic-step")
430 }
431
432 fn make_run(run: RunConfig<'_>) {
433 run.builder.ensure(CyclicStep { n: 2 })
435 }
436
437 fn run(self, builder: &Builder<'_>) -> Self::Output {
438 builder.ensure(CyclicStep { n: self.n.saturating_sub(1) })
440 }
441}
442
443#[derive(Debug, Clone, Hash, PartialEq, Eq)]
448pub struct CoverageDump;
449
450impl Step for CoverageDump {
451 type Output = ();
452 const IS_HOST: bool = true;
453
454 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
455 run.path("src/tools/coverage-dump")
456 }
457
458 fn is_default_step(_builder: &Builder<'_>) -> bool {
459 false
460 }
461
462 fn make_run(run: RunConfig<'_>) {
463 run.builder.ensure(Self {});
464 }
465
466 fn run(self, builder: &Builder<'_>) {
467 let mut cmd = builder.tool_cmd(Tool::CoverageDump);
468 cmd.args(&builder.config.free_args);
469 cmd.run(builder);
470 }
471}
472
473#[derive(Debug, Clone, PartialEq, Eq, Hash)]
474pub struct Rustfmt;
475
476impl Step for Rustfmt {
477 type Output = ();
478 const IS_HOST: bool = true;
479
480 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
481 run.path("src/tools/rustfmt")
482 }
483
484 fn make_run(run: RunConfig<'_>) {
485 run.builder.ensure(Rustfmt);
486 }
487
488 fn run(self, builder: &Builder<'_>) {
489 let host = builder.build.host_target;
490
491 let stage = if builder.config.is_explicit_stage() || builder.top_stage >= 1 {
494 builder.top_stage
495 } else {
496 1
497 };
498
499 if stage == 0 {
500 eprintln!("rustfmt cannot be run at stage 0");
501 eprintln!("HELP: Use `x fmt` to use stage 0 rustfmt.");
502 std::process::exit(1);
503 }
504
505 let compilers = RustcPrivateCompilers::new(builder, stage, host);
506 let rustfmt_build = builder.ensure(tool::Rustfmt::from_compilers(compilers));
507
508 let mut rustfmt = tool::prepare_tool_cargo(
509 builder,
510 rustfmt_build.build_compiler,
511 Mode::ToolRustcPrivate,
512 host,
513 Kind::Run,
514 "src/tools/rustfmt",
515 SourceType::InTree,
516 &[],
517 );
518
519 rustfmt.args(["--bin", "rustfmt", "--"]);
520 rustfmt.args(builder.config.args());
521
522 rustfmt.into_cmd().run(builder);
523 }
524}
525
526pub fn get_help_path(builder: &Builder<'_>) -> PathBuf {
528 builder.src.join("src/etc/xhelp")
529}
530
531#[derive(Debug, Clone, PartialEq, Eq, Hash)]
532pub struct GenerateHelp;
533
534impl Step for GenerateHelp {
535 type Output = ();
536
537 fn run(self, builder: &Builder<'_>) {
538 let help = top_level_help();
539 let path = get_help_path(builder);
540 std::fs::write(&path, help)
541 .unwrap_or_else(|e| panic!("writing help into {} failed: {e:?}", path.display()));
542 }
543
544 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
545 run.alias("generate-help")
546 }
547
548 fn make_run(run: RunConfig<'_>) {
549 run.builder.ensure(GenerateHelp)
550 }
551}