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