]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/dist.rs
Rollup merge of #68050 - Centril:canon-error, r=Mark-Simulacrum
[rust.git] / src / bootstrap / dist.rs
1 //! Implementation of the various distribution aspects of the compiler.
2 //!
3 //! This module is responsible for creating tarballs of the standard library,
4 //! compiler, and documentation. This ends up being what we distribute to
5 //! everyone as well.
6 //!
7 //! No tarball is actually created literally in this file, but rather we shell
8 //! out to `rust-installer` still. This may one day be replaced with bits and
9 //! pieces of `rustup.rs`!
10
11 use std::env;
12 use std::fs;
13 use std::io::Write;
14 use std::path::{Path, PathBuf};
15 use std::process::{Command, Stdio};
16
17 use build_helper::{output, t};
18
19 use crate::builder::{Builder, RunConfig, ShouldRun, Step};
20 use crate::cache::{Interned, INTERNER};
21 use crate::channel;
22 use crate::compile;
23 use crate::tool::{self, Tool};
24 use crate::util::{exe, is_dylib, timeit};
25 use crate::{Compiler, Mode, LLVM_TOOLS};
26 use time::{self, Timespec};
27
28 pub fn pkgname(builder: &Builder<'_>, component: &str) -> String {
29     if component == "cargo" {
30         format!("{}-{}", component, builder.cargo_package_vers())
31     } else if component == "rls" {
32         format!("{}-{}", component, builder.rls_package_vers())
33     } else if component == "clippy" {
34         format!("{}-{}", component, builder.clippy_package_vers())
35     } else if component == "miri" {
36         format!("{}-{}", component, builder.miri_package_vers())
37     } else if component == "rustfmt" {
38         format!("{}-{}", component, builder.rustfmt_package_vers())
39     } else if component == "llvm-tools" {
40         format!("{}-{}", component, builder.llvm_tools_package_vers())
41     } else if component == "lldb" {
42         format!("{}-{}", component, builder.lldb_package_vers())
43     } else {
44         assert!(component.starts_with("rust"));
45         format!("{}-{}", component, builder.rust_package_vers())
46     }
47 }
48
49 fn distdir(builder: &Builder<'_>) -> PathBuf {
50     builder.out.join("dist")
51 }
52
53 pub fn tmpdir(builder: &Builder<'_>) -> PathBuf {
54     builder.out.join("tmp/dist")
55 }
56
57 fn rust_installer(builder: &Builder<'_>) -> Command {
58     builder.tool_cmd(Tool::RustInstaller)
59 }
60
61 fn missing_tool(tool_name: &str, skip: bool) {
62     if skip {
63         println!("Unable to build {}, skipping dist", tool_name)
64     } else {
65         panic!("Unable to build {}", tool_name)
66     }
67 }
68
69 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
70 pub struct Docs {
71     pub host: Interned<String>,
72 }
73
74 impl Step for Docs {
75     type Output = PathBuf;
76     const DEFAULT: bool = true;
77
78     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
79         run.path("src/doc")
80     }
81
82     fn make_run(run: RunConfig<'_>) {
83         run.builder.ensure(Docs { host: run.target });
84     }
85
86     /// Builds the `rust-docs` installer component.
87     fn run(self, builder: &Builder<'_>) -> PathBuf {
88         let host = self.host;
89
90         let name = pkgname(builder, "rust-docs");
91
92         if !builder.config.docs {
93             return distdir(builder).join(format!("{}-{}.tar.gz", name, host));
94         }
95
96         builder.default_doc(None);
97
98         builder.info(&format!("Dist docs ({})", host));
99         let _time = timeit(builder);
100
101         let image = tmpdir(builder).join(format!("{}-{}-image", name, host));
102         let _ = fs::remove_dir_all(&image);
103
104         let dst = image.join("share/doc/rust/html");
105         t!(fs::create_dir_all(&dst));
106         let src = builder.doc_out(host);
107         builder.cp_r(&src, &dst);
108
109         let mut cmd = rust_installer(builder);
110         cmd.arg("generate")
111             .arg("--product-name=Rust-Documentation")
112             .arg("--rel-manifest-dir=rustlib")
113             .arg("--success-message=Rust-documentation-is-installed.")
114             .arg("--image-dir")
115             .arg(&image)
116             .arg("--work-dir")
117             .arg(&tmpdir(builder))
118             .arg("--output-dir")
119             .arg(&distdir(builder))
120             .arg(format!("--package-name={}-{}", name, host))
121             .arg("--component-name=rust-docs")
122             .arg("--legacy-manifest-dirs=rustlib,cargo")
123             .arg("--bulk-dirs=share/doc/rust/html");
124         builder.run(&mut cmd);
125         builder.remove_dir(&image);
126
127         distdir(builder).join(format!("{}-{}.tar.gz", name, host))
128     }
129 }
130
131 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
132 pub struct RustcDocs {
133     pub host: Interned<String>,
134 }
135
136 impl Step for RustcDocs {
137     type Output = PathBuf;
138     const DEFAULT: bool = true;
139
140     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
141         run.path("src/librustc")
142     }
143
144     fn make_run(run: RunConfig<'_>) {
145         run.builder.ensure(RustcDocs { host: run.target });
146     }
147
148     /// Builds the `rustc-docs` installer component.
149     fn run(self, builder: &Builder<'_>) -> PathBuf {
150         let host = self.host;
151
152         let name = pkgname(builder, "rustc-docs");
153
154         if !builder.config.compiler_docs {
155             return distdir(builder).join(format!("{}-{}.tar.gz", name, host));
156         }
157
158         builder.default_doc(None);
159
160         let image = tmpdir(builder).join(format!("{}-{}-image", name, host));
161         let _ = fs::remove_dir_all(&image);
162
163         let dst = image.join("share/doc/rust/html");
164         t!(fs::create_dir_all(&dst));
165         let src = builder.compiler_doc_out(host);
166         builder.cp_r(&src, &dst);
167
168         let mut cmd = rust_installer(builder);
169         cmd.arg("generate")
170             .arg("--product-name=Rustc-Documentation")
171             .arg("--rel-manifest-dir=rustlib")
172             .arg("--success-message=Rustc-documentation-is-installed.")
173             .arg("--image-dir")
174             .arg(&image)
175             .arg("--work-dir")
176             .arg(&tmpdir(builder))
177             .arg("--output-dir")
178             .arg(&distdir(builder))
179             .arg(format!("--package-name={}-{}", name, host))
180             .arg("--component-name=rustc-docs")
181             .arg("--legacy-manifest-dirs=rustlib,cargo")
182             .arg("--bulk-dirs=share/doc/rust/html");
183
184         builder.info(&format!("Dist compiler docs ({})", host));
185         let _time = timeit(builder);
186         builder.run(&mut cmd);
187         builder.remove_dir(&image);
188
189         distdir(builder).join(format!("{}-{}.tar.gz", name, host))
190     }
191 }
192
193 fn find_files(files: &[&str], path: &[PathBuf]) -> Vec<PathBuf> {
194     let mut found = Vec::with_capacity(files.len());
195
196     for file in files {
197         let file_path = path.iter().map(|dir| dir.join(file)).find(|p| p.exists());
198
199         if let Some(file_path) = file_path {
200             found.push(file_path);
201         } else {
202             panic!("Could not find '{}' in {:?}", file, path);
203         }
204     }
205
206     found
207 }
208
209 fn make_win_dist(
210     rust_root: &Path,
211     plat_root: &Path,
212     target_triple: Interned<String>,
213     builder: &Builder<'_>,
214 ) {
215     //Ask gcc where it keeps its stuff
216     let mut cmd = Command::new(builder.cc(target_triple));
217     cmd.arg("-print-search-dirs");
218     let gcc_out = output(&mut cmd);
219
220     let mut bin_path: Vec<_> = env::split_paths(&env::var_os("PATH").unwrap_or_default()).collect();
221     let mut lib_path = Vec::new();
222
223     for line in gcc_out.lines() {
224         let idx = line.find(':').unwrap();
225         let key = &line[..idx];
226         let trim_chars: &[_] = &[' ', '='];
227         let value = line[(idx + 1)..].trim_start_matches(trim_chars).split(';').map(PathBuf::from);
228
229         if key == "programs" {
230             bin_path.extend(value);
231         } else if key == "libraries" {
232             lib_path.extend(value);
233         }
234     }
235
236     let target_tools = ["gcc.exe", "ld.exe", "dlltool.exe", "libwinpthread-1.dll"];
237     let mut rustc_dlls = vec!["libwinpthread-1.dll"];
238     if target_triple.starts_with("i686-") {
239         rustc_dlls.push("libgcc_s_dw2-1.dll");
240     } else {
241         rustc_dlls.push("libgcc_s_seh-1.dll");
242     }
243
244     let target_libs = [
245         //MinGW libs
246         "libgcc.a",
247         "libgcc_eh.a",
248         "libgcc_s.a",
249         "libm.a",
250         "libmingw32.a",
251         "libmingwex.a",
252         "libstdc++.a",
253         "libiconv.a",
254         "libmoldname.a",
255         "libpthread.a",
256         //Windows import libs
257         "libadvapi32.a",
258         "libbcrypt.a",
259         "libcomctl32.a",
260         "libcomdlg32.a",
261         "libcredui.a",
262         "libcrypt32.a",
263         "libdbghelp.a",
264         "libgdi32.a",
265         "libimagehlp.a",
266         "libiphlpapi.a",
267         "libkernel32.a",
268         "libmsimg32.a",
269         "libmsvcrt.a",
270         "libodbc32.a",
271         "libole32.a",
272         "liboleaut32.a",
273         "libopengl32.a",
274         "libpsapi.a",
275         "librpcrt4.a",
276         "libsecur32.a",
277         "libsetupapi.a",
278         "libshell32.a",
279         "libsynchronization.a",
280         "libuser32.a",
281         "libuserenv.a",
282         "libuuid.a",
283         "libwinhttp.a",
284         "libwinmm.a",
285         "libwinspool.a",
286         "libws2_32.a",
287         "libwsock32.a",
288     ];
289
290     //Find mingw artifacts we want to bundle
291     let target_tools = find_files(&target_tools, &bin_path);
292     let rustc_dlls = find_files(&rustc_dlls, &bin_path);
293     let target_libs = find_files(&target_libs, &lib_path);
294
295     // Copy runtime dlls next to rustc.exe
296     let dist_bin_dir = rust_root.join("bin/");
297     fs::create_dir_all(&dist_bin_dir).expect("creating dist_bin_dir failed");
298     for src in rustc_dlls {
299         builder.copy_to_folder(&src, &dist_bin_dir);
300     }
301
302     //Copy platform tools to platform-specific bin directory
303     let target_bin_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("bin");
304     fs::create_dir_all(&target_bin_dir).expect("creating target_bin_dir failed");
305     for src in target_tools {
306         builder.copy_to_folder(&src, &target_bin_dir);
307     }
308
309     // Warn windows-gnu users that the bundled GCC cannot compile C files
310     builder.create(
311         &target_bin_dir.join("GCC-WARNING.txt"),
312         "gcc.exe contained in this folder cannot be used for compiling C files - it is only\
313          used as a linker. In order to be able to compile projects containing C code use\
314          the GCC provided by MinGW or Cygwin.",
315     );
316
317     //Copy platform libs to platform-specific lib directory
318     let target_lib_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("lib");
319     fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed");
320     for src in target_libs {
321         builder.copy_to_folder(&src, &target_lib_dir);
322     }
323 }
324
325 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
326 pub struct Mingw {
327     pub host: Interned<String>,
328 }
329
330 impl Step for Mingw {
331     type Output = Option<PathBuf>;
332     const DEFAULT: bool = true;
333
334     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
335         run.never()
336     }
337
338     fn make_run(run: RunConfig<'_>) {
339         run.builder.ensure(Mingw { host: run.target });
340     }
341
342     /// Builds the `rust-mingw` installer component.
343     ///
344     /// This contains all the bits and pieces to run the MinGW Windows targets
345     /// without any extra installed software (e.g., we bundle gcc, libraries, etc).
346     fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
347         let host = self.host;
348
349         if !host.contains("pc-windows-gnu") {
350             return None;
351         }
352
353         builder.info(&format!("Dist mingw ({})", host));
354         let _time = timeit(builder);
355         let name = pkgname(builder, "rust-mingw");
356         let image = tmpdir(builder).join(format!("{}-{}-image", name, host));
357         let _ = fs::remove_dir_all(&image);
358         t!(fs::create_dir_all(&image));
359
360         // The first argument is a "temporary directory" which is just
361         // thrown away (this contains the runtime DLLs included in the rustc package
362         // above) and the second argument is where to place all the MinGW components
363         // (which is what we want).
364         make_win_dist(&tmpdir(builder), &image, host, &builder);
365
366         let mut cmd = rust_installer(builder);
367         cmd.arg("generate")
368             .arg("--product-name=Rust-MinGW")
369             .arg("--rel-manifest-dir=rustlib")
370             .arg("--success-message=Rust-MinGW-is-installed.")
371             .arg("--image-dir")
372             .arg(&image)
373             .arg("--work-dir")
374             .arg(&tmpdir(builder))
375             .arg("--output-dir")
376             .arg(&distdir(builder))
377             .arg(format!("--package-name={}-{}", name, host))
378             .arg("--component-name=rust-mingw")
379             .arg("--legacy-manifest-dirs=rustlib,cargo");
380         builder.run(&mut cmd);
381         t!(fs::remove_dir_all(&image));
382         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, host)))
383     }
384 }
385
386 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
387 pub struct Rustc {
388     pub compiler: Compiler,
389 }
390
391 impl Step for Rustc {
392     type Output = PathBuf;
393     const DEFAULT: bool = true;
394     const ONLY_HOSTS: bool = true;
395
396     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
397         run.path("src/librustc")
398     }
399
400     fn make_run(run: RunConfig<'_>) {
401         run.builder
402             .ensure(Rustc { compiler: run.builder.compiler(run.builder.top_stage, run.target) });
403     }
404
405     /// Creates the `rustc` installer component.
406     fn run(self, builder: &Builder<'_>) -> PathBuf {
407         let compiler = self.compiler;
408         let host = self.compiler.host;
409
410         let name = pkgname(builder, "rustc");
411         let image = tmpdir(builder).join(format!("{}-{}-image", name, host));
412         let _ = fs::remove_dir_all(&image);
413         let overlay = tmpdir(builder).join(format!("{}-{}-overlay", name, host));
414         let _ = fs::remove_dir_all(&overlay);
415
416         // Prepare the rustc "image", what will actually end up getting installed
417         prepare_image(builder, compiler, &image);
418
419         // Prepare the overlay which is part of the tarball but won't actually be
420         // installed
421         let cp = |file: &str| {
422             builder.install(&builder.src.join(file), &overlay, 0o644);
423         };
424         cp("COPYRIGHT");
425         cp("LICENSE-APACHE");
426         cp("LICENSE-MIT");
427         cp("README.md");
428         // tiny morsel of metadata is used by rust-packaging
429         let version = builder.rust_version();
430         builder.create(&overlay.join("version"), &version);
431         if let Some(sha) = builder.rust_sha() {
432             builder.create(&overlay.join("git-commit-hash"), &sha);
433         }
434
435         // On MinGW we've got a few runtime DLL dependencies that we need to
436         // include. The first argument to this script is where to put these DLLs
437         // (the image we're creating), and the second argument is a junk directory
438         // to ignore all other MinGW stuff the script creates.
439         //
440         // On 32-bit MinGW we're always including a DLL which needs some extra
441         // licenses to distribute. On 64-bit MinGW we don't actually distribute
442         // anything requiring us to distribute a license, but it's likely the
443         // install will *also* include the rust-mingw package, which also needs
444         // licenses, so to be safe we just include it here in all MinGW packages.
445         if host.contains("pc-windows-gnu") {
446             make_win_dist(&image, &tmpdir(builder), host, builder);
447
448             let dst = image.join("share/doc");
449             t!(fs::create_dir_all(&dst));
450             builder.cp_r(&builder.src.join("src/etc/third-party"), &dst);
451         }
452
453         // Finally, wrap everything up in a nice tarball!
454         let mut cmd = rust_installer(builder);
455         cmd.arg("generate")
456             .arg("--product-name=Rust")
457             .arg("--rel-manifest-dir=rustlib")
458             .arg("--success-message=Rust-is-ready-to-roll.")
459             .arg("--image-dir")
460             .arg(&image)
461             .arg("--work-dir")
462             .arg(&tmpdir(builder))
463             .arg("--output-dir")
464             .arg(&distdir(builder))
465             .arg("--non-installed-overlay")
466             .arg(&overlay)
467             .arg(format!("--package-name={}-{}", name, host))
468             .arg("--component-name=rustc")
469             .arg("--legacy-manifest-dirs=rustlib,cargo");
470
471         builder.info(&format!("Dist rustc stage{} ({})", compiler.stage, host));
472         let _time = timeit(builder);
473         builder.run(&mut cmd);
474         builder.remove_dir(&image);
475         builder.remove_dir(&overlay);
476
477         return distdir(builder).join(format!("{}-{}.tar.gz", name, host));
478
479         fn prepare_image(builder: &Builder<'_>, compiler: Compiler, image: &Path) {
480             let host = compiler.host;
481             let src = builder.sysroot(compiler);
482
483             // Copy rustc/rustdoc binaries
484             t!(fs::create_dir_all(image.join("bin")));
485             builder.cp_r(&src.join("bin"), &image.join("bin"));
486
487             builder.install(&builder.rustdoc(compiler), &image.join("bin"), 0o755);
488
489             let libdir_relative = builder.libdir_relative(compiler);
490
491             // Copy runtime DLLs needed by the compiler
492             if libdir_relative.to_str() != Some("bin") {
493                 let libdir = builder.rustc_libdir(compiler);
494                 for entry in builder.read_dir(&libdir) {
495                     let name = entry.file_name();
496                     if let Some(s) = name.to_str() {
497                         if is_dylib(s) {
498                             // Don't use custom libdir here because ^lib/ will be resolved again
499                             // with installer
500                             builder.install(&entry.path(), &image.join("lib"), 0o644);
501                         }
502                     }
503                 }
504             }
505
506             // Copy libLLVM.so to the lib dir as well, if needed. While not
507             // technically needed by rustc itself it's needed by lots of other
508             // components like the llvm tools and LLD. LLD is included below and
509             // tools/LLDB come later, so let's just throw it in the rustc
510             // component for now.
511             maybe_install_llvm_dylib(builder, host, image);
512
513             // Copy over lld if it's there
514             if builder.config.lld_enabled {
515                 let exe = exe("rust-lld", &compiler.host);
516                 let src =
517                     builder.sysroot_libdir(compiler, host).parent().unwrap().join("bin").join(&exe);
518                 // for the rationale about this rename check `compile::copy_lld_to_sysroot`
519                 let dst = image.join("lib/rustlib").join(&*host).join("bin").join(&exe);
520                 t!(fs::create_dir_all(&dst.parent().unwrap()));
521                 builder.copy(&src, &dst);
522             }
523
524             // Man pages
525             t!(fs::create_dir_all(image.join("share/man/man1")));
526             let man_src = builder.src.join("src/doc/man");
527             let man_dst = image.join("share/man/man1");
528
529             // Reproducible builds: If SOURCE_DATE_EPOCH is set, use that as the time.
530             let time = env::var("SOURCE_DATE_EPOCH")
531                 .map(|timestamp| {
532                     let epoch = timestamp
533                         .parse()
534                         .map_err(|err| format!("could not parse SOURCE_DATE_EPOCH: {}", err))
535                         .unwrap();
536
537                     time::at(Timespec::new(epoch, 0))
538                 })
539                 .unwrap_or_else(|_| time::now());
540
541             let month_year = t!(time::strftime("%B %Y", &time));
542             // don't use our `bootstrap::util::{copy, cp_r}`, because those try
543             // to hardlink, and we don't want to edit the source templates
544             for file_entry in builder.read_dir(&man_src) {
545                 let page_src = file_entry.path();
546                 let page_dst = man_dst.join(file_entry.file_name());
547                 t!(fs::copy(&page_src, &page_dst));
548                 // template in month/year and version number
549                 builder.replace_in_file(
550                     &page_dst,
551                     &[
552                         ("<INSERT DATE HERE>", &month_year),
553                         ("<INSERT VERSION HERE>", channel::CFG_RELEASE_NUM),
554                     ],
555                 );
556             }
557
558             // Debugger scripts
559             builder
560                 .ensure(DebuggerScripts { sysroot: INTERNER.intern_path(image.to_owned()), host });
561
562             // Misc license info
563             let cp = |file: &str| {
564                 builder.install(&builder.src.join(file), &image.join("share/doc/rust"), 0o644);
565             };
566             cp("COPYRIGHT");
567             cp("LICENSE-APACHE");
568             cp("LICENSE-MIT");
569             cp("README.md");
570         }
571     }
572 }
573
574 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
575 pub struct DebuggerScripts {
576     pub sysroot: Interned<PathBuf>,
577     pub host: Interned<String>,
578 }
579
580 impl Step for DebuggerScripts {
581     type Output = ();
582
583     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
584         run.path("src/lldb_batchmode.py")
585     }
586
587     fn make_run(run: RunConfig<'_>) {
588         run.builder.ensure(DebuggerScripts {
589             sysroot: run.builder.sysroot(run.builder.compiler(run.builder.top_stage, run.host)),
590             host: run.target,
591         });
592     }
593
594     /// Copies debugger scripts for `target` into the `sysroot` specified.
595     fn run(self, builder: &Builder<'_>) {
596         let host = self.host;
597         let sysroot = self.sysroot;
598         let dst = sysroot.join("lib/rustlib/etc");
599         t!(fs::create_dir_all(&dst));
600         let cp_debugger_script = |file: &str| {
601             builder.install(&builder.src.join("src/etc/").join(file), &dst, 0o644);
602         };
603         if host.contains("windows-msvc") {
604             // windbg debugger scripts
605             builder.install(
606                 &builder.src.join("src/etc/rust-windbg.cmd"),
607                 &sysroot.join("bin"),
608                 0o755,
609             );
610
611             cp_debugger_script("natvis/intrinsic.natvis");
612             cp_debugger_script("natvis/liballoc.natvis");
613             cp_debugger_script("natvis/libcore.natvis");
614             cp_debugger_script("natvis/libstd.natvis");
615         } else {
616             cp_debugger_script("debugger_pretty_printers_common.py");
617
618             // gdb debugger scripts
619             builder.install(&builder.src.join("src/etc/rust-gdb"), &sysroot.join("bin"), 0o755);
620             builder.install(&builder.src.join("src/etc/rust-gdbgui"), &sysroot.join("bin"), 0o755);
621
622             cp_debugger_script("gdb_load_rust_pretty_printers.py");
623             cp_debugger_script("gdb_rust_pretty_printing.py");
624
625             // lldb debugger scripts
626             builder.install(&builder.src.join("src/etc/rust-lldb"), &sysroot.join("bin"), 0o755);
627
628             cp_debugger_script("lldb_rust_formatters.py");
629         }
630     }
631 }
632
633 fn skip_host_target_lib(builder: &Builder<'_>, compiler: Compiler) -> bool {
634     // The only true set of target libraries came from the build triple, so
635     // let's reduce redundant work by only producing archives from that host.
636     if compiler.host != builder.config.build {
637         builder.info("\tskipping, not a build host");
638         true
639     } else {
640         false
641     }
642 }
643
644 /// Copy stamped files into an image's `target/lib` directory.
645 fn copy_target_libs(builder: &Builder<'_>, target: &str, image: &Path, stamp: &Path) {
646     let dst = image.join("lib/rustlib").join(target).join("lib");
647     t!(fs::create_dir_all(&dst));
648     for (path, host) in builder.read_stamp_file(stamp) {
649         if !host || builder.config.build == target {
650             builder.copy(&path, &dst.join(path.file_name().unwrap()));
651         }
652     }
653 }
654
655 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
656 pub struct Std {
657     pub compiler: Compiler,
658     pub target: Interned<String>,
659 }
660
661 impl Step for Std {
662     type Output = PathBuf;
663     const DEFAULT: bool = true;
664
665     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
666         run.path("src/libstd")
667     }
668
669     fn make_run(run: RunConfig<'_>) {
670         run.builder.ensure(Std {
671             compiler: run.builder.compiler_for(
672                 run.builder.top_stage,
673                 run.builder.config.build,
674                 run.target,
675             ),
676             target: run.target,
677         });
678     }
679
680     fn run(self, builder: &Builder<'_>) -> PathBuf {
681         let compiler = self.compiler;
682         let target = self.target;
683
684         let name = pkgname(builder, "rust-std");
685         let archive = distdir(builder).join(format!("{}-{}.tar.gz", name, target));
686         if skip_host_target_lib(builder, compiler) {
687             return archive;
688         }
689
690         builder.ensure(compile::Std { compiler, target });
691
692         let image = tmpdir(builder).join(format!("{}-{}-image", name, target));
693         let _ = fs::remove_dir_all(&image);
694
695         let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
696         let stamp = compile::libstd_stamp(builder, compiler_to_use, target);
697         copy_target_libs(builder, &target, &image, &stamp);
698
699         let mut cmd = rust_installer(builder);
700         cmd.arg("generate")
701             .arg("--product-name=Rust")
702             .arg("--rel-manifest-dir=rustlib")
703             .arg("--success-message=std-is-standing-at-the-ready.")
704             .arg("--image-dir")
705             .arg(&image)
706             .arg("--work-dir")
707             .arg(&tmpdir(builder))
708             .arg("--output-dir")
709             .arg(&distdir(builder))
710             .arg(format!("--package-name={}-{}", name, target))
711             .arg(format!("--component-name=rust-std-{}", target))
712             .arg("--legacy-manifest-dirs=rustlib,cargo");
713
714         builder
715             .info(&format!("Dist std stage{} ({} -> {})", compiler.stage, &compiler.host, target));
716         let _time = timeit(builder);
717         builder.run(&mut cmd);
718         builder.remove_dir(&image);
719         archive
720     }
721 }
722
723 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
724 pub struct RustcDev {
725     pub compiler: Compiler,
726     pub target: Interned<String>,
727 }
728
729 impl Step for RustcDev {
730     type Output = PathBuf;
731     const DEFAULT: bool = true;
732     const ONLY_HOSTS: bool = true;
733
734     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
735         run.path("rustc-dev")
736     }
737
738     fn make_run(run: RunConfig<'_>) {
739         run.builder.ensure(RustcDev {
740             compiler: run.builder.compiler_for(
741                 run.builder.top_stage,
742                 run.builder.config.build,
743                 run.target,
744             ),
745             target: run.target,
746         });
747     }
748
749     fn run(self, builder: &Builder<'_>) -> PathBuf {
750         let compiler = self.compiler;
751         let target = self.target;
752
753         let name = pkgname(builder, "rustc-dev");
754         let archive = distdir(builder).join(format!("{}-{}.tar.gz", name, target));
755         if skip_host_target_lib(builder, compiler) {
756             return archive;
757         }
758
759         builder.ensure(compile::Rustc { compiler, target });
760
761         let image = tmpdir(builder).join(format!("{}-{}-image", name, target));
762         let _ = fs::remove_dir_all(&image);
763
764         let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
765         let stamp = compile::librustc_stamp(builder, compiler_to_use, target);
766         copy_target_libs(builder, &target, &image, &stamp);
767
768         let mut cmd = rust_installer(builder);
769         cmd.arg("generate")
770             .arg("--product-name=Rust")
771             .arg("--rel-manifest-dir=rustlib")
772             .arg("--success-message=Rust-is-ready-to-develop.")
773             .arg("--image-dir")
774             .arg(&image)
775             .arg("--work-dir")
776             .arg(&tmpdir(builder))
777             .arg("--output-dir")
778             .arg(&distdir(builder))
779             .arg(format!("--package-name={}-{}", name, target))
780             .arg(format!("--component-name=rustc-dev-{}", target))
781             .arg("--legacy-manifest-dirs=rustlib,cargo");
782
783         builder.info(&format!(
784             "Dist rustc-dev stage{} ({} -> {})",
785             compiler.stage, &compiler.host, target
786         ));
787         let _time = timeit(builder);
788         builder.run(&mut cmd);
789         builder.remove_dir(&image);
790         archive
791     }
792 }
793
794 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
795 pub struct Analysis {
796     pub compiler: Compiler,
797     pub target: Interned<String>,
798 }
799
800 impl Step for Analysis {
801     type Output = PathBuf;
802     const DEFAULT: bool = true;
803
804     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
805         let builder = run.builder;
806         run.path("analysis").default_condition(builder.config.extended)
807     }
808
809     fn make_run(run: RunConfig<'_>) {
810         run.builder.ensure(Analysis {
811             // Find the actual compiler (handling the full bootstrap option) which
812             // produced the save-analysis data because that data isn't copied
813             // through the sysroot uplifting.
814             compiler: run.builder.compiler_for(
815                 run.builder.top_stage,
816                 run.builder.config.build,
817                 run.target,
818             ),
819             target: run.target,
820         });
821     }
822
823     /// Creates a tarball of save-analysis metadata, if available.
824     fn run(self, builder: &Builder<'_>) -> PathBuf {
825         let compiler = self.compiler;
826         let target = self.target;
827         assert!(builder.config.extended);
828         let name = pkgname(builder, "rust-analysis");
829
830         if &compiler.host != builder.config.build {
831             return distdir(builder).join(format!("{}-{}.tar.gz", name, target));
832         }
833
834         builder.ensure(compile::Std { compiler, target });
835
836         let image = tmpdir(builder).join(format!("{}-{}-image", name, target));
837
838         let src = builder
839             .stage_out(compiler, Mode::Std)
840             .join(target)
841             .join(builder.cargo_dir())
842             .join("deps");
843
844         let image_src = src.join("save-analysis");
845         let dst = image.join("lib/rustlib").join(target).join("analysis");
846         t!(fs::create_dir_all(&dst));
847         builder.info(&format!("image_src: {:?}, dst: {:?}", image_src, dst));
848         builder.cp_r(&image_src, &dst);
849
850         let mut cmd = rust_installer(builder);
851         cmd.arg("generate")
852             .arg("--product-name=Rust")
853             .arg("--rel-manifest-dir=rustlib")
854             .arg("--success-message=save-analysis-saved.")
855             .arg("--image-dir")
856             .arg(&image)
857             .arg("--work-dir")
858             .arg(&tmpdir(builder))
859             .arg("--output-dir")
860             .arg(&distdir(builder))
861             .arg(format!("--package-name={}-{}", name, target))
862             .arg(format!("--component-name=rust-analysis-{}", target))
863             .arg("--legacy-manifest-dirs=rustlib,cargo");
864
865         builder.info("Dist analysis");
866         let _time = timeit(builder);
867         builder.run(&mut cmd);
868         builder.remove_dir(&image);
869         distdir(builder).join(format!("{}-{}.tar.gz", name, target))
870     }
871 }
872
873 fn copy_src_dirs(builder: &Builder<'_>, src_dirs: &[&str], exclude_dirs: &[&str], dst_dir: &Path) {
874     fn filter_fn(exclude_dirs: &[&str], dir: &str, path: &Path) -> bool {
875         let spath = match path.to_str() {
876             Some(path) => path,
877             None => return false,
878         };
879         if spath.ends_with("~") || spath.ends_with(".pyc") {
880             return false;
881         }
882
883         const LLVM_PROJECTS: &[&str] = &[
884             "llvm-project/clang",
885             "llvm-project\\clang",
886             "llvm-project/libunwind",
887             "llvm-project\\libunwind",
888             "llvm-project/lld",
889             "llvm-project\\lld",
890             "llvm-project/lldb",
891             "llvm-project\\lldb",
892             "llvm-project/llvm",
893             "llvm-project\\llvm",
894             "llvm-project/compiler-rt",
895             "llvm-project\\compiler-rt",
896         ];
897         if spath.contains("llvm-project")
898             && !spath.ends_with("llvm-project")
899             && !LLVM_PROJECTS.iter().any(|path| spath.contains(path))
900         {
901             return false;
902         }
903
904         const LLVM_TEST: &[&str] = &["llvm-project/llvm/test", "llvm-project\\llvm\\test"];
905         if LLVM_TEST.iter().any(|path| spath.contains(path))
906             && (spath.ends_with(".ll") || spath.ends_with(".td") || spath.ends_with(".s"))
907         {
908             return false;
909         }
910
911         let full_path = Path::new(dir).join(path);
912         if exclude_dirs.iter().any(|excl| full_path == Path::new(excl)) {
913             return false;
914         }
915
916         let excludes = [
917             "CVS",
918             "RCS",
919             "SCCS",
920             ".git",
921             ".gitignore",
922             ".gitmodules",
923             ".gitattributes",
924             ".cvsignore",
925             ".svn",
926             ".arch-ids",
927             "{arch}",
928             "=RELEASE-ID",
929             "=meta-update",
930             "=update",
931             ".bzr",
932             ".bzrignore",
933             ".bzrtags",
934             ".hg",
935             ".hgignore",
936             ".hgrags",
937             "_darcs",
938         ];
939         !path.iter().map(|s| s.to_str().unwrap()).any(|s| excludes.contains(&s))
940     }
941
942     // Copy the directories using our filter
943     for item in src_dirs {
944         let dst = &dst_dir.join(item);
945         t!(fs::create_dir_all(dst));
946         builder
947             .cp_filtered(&builder.src.join(item), dst, &|path| filter_fn(exclude_dirs, item, path));
948     }
949 }
950
951 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
952 pub struct Src;
953
954 impl Step for Src {
955     /// The output path of the src installer tarball
956     type Output = PathBuf;
957     const DEFAULT: bool = true;
958     const ONLY_HOSTS: bool = true;
959
960     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
961         run.path("src")
962     }
963
964     fn make_run(run: RunConfig<'_>) {
965         run.builder.ensure(Src);
966     }
967
968     /// Creates the `rust-src` installer component
969     fn run(self, builder: &Builder<'_>) -> PathBuf {
970         let name = pkgname(builder, "rust-src");
971         let image = tmpdir(builder).join(format!("{}-image", name));
972         let _ = fs::remove_dir_all(&image);
973
974         let dst = image.join("lib/rustlib/src");
975         let dst_src = dst.join("rust");
976         t!(fs::create_dir_all(&dst_src));
977
978         let src_files = ["Cargo.lock"];
979         // This is the reduced set of paths which will become the rust-src component
980         // (essentially libstd and all of its path dependencies)
981         let std_src_dirs = [
982             "src/build_helper",
983             "src/liballoc",
984             "src/libcore",
985             "src/libpanic_abort",
986             "src/libpanic_unwind",
987             "src/librustc_asan",
988             "src/librustc_lsan",
989             "src/librustc_msan",
990             "src/librustc_tsan",
991             "src/libstd",
992             "src/libunwind",
993             "src/libtest",
994             "src/libterm",
995             "src/libprofiler_builtins",
996             "src/stdarch",
997             "src/libproc_macro",
998             "src/tools/rustc-std-workspace-core",
999             "src/tools/rustc-std-workspace-alloc",
1000             "src/tools/rustc-std-workspace-std",
1001             "src/librustc",
1002             "src/libsyntax",
1003         ];
1004
1005         copy_src_dirs(builder, &std_src_dirs[..], &[], &dst_src);
1006         for file in src_files.iter() {
1007             builder.copy(&builder.src.join(file), &dst_src.join(file));
1008         }
1009
1010         // Create source tarball in rust-installer format
1011         let mut cmd = rust_installer(builder);
1012         cmd.arg("generate")
1013             .arg("--product-name=Rust")
1014             .arg("--rel-manifest-dir=rustlib")
1015             .arg("--success-message=Awesome-Source.")
1016             .arg("--image-dir")
1017             .arg(&image)
1018             .arg("--work-dir")
1019             .arg(&tmpdir(builder))
1020             .arg("--output-dir")
1021             .arg(&distdir(builder))
1022             .arg(format!("--package-name={}", name))
1023             .arg("--component-name=rust-src")
1024             .arg("--legacy-manifest-dirs=rustlib,cargo");
1025
1026         builder.info("Dist src");
1027         let _time = timeit(builder);
1028         builder.run(&mut cmd);
1029
1030         builder.remove_dir(&image);
1031         distdir(builder).join(&format!("{}.tar.gz", name))
1032     }
1033 }
1034
1035 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1036 pub struct PlainSourceTarball;
1037
1038 impl Step for PlainSourceTarball {
1039     /// Produces the location of the tarball generated
1040     type Output = PathBuf;
1041     const DEFAULT: bool = true;
1042     const ONLY_HOSTS: bool = true;
1043
1044     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1045         let builder = run.builder;
1046         run.path("src").default_condition(builder.config.rust_dist_src)
1047     }
1048
1049     fn make_run(run: RunConfig<'_>) {
1050         run.builder.ensure(PlainSourceTarball);
1051     }
1052
1053     /// Creates the plain source tarball
1054     fn run(self, builder: &Builder<'_>) -> PathBuf {
1055         // Make sure that the root folder of tarball has the correct name
1056         let plain_name = format!("{}-src", pkgname(builder, "rustc"));
1057         let plain_dst_src = tmpdir(builder).join(&plain_name);
1058         let _ = fs::remove_dir_all(&plain_dst_src);
1059         t!(fs::create_dir_all(&plain_dst_src));
1060
1061         // This is the set of root paths which will become part of the source package
1062         let src_files = [
1063             "COPYRIGHT",
1064             "LICENSE-APACHE",
1065             "LICENSE-MIT",
1066             "CONTRIBUTING.md",
1067             "README.md",
1068             "RELEASES.md",
1069             "configure",
1070             "x.py",
1071             "config.toml.example",
1072             "Cargo.toml",
1073             "Cargo.lock",
1074         ];
1075         let src_dirs = ["src"];
1076
1077         copy_src_dirs(builder, &src_dirs[..], &[], &plain_dst_src);
1078
1079         // Copy the files normally
1080         for item in &src_files {
1081             builder.copy(&builder.src.join(item), &plain_dst_src.join(item));
1082         }
1083
1084         // Create the version file
1085         builder.create(&plain_dst_src.join("version"), &builder.rust_version());
1086         if let Some(sha) = builder.rust_sha() {
1087             builder.create(&plain_dst_src.join("git-commit-hash"), &sha);
1088         }
1089
1090         // If we're building from git sources, we need to vendor a complete distribution.
1091         if builder.rust_info.is_git() {
1092             // Vendor all Cargo dependencies
1093             let mut cmd = Command::new(&builder.initial_cargo);
1094             cmd.arg("vendor").current_dir(&plain_dst_src);
1095             builder.run(&mut cmd);
1096         }
1097
1098         // Create plain source tarball
1099         let plain_name = format!("rustc-{}-src", builder.rust_package_vers());
1100         let mut tarball = distdir(builder).join(&format!("{}.tar.gz", plain_name));
1101         tarball.set_extension(""); // strip .gz
1102         tarball.set_extension(""); // strip .tar
1103         if let Some(dir) = tarball.parent() {
1104             builder.create_dir(&dir);
1105         }
1106         builder.info("running installer");
1107         let mut cmd = rust_installer(builder);
1108         cmd.arg("tarball")
1109             .arg("--input")
1110             .arg(&plain_name)
1111             .arg("--output")
1112             .arg(&tarball)
1113             .arg("--work-dir=.")
1114             .current_dir(tmpdir(builder));
1115
1116         builder.info("Create plain source tarball");
1117         let _time = timeit(builder);
1118         builder.run(&mut cmd);
1119         distdir(builder).join(&format!("{}.tar.gz", plain_name))
1120     }
1121 }
1122
1123 // We have to run a few shell scripts, which choke quite a bit on both `\`
1124 // characters and on `C:\` paths, so normalize both of them away.
1125 pub fn sanitize_sh(path: &Path) -> String {
1126     let path = path.to_str().unwrap().replace("\\", "/");
1127     return change_drive(&path).unwrap_or(path);
1128
1129     fn change_drive(s: &str) -> Option<String> {
1130         let mut ch = s.chars();
1131         let drive = ch.next().unwrap_or('C');
1132         if ch.next() != Some(':') {
1133             return None;
1134         }
1135         if ch.next() != Some('/') {
1136             return None;
1137         }
1138         Some(format!("/{}/{}", drive, &s[drive.len_utf8() + 2..]))
1139     }
1140 }
1141
1142 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1143 pub struct Cargo {
1144     pub compiler: Compiler,
1145     pub target: Interned<String>,
1146 }
1147
1148 impl Step for Cargo {
1149     type Output = PathBuf;
1150     const ONLY_HOSTS: bool = true;
1151
1152     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1153         run.path("cargo")
1154     }
1155
1156     fn make_run(run: RunConfig<'_>) {
1157         run.builder.ensure(Cargo {
1158             compiler: run.builder.compiler_for(
1159                 run.builder.top_stage,
1160                 run.builder.config.build,
1161                 run.target,
1162             ),
1163             target: run.target,
1164         });
1165     }
1166
1167     fn run(self, builder: &Builder<'_>) -> PathBuf {
1168         let compiler = self.compiler;
1169         let target = self.target;
1170
1171         let src = builder.src.join("src/tools/cargo");
1172         let etc = src.join("src/etc");
1173         let release_num = builder.release_num("cargo");
1174         let name = pkgname(builder, "cargo");
1175         let version = builder.cargo_info.version(builder, &release_num);
1176
1177         let tmp = tmpdir(builder);
1178         let image = tmp.join("cargo-image");
1179         drop(fs::remove_dir_all(&image));
1180         builder.create_dir(&image);
1181
1182         // Prepare the image directory
1183         builder.create_dir(&image.join("share/zsh/site-functions"));
1184         builder.create_dir(&image.join("etc/bash_completion.d"));
1185         let cargo = builder.ensure(tool::Cargo { compiler, target });
1186         builder.install(&cargo, &image.join("bin"), 0o755);
1187         for man in t!(etc.join("man").read_dir()) {
1188             let man = t!(man);
1189             builder.install(&man.path(), &image.join("share/man/man1"), 0o644);
1190         }
1191         builder.install(&etc.join("_cargo"), &image.join("share/zsh/site-functions"), 0o644);
1192         builder.copy(&etc.join("cargo.bashcomp.sh"), &image.join("etc/bash_completion.d/cargo"));
1193         let doc = image.join("share/doc/cargo");
1194         builder.install(&src.join("README.md"), &doc, 0o644);
1195         builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
1196         builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1197         builder.install(&src.join("LICENSE-THIRD-PARTY"), &doc, 0o644);
1198
1199         // Prepare the overlay
1200         let overlay = tmp.join("cargo-overlay");
1201         drop(fs::remove_dir_all(&overlay));
1202         builder.create_dir(&overlay);
1203         builder.install(&src.join("README.md"), &overlay, 0o644);
1204         builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
1205         builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
1206         builder.install(&src.join("LICENSE-THIRD-PARTY"), &overlay, 0o644);
1207         builder.create(&overlay.join("version"), &version);
1208
1209         // Generate the installer tarball
1210         let mut cmd = rust_installer(builder);
1211         cmd.arg("generate")
1212             .arg("--product-name=Rust")
1213             .arg("--rel-manifest-dir=rustlib")
1214             .arg("--success-message=Rust-is-ready-to-roll.")
1215             .arg("--image-dir")
1216             .arg(&image)
1217             .arg("--work-dir")
1218             .arg(&tmpdir(builder))
1219             .arg("--output-dir")
1220             .arg(&distdir(builder))
1221             .arg("--non-installed-overlay")
1222             .arg(&overlay)
1223             .arg(format!("--package-name={}-{}", name, target))
1224             .arg("--component-name=cargo")
1225             .arg("--legacy-manifest-dirs=rustlib,cargo");
1226
1227         builder.info(&format!("Dist cargo stage{} ({})", compiler.stage, target));
1228         let _time = timeit(builder);
1229         builder.run(&mut cmd);
1230         distdir(builder).join(format!("{}-{}.tar.gz", name, target))
1231     }
1232 }
1233
1234 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1235 pub struct Rls {
1236     pub compiler: Compiler,
1237     pub target: Interned<String>,
1238 }
1239
1240 impl Step for Rls {
1241     type Output = Option<PathBuf>;
1242     const ONLY_HOSTS: bool = true;
1243
1244     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1245         run.path("rls")
1246     }
1247
1248     fn make_run(run: RunConfig<'_>) {
1249         run.builder.ensure(Rls {
1250             compiler: run.builder.compiler_for(
1251                 run.builder.top_stage,
1252                 run.builder.config.build,
1253                 run.target,
1254             ),
1255             target: run.target,
1256         });
1257     }
1258
1259     fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
1260         let compiler = self.compiler;
1261         let target = self.target;
1262         assert!(builder.config.extended);
1263
1264         let src = builder.src.join("src/tools/rls");
1265         let release_num = builder.release_num("rls");
1266         let name = pkgname(builder, "rls");
1267         let version = builder.rls_info.version(builder, &release_num);
1268
1269         let tmp = tmpdir(builder);
1270         let image = tmp.join("rls-image");
1271         drop(fs::remove_dir_all(&image));
1272         t!(fs::create_dir_all(&image));
1273
1274         // Prepare the image directory
1275         // We expect RLS to build, because we've exited this step above if tool
1276         // state for RLS isn't testing.
1277         let rls = builder
1278             .ensure(tool::Rls { compiler, target, extra_features: Vec::new() })
1279             .or_else(|| {
1280                 missing_tool("RLS", builder.build.config.missing_tools);
1281                 None
1282             })?;
1283
1284         builder.install(&rls, &image.join("bin"), 0o755);
1285         let doc = image.join("share/doc/rls");
1286         builder.install(&src.join("README.md"), &doc, 0o644);
1287         builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
1288         builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1289
1290         // Prepare the overlay
1291         let overlay = tmp.join("rls-overlay");
1292         drop(fs::remove_dir_all(&overlay));
1293         t!(fs::create_dir_all(&overlay));
1294         builder.install(&src.join("README.md"), &overlay, 0o644);
1295         builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
1296         builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
1297         builder.create(&overlay.join("version"), &version);
1298
1299         // Generate the installer tarball
1300         let mut cmd = rust_installer(builder);
1301         cmd.arg("generate")
1302             .arg("--product-name=Rust")
1303             .arg("--rel-manifest-dir=rustlib")
1304             .arg("--success-message=RLS-ready-to-serve.")
1305             .arg("--image-dir")
1306             .arg(&image)
1307             .arg("--work-dir")
1308             .arg(&tmpdir(builder))
1309             .arg("--output-dir")
1310             .arg(&distdir(builder))
1311             .arg("--non-installed-overlay")
1312             .arg(&overlay)
1313             .arg(format!("--package-name={}-{}", name, target))
1314             .arg("--legacy-manifest-dirs=rustlib,cargo")
1315             .arg("--component-name=rls-preview");
1316
1317         builder.info(&format!("Dist RLS stage{} ({})", compiler.stage, target));
1318         let _time = timeit(builder);
1319         builder.run(&mut cmd);
1320         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
1321     }
1322 }
1323
1324 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1325 pub struct Clippy {
1326     pub compiler: Compiler,
1327     pub target: Interned<String>,
1328 }
1329
1330 impl Step for Clippy {
1331     type Output = Option<PathBuf>;
1332     const ONLY_HOSTS: bool = true;
1333
1334     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1335         run.path("clippy")
1336     }
1337
1338     fn make_run(run: RunConfig<'_>) {
1339         run.builder.ensure(Clippy {
1340             compiler: run.builder.compiler_for(
1341                 run.builder.top_stage,
1342                 run.builder.config.build,
1343                 run.target,
1344             ),
1345             target: run.target,
1346         });
1347     }
1348
1349     fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
1350         let compiler = self.compiler;
1351         let target = self.target;
1352         assert!(builder.config.extended);
1353
1354         let src = builder.src.join("src/tools/clippy");
1355         let release_num = builder.release_num("clippy");
1356         let name = pkgname(builder, "clippy");
1357         let version = builder.clippy_info.version(builder, &release_num);
1358
1359         let tmp = tmpdir(builder);
1360         let image = tmp.join("clippy-image");
1361         drop(fs::remove_dir_all(&image));
1362         builder.create_dir(&image);
1363
1364         // Prepare the image directory
1365         // We expect clippy to build, because we've exited this step above if tool
1366         // state for clippy isn't testing.
1367         let clippy = builder
1368             .ensure(tool::Clippy { compiler, target, extra_features: Vec::new() })
1369             .or_else(|| {
1370                 missing_tool("clippy", builder.build.config.missing_tools);
1371                 None
1372             })?;
1373         let cargoclippy = builder
1374             .ensure(tool::CargoClippy { compiler, target, extra_features: Vec::new() })
1375             .or_else(|| {
1376                 missing_tool("cargo clippy", builder.build.config.missing_tools);
1377                 None
1378             })?;
1379
1380         builder.install(&clippy, &image.join("bin"), 0o755);
1381         builder.install(&cargoclippy, &image.join("bin"), 0o755);
1382         let doc = image.join("share/doc/clippy");
1383         builder.install(&src.join("README.md"), &doc, 0o644);
1384         builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1385         builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
1386
1387         // Prepare the overlay
1388         let overlay = tmp.join("clippy-overlay");
1389         drop(fs::remove_dir_all(&overlay));
1390         t!(fs::create_dir_all(&overlay));
1391         builder.install(&src.join("README.md"), &overlay, 0o644);
1392         builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1393         builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
1394         builder.create(&overlay.join("version"), &version);
1395
1396         // Generate the installer tarball
1397         let mut cmd = rust_installer(builder);
1398         cmd.arg("generate")
1399             .arg("--product-name=Rust")
1400             .arg("--rel-manifest-dir=rustlib")
1401             .arg("--success-message=clippy-ready-to-serve.")
1402             .arg("--image-dir")
1403             .arg(&image)
1404             .arg("--work-dir")
1405             .arg(&tmpdir(builder))
1406             .arg("--output-dir")
1407             .arg(&distdir(builder))
1408             .arg("--non-installed-overlay")
1409             .arg(&overlay)
1410             .arg(format!("--package-name={}-{}", name, target))
1411             .arg("--legacy-manifest-dirs=rustlib,cargo")
1412             .arg("--component-name=clippy-preview");
1413
1414         builder.info(&format!("Dist clippy stage{} ({})", compiler.stage, target));
1415         let _time = timeit(builder);
1416         builder.run(&mut cmd);
1417         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
1418     }
1419 }
1420
1421 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1422 pub struct Miri {
1423     pub compiler: Compiler,
1424     pub target: Interned<String>,
1425 }
1426
1427 impl Step for Miri {
1428     type Output = Option<PathBuf>;
1429     const ONLY_HOSTS: bool = true;
1430
1431     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1432         run.path("miri")
1433     }
1434
1435     fn make_run(run: RunConfig<'_>) {
1436         run.builder.ensure(Miri {
1437             compiler: run.builder.compiler_for(
1438                 run.builder.top_stage,
1439                 run.builder.config.build,
1440                 run.target,
1441             ),
1442             target: run.target,
1443         });
1444     }
1445
1446     fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
1447         let compiler = self.compiler;
1448         let target = self.target;
1449         assert!(builder.config.extended);
1450
1451         let src = builder.src.join("src/tools/miri");
1452         let release_num = builder.release_num("miri");
1453         let name = pkgname(builder, "miri");
1454         let version = builder.miri_info.version(builder, &release_num);
1455
1456         let tmp = tmpdir(builder);
1457         let image = tmp.join("miri-image");
1458         drop(fs::remove_dir_all(&image));
1459         builder.create_dir(&image);
1460
1461         // Prepare the image directory
1462         // We expect miri to build, because we've exited this step above if tool
1463         // state for miri isn't testing.
1464         let miri = builder
1465             .ensure(tool::Miri { compiler, target, extra_features: Vec::new() })
1466             .or_else(|| {
1467                 missing_tool("miri", builder.build.config.missing_tools);
1468                 None
1469             })?;
1470         let cargomiri = builder
1471             .ensure(tool::CargoMiri { compiler, target, extra_features: Vec::new() })
1472             .or_else(|| {
1473                 missing_tool("cargo miri", builder.build.config.missing_tools);
1474                 None
1475             })?;
1476
1477         builder.install(&miri, &image.join("bin"), 0o755);
1478         builder.install(&cargomiri, &image.join("bin"), 0o755);
1479         let doc = image.join("share/doc/miri");
1480         builder.install(&src.join("README.md"), &doc, 0o644);
1481         builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1482         builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
1483
1484         // Prepare the overlay
1485         let overlay = tmp.join("miri-overlay");
1486         drop(fs::remove_dir_all(&overlay));
1487         t!(fs::create_dir_all(&overlay));
1488         builder.install(&src.join("README.md"), &overlay, 0o644);
1489         builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1490         builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
1491         builder.create(&overlay.join("version"), &version);
1492
1493         // Generate the installer tarball
1494         let mut cmd = rust_installer(builder);
1495         cmd.arg("generate")
1496             .arg("--product-name=Rust")
1497             .arg("--rel-manifest-dir=rustlib")
1498             .arg("--success-message=miri-ready-to-serve.")
1499             .arg("--image-dir")
1500             .arg(&image)
1501             .arg("--work-dir")
1502             .arg(&tmpdir(builder))
1503             .arg("--output-dir")
1504             .arg(&distdir(builder))
1505             .arg("--non-installed-overlay")
1506             .arg(&overlay)
1507             .arg(format!("--package-name={}-{}", name, target))
1508             .arg("--legacy-manifest-dirs=rustlib,cargo")
1509             .arg("--component-name=miri-preview");
1510
1511         builder.info(&format!("Dist miri stage{} ({})", compiler.stage, target));
1512         let _time = timeit(builder);
1513         builder.run(&mut cmd);
1514         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
1515     }
1516 }
1517
1518 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1519 pub struct Rustfmt {
1520     pub compiler: Compiler,
1521     pub target: Interned<String>,
1522 }
1523
1524 impl Step for Rustfmt {
1525     type Output = Option<PathBuf>;
1526     const ONLY_HOSTS: bool = true;
1527
1528     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1529         run.path("rustfmt")
1530     }
1531
1532     fn make_run(run: RunConfig<'_>) {
1533         run.builder.ensure(Rustfmt {
1534             compiler: run.builder.compiler_for(
1535                 run.builder.top_stage,
1536                 run.builder.config.build,
1537                 run.target,
1538             ),
1539             target: run.target,
1540         });
1541     }
1542
1543     fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
1544         let compiler = self.compiler;
1545         let target = self.target;
1546
1547         let src = builder.src.join("src/tools/rustfmt");
1548         let release_num = builder.release_num("rustfmt");
1549         let name = pkgname(builder, "rustfmt");
1550         let version = builder.rustfmt_info.version(builder, &release_num);
1551
1552         let tmp = tmpdir(builder);
1553         let image = tmp.join("rustfmt-image");
1554         drop(fs::remove_dir_all(&image));
1555         builder.create_dir(&image);
1556
1557         // Prepare the image directory
1558         let rustfmt = builder
1559             .ensure(tool::Rustfmt { compiler, target, extra_features: Vec::new() })
1560             .or_else(|| {
1561                 missing_tool("Rustfmt", builder.build.config.missing_tools);
1562                 None
1563             })?;
1564         let cargofmt = builder
1565             .ensure(tool::Cargofmt { compiler, target, extra_features: Vec::new() })
1566             .or_else(|| {
1567                 missing_tool("Cargofmt", builder.build.config.missing_tools);
1568                 None
1569             })?;
1570
1571         builder.install(&rustfmt, &image.join("bin"), 0o755);
1572         builder.install(&cargofmt, &image.join("bin"), 0o755);
1573         let doc = image.join("share/doc/rustfmt");
1574         builder.install(&src.join("README.md"), &doc, 0o644);
1575         builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
1576         builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1577
1578         // Prepare the overlay
1579         let overlay = tmp.join("rustfmt-overlay");
1580         drop(fs::remove_dir_all(&overlay));
1581         builder.create_dir(&overlay);
1582         builder.install(&src.join("README.md"), &overlay, 0o644);
1583         builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
1584         builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
1585         builder.create(&overlay.join("version"), &version);
1586
1587         // Generate the installer tarball
1588         let mut cmd = rust_installer(builder);
1589         cmd.arg("generate")
1590             .arg("--product-name=Rust")
1591             .arg("--rel-manifest-dir=rustlib")
1592             .arg("--success-message=rustfmt-ready-to-fmt.")
1593             .arg("--image-dir")
1594             .arg(&image)
1595             .arg("--work-dir")
1596             .arg(&tmpdir(builder))
1597             .arg("--output-dir")
1598             .arg(&distdir(builder))
1599             .arg("--non-installed-overlay")
1600             .arg(&overlay)
1601             .arg(format!("--package-name={}-{}", name, target))
1602             .arg("--legacy-manifest-dirs=rustlib,cargo")
1603             .arg("--component-name=rustfmt-preview");
1604
1605         builder.info(&format!("Dist Rustfmt stage{} ({})", compiler.stage, target));
1606         let _time = timeit(builder);
1607         builder.run(&mut cmd);
1608         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
1609     }
1610 }
1611
1612 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1613 pub struct Extended {
1614     stage: u32,
1615     host: Interned<String>,
1616     target: Interned<String>,
1617 }
1618
1619 impl Step for Extended {
1620     type Output = ();
1621     const DEFAULT: bool = true;
1622     const ONLY_HOSTS: bool = true;
1623
1624     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1625         let builder = run.builder;
1626         run.path("extended").default_condition(builder.config.extended)
1627     }
1628
1629     fn make_run(run: RunConfig<'_>) {
1630         run.builder.ensure(Extended {
1631             stage: run.builder.top_stage,
1632             host: run.builder.config.build,
1633             target: run.target,
1634         });
1635     }
1636
1637     /// Creates a combined installer for the specified target in the provided stage.
1638     fn run(self, builder: &Builder<'_>) {
1639         let target = self.target;
1640         let stage = self.stage;
1641         let compiler = builder.compiler_for(self.stage, self.host, self.target);
1642
1643         builder.info(&format!("Dist extended stage{} ({})", compiler.stage, target));
1644
1645         let rustc_installer = builder.ensure(Rustc { compiler: builder.compiler(stage, target) });
1646         let cargo_installer = builder.ensure(Cargo { compiler, target });
1647         let rustfmt_installer = builder.ensure(Rustfmt { compiler, target });
1648         let rls_installer = builder.ensure(Rls { compiler, target });
1649         let llvm_tools_installer = builder.ensure(LlvmTools { target });
1650         let clippy_installer = builder.ensure(Clippy { compiler, target });
1651         let miri_installer = builder.ensure(Miri { compiler, target });
1652         let lldb_installer = builder.ensure(Lldb { target });
1653         let mingw_installer = builder.ensure(Mingw { host: target });
1654         let analysis_installer = builder.ensure(Analysis { compiler, target });
1655
1656         let docs_installer = builder.ensure(Docs { host: target });
1657         let std_installer =
1658             builder.ensure(Std { compiler: builder.compiler(stage, target), target });
1659
1660         let tmp = tmpdir(builder);
1661         let overlay = tmp.join("extended-overlay");
1662         let etc = builder.src.join("src/etc/installer");
1663         let work = tmp.join("work");
1664
1665         let _ = fs::remove_dir_all(&overlay);
1666         builder.install(&builder.src.join("COPYRIGHT"), &overlay, 0o644);
1667         builder.install(&builder.src.join("LICENSE-APACHE"), &overlay, 0o644);
1668         builder.install(&builder.src.join("LICENSE-MIT"), &overlay, 0o644);
1669         let version = builder.rust_version();
1670         builder.create(&overlay.join("version"), &version);
1671         if let Some(sha) = builder.rust_sha() {
1672             builder.create(&overlay.join("git-commit-hash"), &sha);
1673         }
1674         builder.install(&etc.join("README.md"), &overlay, 0o644);
1675
1676         // When rust-std package split from rustc, we needed to ensure that during
1677         // upgrades rustc was upgraded before rust-std. To avoid rustc clobbering
1678         // the std files during uninstall. To do this ensure that rustc comes
1679         // before rust-std in the list below.
1680         let mut tarballs = Vec::new();
1681         tarballs.push(rustc_installer);
1682         tarballs.push(cargo_installer);
1683         tarballs.extend(rls_installer.clone());
1684         tarballs.extend(clippy_installer.clone());
1685         tarballs.extend(miri_installer.clone());
1686         tarballs.extend(rustfmt_installer.clone());
1687         tarballs.extend(llvm_tools_installer);
1688         tarballs.extend(lldb_installer);
1689         tarballs.push(analysis_installer);
1690         tarballs.push(std_installer);
1691         if builder.config.docs {
1692             tarballs.push(docs_installer);
1693         }
1694         if target.contains("pc-windows-gnu") {
1695             tarballs.push(mingw_installer.unwrap());
1696         }
1697         let mut input_tarballs = tarballs[0].as_os_str().to_owned();
1698         for tarball in &tarballs[1..] {
1699             input_tarballs.push(",");
1700             input_tarballs.push(tarball);
1701         }
1702
1703         builder.info("building combined installer");
1704         let mut cmd = rust_installer(builder);
1705         cmd.arg("combine")
1706             .arg("--product-name=Rust")
1707             .arg("--rel-manifest-dir=rustlib")
1708             .arg("--success-message=Rust-is-ready-to-roll.")
1709             .arg("--work-dir")
1710             .arg(&work)
1711             .arg("--output-dir")
1712             .arg(&distdir(builder))
1713             .arg(format!("--package-name={}-{}", pkgname(builder, "rust"), target))
1714             .arg("--legacy-manifest-dirs=rustlib,cargo")
1715             .arg("--input-tarballs")
1716             .arg(input_tarballs)
1717             .arg("--non-installed-overlay")
1718             .arg(&overlay);
1719         let time = timeit(&builder);
1720         builder.run(&mut cmd);
1721         drop(time);
1722
1723         let mut license = String::new();
1724         license += &builder.read(&builder.src.join("COPYRIGHT"));
1725         license += &builder.read(&builder.src.join("LICENSE-APACHE"));
1726         license += &builder.read(&builder.src.join("LICENSE-MIT"));
1727         license.push_str("\n");
1728         license.push_str("\n");
1729
1730         let rtf = r"{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Arial;}}\nowwrap\fs18";
1731         let mut rtf = rtf.to_string();
1732         rtf.push_str("\n");
1733         for line in license.lines() {
1734             rtf.push_str(line);
1735             rtf.push_str("\\line ");
1736         }
1737         rtf.push_str("}");
1738
1739         fn filter(contents: &str, marker: &str) -> String {
1740             let start = format!("tool-{}-start", marker);
1741             let end = format!("tool-{}-end", marker);
1742             let mut lines = Vec::new();
1743             let mut omitted = false;
1744             for line in contents.lines() {
1745                 if line.contains(&start) {
1746                     omitted = true;
1747                 } else if line.contains(&end) {
1748                     omitted = false;
1749                 } else if !omitted {
1750                     lines.push(line);
1751                 }
1752             }
1753
1754             lines.join("\n")
1755         }
1756
1757         let xform = |p: &Path| {
1758             let mut contents = t!(fs::read_to_string(p));
1759             if rls_installer.is_none() {
1760                 contents = filter(&contents, "rls");
1761             }
1762             if clippy_installer.is_none() {
1763                 contents = filter(&contents, "clippy");
1764             }
1765             if miri_installer.is_none() {
1766                 contents = filter(&contents, "miri");
1767             }
1768             if rustfmt_installer.is_none() {
1769                 contents = filter(&contents, "rustfmt");
1770             }
1771             let ret = tmp.join(p.file_name().unwrap());
1772             t!(fs::write(&ret, &contents));
1773             ret
1774         };
1775
1776         if target.contains("apple-darwin") {
1777             builder.info("building pkg installer");
1778             let pkg = tmp.join("pkg");
1779             let _ = fs::remove_dir_all(&pkg);
1780
1781             let pkgbuild = |component: &str| {
1782                 let mut cmd = Command::new("pkgbuild");
1783                 cmd.arg("--identifier")
1784                     .arg(format!("org.rust-lang.{}", component))
1785                     .arg("--scripts")
1786                     .arg(pkg.join(component))
1787                     .arg("--nopayload")
1788                     .arg(pkg.join(component).with_extension("pkg"));
1789                 builder.run(&mut cmd);
1790             };
1791
1792             let prepare = |name: &str| {
1793                 builder.create_dir(&pkg.join(name));
1794                 builder.cp_r(
1795                     &work.join(&format!("{}-{}", pkgname(builder, name), target)),
1796                     &pkg.join(name),
1797                 );
1798                 builder.install(&etc.join("pkg/postinstall"), &pkg.join(name), 0o755);
1799                 pkgbuild(name);
1800             };
1801             prepare("rustc");
1802             prepare("cargo");
1803             prepare("rust-docs");
1804             prepare("rust-std");
1805             prepare("rust-analysis");
1806
1807             if rls_installer.is_some() {
1808                 prepare("rls");
1809             }
1810             if clippy_installer.is_some() {
1811                 prepare("clippy");
1812             }
1813             if miri_installer.is_some() {
1814                 prepare("miri");
1815             }
1816
1817             // create an 'uninstall' package
1818             builder.install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), 0o755);
1819             pkgbuild("uninstall");
1820
1821             builder.create_dir(&pkg.join("res"));
1822             builder.create(&pkg.join("res/LICENSE.txt"), &license);
1823             builder.install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644);
1824             let mut cmd = Command::new("productbuild");
1825             cmd.arg("--distribution")
1826                 .arg(xform(&etc.join("pkg/Distribution.xml")))
1827                 .arg("--resources")
1828                 .arg(pkg.join("res"))
1829                 .arg(distdir(builder).join(format!("{}-{}.pkg", pkgname(builder, "rust"), target)))
1830                 .arg("--package-path")
1831                 .arg(&pkg);
1832             let _time = timeit(builder);
1833             builder.run(&mut cmd);
1834         }
1835
1836         if target.contains("windows") {
1837             let exe = tmp.join("exe");
1838             let _ = fs::remove_dir_all(&exe);
1839
1840             let prepare = |name: &str| {
1841                 builder.create_dir(&exe.join(name));
1842                 let dir = if name == "rust-std" || name == "rust-analysis" {
1843                     format!("{}-{}", name, target)
1844                 } else if name == "rls" {
1845                     "rls-preview".to_string()
1846                 } else if name == "clippy" {
1847                     "clippy-preview".to_string()
1848                 } else if name == "miri" {
1849                     "miri-preview".to_string()
1850                 } else {
1851                     name.to_string()
1852                 };
1853                 builder.cp_r(
1854                     &work.join(&format!("{}-{}", pkgname(builder, name), target)).join(dir),
1855                     &exe.join(name),
1856                 );
1857                 builder.remove(&exe.join(name).join("manifest.in"));
1858             };
1859             prepare("rustc");
1860             prepare("cargo");
1861             prepare("rust-analysis");
1862             prepare("rust-docs");
1863             prepare("rust-std");
1864             if rls_installer.is_some() {
1865                 prepare("rls");
1866             }
1867             if clippy_installer.is_some() {
1868                 prepare("clippy");
1869             }
1870             if miri_installer.is_some() {
1871                 prepare("miri");
1872             }
1873             if target.contains("windows-gnu") {
1874                 prepare("rust-mingw");
1875             }
1876
1877             builder.install(&xform(&etc.join("exe/rust.iss")), &exe, 0o644);
1878             builder.install(&etc.join("exe/modpath.iss"), &exe, 0o644);
1879             builder.install(&etc.join("exe/upgrade.iss"), &exe, 0o644);
1880             builder.install(&etc.join("gfx/rust-logo.ico"), &exe, 0o644);
1881             builder.create(&exe.join("LICENSE.txt"), &license);
1882
1883             // Generate exe installer
1884             builder.info("building `exe` installer with `iscc`");
1885             let mut cmd = Command::new("iscc");
1886             cmd.arg("rust.iss").arg("/Q").current_dir(&exe);
1887             if target.contains("windows-gnu") {
1888                 cmd.arg("/dMINGW");
1889             }
1890             add_env(builder, &mut cmd, target);
1891             let time = timeit(builder);
1892             builder.run(&mut cmd);
1893             drop(time);
1894             builder.install(
1895                 &exe.join(format!("{}-{}.exe", pkgname(builder, "rust"), target)),
1896                 &distdir(builder),
1897                 0o755,
1898             );
1899
1900             // Generate msi installer
1901             let wix = PathBuf::from(env::var_os("WIX").unwrap());
1902             let heat = wix.join("bin/heat.exe");
1903             let candle = wix.join("bin/candle.exe");
1904             let light = wix.join("bin/light.exe");
1905
1906             let heat_flags = ["-nologo", "-gg", "-sfrag", "-srd", "-sreg"];
1907             builder.run(
1908                 Command::new(&heat)
1909                     .current_dir(&exe)
1910                     .arg("dir")
1911                     .arg("rustc")
1912                     .args(&heat_flags)
1913                     .arg("-cg")
1914                     .arg("RustcGroup")
1915                     .arg("-dr")
1916                     .arg("Rustc")
1917                     .arg("-var")
1918                     .arg("var.RustcDir")
1919                     .arg("-out")
1920                     .arg(exe.join("RustcGroup.wxs")),
1921             );
1922             builder.run(
1923                 Command::new(&heat)
1924                     .current_dir(&exe)
1925                     .arg("dir")
1926                     .arg("rust-docs")
1927                     .args(&heat_flags)
1928                     .arg("-cg")
1929                     .arg("DocsGroup")
1930                     .arg("-dr")
1931                     .arg("Docs")
1932                     .arg("-var")
1933                     .arg("var.DocsDir")
1934                     .arg("-out")
1935                     .arg(exe.join("DocsGroup.wxs"))
1936                     .arg("-t")
1937                     .arg(etc.join("msi/squash-components.xsl")),
1938             );
1939             builder.run(
1940                 Command::new(&heat)
1941                     .current_dir(&exe)
1942                     .arg("dir")
1943                     .arg("cargo")
1944                     .args(&heat_flags)
1945                     .arg("-cg")
1946                     .arg("CargoGroup")
1947                     .arg("-dr")
1948                     .arg("Cargo")
1949                     .arg("-var")
1950                     .arg("var.CargoDir")
1951                     .arg("-out")
1952                     .arg(exe.join("CargoGroup.wxs"))
1953                     .arg("-t")
1954                     .arg(etc.join("msi/remove-duplicates.xsl")),
1955             );
1956             builder.run(
1957                 Command::new(&heat)
1958                     .current_dir(&exe)
1959                     .arg("dir")
1960                     .arg("rust-std")
1961                     .args(&heat_flags)
1962                     .arg("-cg")
1963                     .arg("StdGroup")
1964                     .arg("-dr")
1965                     .arg("Std")
1966                     .arg("-var")
1967                     .arg("var.StdDir")
1968                     .arg("-out")
1969                     .arg(exe.join("StdGroup.wxs")),
1970             );
1971             if rls_installer.is_some() {
1972                 builder.run(
1973                     Command::new(&heat)
1974                         .current_dir(&exe)
1975                         .arg("dir")
1976                         .arg("rls")
1977                         .args(&heat_flags)
1978                         .arg("-cg")
1979                         .arg("RlsGroup")
1980                         .arg("-dr")
1981                         .arg("Rls")
1982                         .arg("-var")
1983                         .arg("var.RlsDir")
1984                         .arg("-out")
1985                         .arg(exe.join("RlsGroup.wxs"))
1986                         .arg("-t")
1987                         .arg(etc.join("msi/remove-duplicates.xsl")),
1988                 );
1989             }
1990             if clippy_installer.is_some() {
1991                 builder.run(
1992                     Command::new(&heat)
1993                         .current_dir(&exe)
1994                         .arg("dir")
1995                         .arg("clippy")
1996                         .args(&heat_flags)
1997                         .arg("-cg")
1998                         .arg("ClippyGroup")
1999                         .arg("-dr")
2000                         .arg("Clippy")
2001                         .arg("-var")
2002                         .arg("var.ClippyDir")
2003                         .arg("-out")
2004                         .arg(exe.join("ClippyGroup.wxs"))
2005                         .arg("-t")
2006                         .arg(etc.join("msi/remove-duplicates.xsl")),
2007                 );
2008             }
2009             if miri_installer.is_some() {
2010                 builder.run(
2011                     Command::new(&heat)
2012                         .current_dir(&exe)
2013                         .arg("dir")
2014                         .arg("miri")
2015                         .args(&heat_flags)
2016                         .arg("-cg")
2017                         .arg("MiriGroup")
2018                         .arg("-dr")
2019                         .arg("Miri")
2020                         .arg("-var")
2021                         .arg("var.MiriDir")
2022                         .arg("-out")
2023                         .arg(exe.join("MiriGroup.wxs"))
2024                         .arg("-t")
2025                         .arg(etc.join("msi/remove-duplicates.xsl")),
2026                 );
2027             }
2028             builder.run(
2029                 Command::new(&heat)
2030                     .current_dir(&exe)
2031                     .arg("dir")
2032                     .arg("rust-analysis")
2033                     .args(&heat_flags)
2034                     .arg("-cg")
2035                     .arg("AnalysisGroup")
2036                     .arg("-dr")
2037                     .arg("Analysis")
2038                     .arg("-var")
2039                     .arg("var.AnalysisDir")
2040                     .arg("-out")
2041                     .arg(exe.join("AnalysisGroup.wxs"))
2042                     .arg("-t")
2043                     .arg(etc.join("msi/remove-duplicates.xsl")),
2044             );
2045             if target.contains("windows-gnu") {
2046                 builder.run(
2047                     Command::new(&heat)
2048                         .current_dir(&exe)
2049                         .arg("dir")
2050                         .arg("rust-mingw")
2051                         .args(&heat_flags)
2052                         .arg("-cg")
2053                         .arg("GccGroup")
2054                         .arg("-dr")
2055                         .arg("Gcc")
2056                         .arg("-var")
2057                         .arg("var.GccDir")
2058                         .arg("-out")
2059                         .arg(exe.join("GccGroup.wxs")),
2060                 );
2061             }
2062
2063             let candle = |input: &Path| {
2064                 let output = exe.join(input.file_stem().unwrap()).with_extension("wixobj");
2065                 let arch = if target.contains("x86_64") { "x64" } else { "x86" };
2066                 let mut cmd = Command::new(&candle);
2067                 cmd.current_dir(&exe)
2068                     .arg("-nologo")
2069                     .arg("-dRustcDir=rustc")
2070                     .arg("-dDocsDir=rust-docs")
2071                     .arg("-dCargoDir=cargo")
2072                     .arg("-dStdDir=rust-std")
2073                     .arg("-dAnalysisDir=rust-analysis")
2074                     .arg("-arch")
2075                     .arg(&arch)
2076                     .arg("-out")
2077                     .arg(&output)
2078                     .arg(&input);
2079                 add_env(builder, &mut cmd, target);
2080
2081                 if rls_installer.is_some() {
2082                     cmd.arg("-dRlsDir=rls");
2083                 }
2084                 if clippy_installer.is_some() {
2085                     cmd.arg("-dClippyDir=clippy");
2086                 }
2087                 if miri_installer.is_some() {
2088                     cmd.arg("-dMiriDir=miri");
2089                 }
2090                 if target.contains("windows-gnu") {
2091                     cmd.arg("-dGccDir=rust-mingw");
2092                 }
2093                 builder.run(&mut cmd);
2094             };
2095             candle(&xform(&etc.join("msi/rust.wxs")));
2096             candle(&etc.join("msi/ui.wxs"));
2097             candle(&etc.join("msi/rustwelcomedlg.wxs"));
2098             candle("RustcGroup.wxs".as_ref());
2099             candle("DocsGroup.wxs".as_ref());
2100             candle("CargoGroup.wxs".as_ref());
2101             candle("StdGroup.wxs".as_ref());
2102             if rls_installer.is_some() {
2103                 candle("RlsGroup.wxs".as_ref());
2104             }
2105             if clippy_installer.is_some() {
2106                 candle("ClippyGroup.wxs".as_ref());
2107             }
2108             if miri_installer.is_some() {
2109                 candle("MiriGroup.wxs".as_ref());
2110             }
2111             candle("AnalysisGroup.wxs".as_ref());
2112
2113             if target.contains("windows-gnu") {
2114                 candle("GccGroup.wxs".as_ref());
2115             }
2116
2117             builder.create(&exe.join("LICENSE.rtf"), &rtf);
2118             builder.install(&etc.join("gfx/banner.bmp"), &exe, 0o644);
2119             builder.install(&etc.join("gfx/dialogbg.bmp"), &exe, 0o644);
2120
2121             builder.info(&format!("building `msi` installer with {:?}", light));
2122             let filename = format!("{}-{}.msi", pkgname(builder, "rust"), target);
2123             let mut cmd = Command::new(&light);
2124             cmd.arg("-nologo")
2125                 .arg("-ext")
2126                 .arg("WixUIExtension")
2127                 .arg("-ext")
2128                 .arg("WixUtilExtension")
2129                 .arg("-out")
2130                 .arg(exe.join(&filename))
2131                 .arg("rust.wixobj")
2132                 .arg("ui.wixobj")
2133                 .arg("rustwelcomedlg.wixobj")
2134                 .arg("RustcGroup.wixobj")
2135                 .arg("DocsGroup.wixobj")
2136                 .arg("CargoGroup.wixobj")
2137                 .arg("StdGroup.wixobj")
2138                 .arg("AnalysisGroup.wixobj")
2139                 .current_dir(&exe);
2140
2141             if rls_installer.is_some() {
2142                 cmd.arg("RlsGroup.wixobj");
2143             }
2144             if clippy_installer.is_some() {
2145                 cmd.arg("ClippyGroup.wixobj");
2146             }
2147             if miri_installer.is_some() {
2148                 cmd.arg("MiriGroup.wixobj");
2149             }
2150
2151             if target.contains("windows-gnu") {
2152                 cmd.arg("GccGroup.wixobj");
2153             }
2154             // ICE57 wrongly complains about the shortcuts
2155             cmd.arg("-sice:ICE57");
2156
2157             let _time = timeit(builder);
2158             builder.run(&mut cmd);
2159
2160             if !builder.config.dry_run {
2161                 t!(fs::rename(exe.join(&filename), distdir(builder).join(&filename)));
2162             }
2163         }
2164     }
2165 }
2166
2167 fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: Interned<String>) {
2168     let mut parts = channel::CFG_RELEASE_NUM.split('.');
2169     cmd.env("CFG_RELEASE_INFO", builder.rust_version())
2170         .env("CFG_RELEASE_NUM", channel::CFG_RELEASE_NUM)
2171         .env("CFG_RELEASE", builder.rust_release())
2172         .env("CFG_VER_MAJOR", parts.next().unwrap())
2173         .env("CFG_VER_MINOR", parts.next().unwrap())
2174         .env("CFG_VER_PATCH", parts.next().unwrap())
2175         .env("CFG_VER_BUILD", "0") // just needed to build
2176         .env("CFG_PACKAGE_VERS", builder.rust_package_vers())
2177         .env("CFG_PACKAGE_NAME", pkgname(builder, "rust"))
2178         .env("CFG_BUILD", target)
2179         .env("CFG_CHANNEL", &builder.config.channel);
2180
2181     if target.contains("windows-gnu") {
2182         cmd.env("CFG_MINGW", "1").env("CFG_ABI", "GNU");
2183     } else {
2184         cmd.env("CFG_MINGW", "0").env("CFG_ABI", "MSVC");
2185     }
2186
2187     if target.contains("x86_64") {
2188         cmd.env("CFG_PLATFORM", "x64");
2189     } else {
2190         cmd.env("CFG_PLATFORM", "x86");
2191     }
2192 }
2193
2194 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
2195 pub struct HashSign;
2196
2197 impl Step for HashSign {
2198     type Output = ();
2199     const ONLY_HOSTS: bool = true;
2200
2201     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2202         run.path("hash-and-sign")
2203     }
2204
2205     fn make_run(run: RunConfig<'_>) {
2206         run.builder.ensure(HashSign);
2207     }
2208
2209     fn run(self, builder: &Builder<'_>) {
2210         // This gets called by `promote-release`
2211         // (https://github.com/rust-lang/rust-central-station/tree/master/promote-release).
2212         let mut cmd = builder.tool_cmd(Tool::BuildManifest);
2213         if builder.config.dry_run {
2214             return;
2215         }
2216         let sign = builder.config.dist_sign_folder.as_ref().unwrap_or_else(|| {
2217             panic!("\n\nfailed to specify `dist.sign-folder` in `config.toml`\n\n")
2218         });
2219         let addr = builder.config.dist_upload_addr.as_ref().unwrap_or_else(|| {
2220             panic!("\n\nfailed to specify `dist.upload-addr` in `config.toml`\n\n")
2221         });
2222         let pass = if env::var("BUILD_MANIFEST_DISABLE_SIGNING").is_err() {
2223             let file = builder.config.dist_gpg_password_file.as_ref().unwrap_or_else(|| {
2224                 panic!("\n\nfailed to specify `dist.gpg-password-file` in `config.toml`\n\n")
2225             });
2226             t!(fs::read_to_string(&file))
2227         } else {
2228             String::new()
2229         };
2230
2231         let today = output(Command::new("date").arg("+%Y-%m-%d"));
2232
2233         cmd.arg(sign);
2234         cmd.arg(distdir(builder));
2235         cmd.arg(today.trim());
2236         cmd.arg(builder.rust_package_vers());
2237         cmd.arg(addr);
2238         cmd.arg(builder.package_vers(&builder.release_num("cargo")));
2239         cmd.arg(builder.package_vers(&builder.release_num("rls")));
2240         cmd.arg(builder.package_vers(&builder.release_num("clippy")));
2241         cmd.arg(builder.package_vers(&builder.release_num("miri")));
2242         cmd.arg(builder.package_vers(&builder.release_num("rustfmt")));
2243         cmd.arg(builder.llvm_tools_package_vers());
2244         cmd.arg(builder.lldb_package_vers());
2245
2246         builder.create_dir(&distdir(builder));
2247
2248         let mut child = t!(cmd.stdin(Stdio::piped()).spawn());
2249         t!(child.stdin.take().unwrap().write_all(pass.as_bytes()));
2250         let status = t!(child.wait());
2251         assert!(status.success());
2252     }
2253 }
2254
2255 // Maybe add libLLVM.so to the lib-dir. It will only have been built if
2256 // LLVM tools are linked dynamically.
2257 //
2258 // We add this to both the libdir of the rustc binary itself (for it to load at
2259 // runtime) and also to the target directory so it can find it at link-time.
2260 //
2261 // Note: This function does no yet support Windows but we also don't support
2262 //       linking LLVM tools dynamically on Windows yet.
2263 pub fn maybe_install_llvm_dylib(builder: &Builder<'_>, target: Interned<String>, sysroot: &Path) {
2264     let src_libdir = builder.llvm_out(target).join("lib");
2265     let dst_libdir1 = sysroot.join("lib/rustlib").join(&*target).join("lib");
2266     let dst_libdir2 =
2267         sysroot.join(builder.sysroot_libdir_relative(Compiler { stage: 1, host: target }));
2268     t!(fs::create_dir_all(&dst_libdir1));
2269     t!(fs::create_dir_all(&dst_libdir2));
2270
2271     if target.contains("apple-darwin") {
2272         let llvm_dylib_path = src_libdir.join("libLLVM.dylib");
2273         if llvm_dylib_path.exists() {
2274             builder.install(&llvm_dylib_path, &dst_libdir1, 0o644);
2275             builder.install(&llvm_dylib_path, &dst_libdir2, 0o644);
2276         }
2277         return;
2278     }
2279
2280     // Usually libLLVM.so is a symlink to something like libLLVM-6.0.so.
2281     // Since tools link to the latter rather than the former, we have to
2282     // follow the symlink to find out what to distribute.
2283     let llvm_dylib_path = src_libdir.join("libLLVM.so");
2284     if llvm_dylib_path.exists() {
2285         let llvm_dylib_path = llvm_dylib_path.canonicalize().unwrap_or_else(|e| {
2286             panic!("dist: Error calling canonicalize path `{}`: {}", llvm_dylib_path.display(), e);
2287         });
2288
2289         builder.install(&llvm_dylib_path, &dst_libdir1, 0o644);
2290         builder.install(&llvm_dylib_path, &dst_libdir2, 0o644);
2291     }
2292 }
2293
2294 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
2295 pub struct LlvmTools {
2296     pub target: Interned<String>,
2297 }
2298
2299 impl Step for LlvmTools {
2300     type Output = Option<PathBuf>;
2301     const ONLY_HOSTS: bool = true;
2302
2303     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2304         run.path("llvm-tools")
2305     }
2306
2307     fn make_run(run: RunConfig<'_>) {
2308         run.builder.ensure(LlvmTools { target: run.target });
2309     }
2310
2311     fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
2312         let target = self.target;
2313         assert!(builder.config.extended);
2314
2315         /* run only if llvm-config isn't used */
2316         if let Some(config) = builder.config.target_config.get(&target) {
2317             if let Some(ref _s) = config.llvm_config {
2318                 builder.info(&format!("Skipping LlvmTools ({}): external LLVM", target));
2319                 return None;
2320             }
2321         }
2322
2323         builder.info(&format!("Dist LlvmTools ({})", target));
2324         let _time = timeit(builder);
2325         let src = builder.src.join("src/llvm-project/llvm");
2326         let name = pkgname(builder, "llvm-tools");
2327
2328         let tmp = tmpdir(builder);
2329         let image = tmp.join("llvm-tools-image");
2330         drop(fs::remove_dir_all(&image));
2331
2332         // Prepare the image directory
2333         let src_bindir = builder.llvm_out(target).join("bin");
2334         let dst_bindir = image.join("lib/rustlib").join(&*target).join("bin");
2335         t!(fs::create_dir_all(&dst_bindir));
2336         for tool in LLVM_TOOLS {
2337             let exe = src_bindir.join(exe(tool, &target));
2338             builder.install(&exe, &dst_bindir, 0o755);
2339         }
2340
2341         // Prepare the overlay
2342         let overlay = tmp.join("llvm-tools-overlay");
2343         drop(fs::remove_dir_all(&overlay));
2344         builder.create_dir(&overlay);
2345         builder.install(&src.join("README.txt"), &overlay, 0o644);
2346         builder.install(&src.join("LICENSE.TXT"), &overlay, 0o644);
2347         builder.create(&overlay.join("version"), &builder.llvm_tools_vers());
2348
2349         // Generate the installer tarball
2350         let mut cmd = rust_installer(builder);
2351         cmd.arg("generate")
2352             .arg("--product-name=Rust")
2353             .arg("--rel-manifest-dir=rustlib")
2354             .arg("--success-message=llvm-tools-installed.")
2355             .arg("--image-dir")
2356             .arg(&image)
2357             .arg("--work-dir")
2358             .arg(&tmpdir(builder))
2359             .arg("--output-dir")
2360             .arg(&distdir(builder))
2361             .arg("--non-installed-overlay")
2362             .arg(&overlay)
2363             .arg(format!("--package-name={}-{}", name, target))
2364             .arg("--legacy-manifest-dirs=rustlib,cargo")
2365             .arg("--component-name=llvm-tools-preview");
2366
2367         builder.run(&mut cmd);
2368         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
2369     }
2370 }
2371
2372 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
2373 pub struct Lldb {
2374     pub target: Interned<String>,
2375 }
2376
2377 impl Step for Lldb {
2378     type Output = Option<PathBuf>;
2379     const ONLY_HOSTS: bool = true;
2380     const DEFAULT: bool = true;
2381
2382     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2383         run.path("src/llvm-project/lldb").path("src/tools/lldb")
2384     }
2385
2386     fn make_run(run: RunConfig<'_>) {
2387         run.builder.ensure(Lldb { target: run.target });
2388     }
2389
2390     fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
2391         let target = self.target;
2392
2393         if builder.config.dry_run {
2394             return None;
2395         }
2396
2397         let bindir = builder.llvm_out(target).join("bin");
2398         let lldb_exe = bindir.join(exe("lldb", &target));
2399         if !lldb_exe.exists() {
2400             return None;
2401         }
2402
2403         builder.info(&format!("Dist Lldb ({})", target));
2404         let src = builder.src.join("src/llvm-project/lldb");
2405         let name = pkgname(builder, "lldb");
2406
2407         let tmp = tmpdir(builder);
2408         let image = tmp.join("lldb-image");
2409         drop(fs::remove_dir_all(&image));
2410
2411         // Prepare the image directory
2412         let root = image.join("lib/rustlib").join(&*target);
2413         let dst = root.join("bin");
2414         t!(fs::create_dir_all(&dst));
2415         for program in &["lldb", "lldb-argdumper", "lldb-mi", "lldb-server"] {
2416             let exe = bindir.join(exe(program, &target));
2417             builder.install(&exe, &dst, 0o755);
2418         }
2419
2420         // The libraries.
2421         let libdir = builder.llvm_out(target).join("lib");
2422         let dst = root.join("lib");
2423         t!(fs::create_dir_all(&dst));
2424         for entry in t!(fs::read_dir(&libdir)) {
2425             let entry = entry.unwrap();
2426             if let Ok(name) = entry.file_name().into_string() {
2427                 if name.starts_with("liblldb.") && !name.ends_with(".a") {
2428                     if t!(entry.file_type()).is_symlink() {
2429                         builder.copy_to_folder(&entry.path(), &dst);
2430                     } else {
2431                         builder.install(&entry.path(), &dst, 0o755);
2432                     }
2433                 }
2434             }
2435         }
2436
2437         // The lldb scripts might be installed in lib/python$version
2438         // or in lib64/python$version.  If lib64 exists, use it;
2439         // otherwise lib.
2440         let libdir = builder.llvm_out(target).join("lib64");
2441         let (libdir, libdir_name) = if libdir.exists() {
2442             (libdir, "lib64")
2443         } else {
2444             (builder.llvm_out(target).join("lib"), "lib")
2445         };
2446         for entry in t!(fs::read_dir(&libdir)) {
2447             let entry = t!(entry);
2448             if let Ok(name) = entry.file_name().into_string() {
2449                 if name.starts_with("python") {
2450                     let dst = root.join(libdir_name).join(entry.file_name());
2451                     t!(fs::create_dir_all(&dst));
2452                     builder.cp_r(&entry.path(), &dst);
2453                     break;
2454                 }
2455             }
2456         }
2457
2458         // Prepare the overlay
2459         let overlay = tmp.join("lldb-overlay");
2460         drop(fs::remove_dir_all(&overlay));
2461         builder.create_dir(&overlay);
2462         builder.install(&src.join("LICENSE.TXT"), &overlay, 0o644);
2463         builder.create(&overlay.join("version"), &builder.lldb_vers());
2464
2465         // Generate the installer tarball
2466         let mut cmd = rust_installer(builder);
2467         cmd.arg("generate")
2468             .arg("--product-name=Rust")
2469             .arg("--rel-manifest-dir=rustlib")
2470             .arg("--success-message=lldb-installed.")
2471             .arg("--image-dir")
2472             .arg(&image)
2473             .arg("--work-dir")
2474             .arg(&tmpdir(builder))
2475             .arg("--output-dir")
2476             .arg(&distdir(builder))
2477             .arg("--non-installed-overlay")
2478             .arg(&overlay)
2479             .arg(format!("--package-name={}-{}", name, target))
2480             .arg("--legacy-manifest-dirs=rustlib,cargo")
2481             .arg("--component-name=lldb-preview");
2482
2483         builder.run(&mut cmd);
2484         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
2485     }
2486 }