]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/dist.rs
clean up error codes explanation
[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/libstd",
988             "src/libunwind",
989             "src/libtest",
990             "src/libterm",
991             "src/libprofiler_builtins",
992             "src/stdarch",
993             "src/libproc_macro",
994             "src/tools/rustc-std-workspace-core",
995             "src/tools/rustc-std-workspace-alloc",
996             "src/tools/rustc-std-workspace-std",
997             "src/librustc",
998             "src/libsyntax",
999         ];
1000
1001         copy_src_dirs(builder, &std_src_dirs[..], &[], &dst_src);
1002         for file in src_files.iter() {
1003             builder.copy(&builder.src.join(file), &dst_src.join(file));
1004         }
1005
1006         // Create source tarball in rust-installer format
1007         let mut cmd = rust_installer(builder);
1008         cmd.arg("generate")
1009             .arg("--product-name=Rust")
1010             .arg("--rel-manifest-dir=rustlib")
1011             .arg("--success-message=Awesome-Source.")
1012             .arg("--image-dir")
1013             .arg(&image)
1014             .arg("--work-dir")
1015             .arg(&tmpdir(builder))
1016             .arg("--output-dir")
1017             .arg(&distdir(builder))
1018             .arg(format!("--package-name={}", name))
1019             .arg("--component-name=rust-src")
1020             .arg("--legacy-manifest-dirs=rustlib,cargo");
1021
1022         builder.info("Dist src");
1023         let _time = timeit(builder);
1024         builder.run(&mut cmd);
1025
1026         builder.remove_dir(&image);
1027         distdir(builder).join(&format!("{}.tar.gz", name))
1028     }
1029 }
1030
1031 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1032 pub struct PlainSourceTarball;
1033
1034 impl Step for PlainSourceTarball {
1035     /// Produces the location of the tarball generated
1036     type Output = PathBuf;
1037     const DEFAULT: bool = true;
1038     const ONLY_HOSTS: bool = true;
1039
1040     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1041         let builder = run.builder;
1042         run.path("src").default_condition(builder.config.rust_dist_src)
1043     }
1044
1045     fn make_run(run: RunConfig<'_>) {
1046         run.builder.ensure(PlainSourceTarball);
1047     }
1048
1049     /// Creates the plain source tarball
1050     fn run(self, builder: &Builder<'_>) -> PathBuf {
1051         // Make sure that the root folder of tarball has the correct name
1052         let plain_name = format!("{}-src", pkgname(builder, "rustc"));
1053         let plain_dst_src = tmpdir(builder).join(&plain_name);
1054         let _ = fs::remove_dir_all(&plain_dst_src);
1055         t!(fs::create_dir_all(&plain_dst_src));
1056
1057         // This is the set of root paths which will become part of the source package
1058         let src_files = [
1059             "COPYRIGHT",
1060             "LICENSE-APACHE",
1061             "LICENSE-MIT",
1062             "CONTRIBUTING.md",
1063             "README.md",
1064             "RELEASES.md",
1065             "configure",
1066             "x.py",
1067             "config.toml.example",
1068             "Cargo.toml",
1069             "Cargo.lock",
1070         ];
1071         let src_dirs = ["src"];
1072
1073         copy_src_dirs(builder, &src_dirs[..], &[], &plain_dst_src);
1074
1075         // Copy the files normally
1076         for item in &src_files {
1077             builder.copy(&builder.src.join(item), &plain_dst_src.join(item));
1078         }
1079
1080         // Create the version file
1081         builder.create(&plain_dst_src.join("version"), &builder.rust_version());
1082         if let Some(sha) = builder.rust_sha() {
1083             builder.create(&plain_dst_src.join("git-commit-hash"), &sha);
1084         }
1085
1086         // If we're building from git sources, we need to vendor a complete distribution.
1087         if builder.rust_info.is_git() {
1088             // Vendor all Cargo dependencies
1089             let mut cmd = Command::new(&builder.initial_cargo);
1090             cmd.arg("vendor").current_dir(&plain_dst_src);
1091             builder.run(&mut cmd);
1092         }
1093
1094         // Create plain source tarball
1095         let plain_name = format!("rustc-{}-src", builder.rust_package_vers());
1096         let mut tarball = distdir(builder).join(&format!("{}.tar.gz", plain_name));
1097         tarball.set_extension(""); // strip .gz
1098         tarball.set_extension(""); // strip .tar
1099         if let Some(dir) = tarball.parent() {
1100             builder.create_dir(&dir);
1101         }
1102         builder.info("running installer");
1103         let mut cmd = rust_installer(builder);
1104         cmd.arg("tarball")
1105             .arg("--input")
1106             .arg(&plain_name)
1107             .arg("--output")
1108             .arg(&tarball)
1109             .arg("--work-dir=.")
1110             .current_dir(tmpdir(builder));
1111
1112         builder.info("Create plain source tarball");
1113         let _time = timeit(builder);
1114         builder.run(&mut cmd);
1115         distdir(builder).join(&format!("{}.tar.gz", plain_name))
1116     }
1117 }
1118
1119 // We have to run a few shell scripts, which choke quite a bit on both `\`
1120 // characters and on `C:\` paths, so normalize both of them away.
1121 pub fn sanitize_sh(path: &Path) -> String {
1122     let path = path.to_str().unwrap().replace("\\", "/");
1123     return change_drive(&path).unwrap_or(path);
1124
1125     fn change_drive(s: &str) -> Option<String> {
1126         let mut ch = s.chars();
1127         let drive = ch.next().unwrap_or('C');
1128         if ch.next() != Some(':') {
1129             return None;
1130         }
1131         if ch.next() != Some('/') {
1132             return None;
1133         }
1134         Some(format!("/{}/{}", drive, &s[drive.len_utf8() + 2..]))
1135     }
1136 }
1137
1138 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1139 pub struct Cargo {
1140     pub compiler: Compiler,
1141     pub target: Interned<String>,
1142 }
1143
1144 impl Step for Cargo {
1145     type Output = PathBuf;
1146     const ONLY_HOSTS: bool = true;
1147
1148     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1149         run.path("cargo")
1150     }
1151
1152     fn make_run(run: RunConfig<'_>) {
1153         run.builder.ensure(Cargo {
1154             compiler: run.builder.compiler_for(
1155                 run.builder.top_stage,
1156                 run.builder.config.build,
1157                 run.target,
1158             ),
1159             target: run.target,
1160         });
1161     }
1162
1163     fn run(self, builder: &Builder<'_>) -> PathBuf {
1164         let compiler = self.compiler;
1165         let target = self.target;
1166
1167         let src = builder.src.join("src/tools/cargo");
1168         let etc = src.join("src/etc");
1169         let release_num = builder.release_num("cargo");
1170         let name = pkgname(builder, "cargo");
1171         let version = builder.cargo_info.version(builder, &release_num);
1172
1173         let tmp = tmpdir(builder);
1174         let image = tmp.join("cargo-image");
1175         drop(fs::remove_dir_all(&image));
1176         builder.create_dir(&image);
1177
1178         // Prepare the image directory
1179         builder.create_dir(&image.join("share/zsh/site-functions"));
1180         builder.create_dir(&image.join("etc/bash_completion.d"));
1181         let cargo = builder.ensure(tool::Cargo { compiler, target });
1182         builder.install(&cargo, &image.join("bin"), 0o755);
1183         for man in t!(etc.join("man").read_dir()) {
1184             let man = t!(man);
1185             builder.install(&man.path(), &image.join("share/man/man1"), 0o644);
1186         }
1187         builder.install(&etc.join("_cargo"), &image.join("share/zsh/site-functions"), 0o644);
1188         builder.copy(&etc.join("cargo.bashcomp.sh"), &image.join("etc/bash_completion.d/cargo"));
1189         let doc = image.join("share/doc/cargo");
1190         builder.install(&src.join("README.md"), &doc, 0o644);
1191         builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
1192         builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1193         builder.install(&src.join("LICENSE-THIRD-PARTY"), &doc, 0o644);
1194
1195         // Prepare the overlay
1196         let overlay = tmp.join("cargo-overlay");
1197         drop(fs::remove_dir_all(&overlay));
1198         builder.create_dir(&overlay);
1199         builder.install(&src.join("README.md"), &overlay, 0o644);
1200         builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
1201         builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
1202         builder.install(&src.join("LICENSE-THIRD-PARTY"), &overlay, 0o644);
1203         builder.create(&overlay.join("version"), &version);
1204
1205         // Generate the installer tarball
1206         let mut cmd = rust_installer(builder);
1207         cmd.arg("generate")
1208             .arg("--product-name=Rust")
1209             .arg("--rel-manifest-dir=rustlib")
1210             .arg("--success-message=Rust-is-ready-to-roll.")
1211             .arg("--image-dir")
1212             .arg(&image)
1213             .arg("--work-dir")
1214             .arg(&tmpdir(builder))
1215             .arg("--output-dir")
1216             .arg(&distdir(builder))
1217             .arg("--non-installed-overlay")
1218             .arg(&overlay)
1219             .arg(format!("--package-name={}-{}", name, target))
1220             .arg("--component-name=cargo")
1221             .arg("--legacy-manifest-dirs=rustlib,cargo");
1222
1223         builder.info(&format!("Dist cargo stage{} ({})", compiler.stage, target));
1224         let _time = timeit(builder);
1225         builder.run(&mut cmd);
1226         distdir(builder).join(format!("{}-{}.tar.gz", name, target))
1227     }
1228 }
1229
1230 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1231 pub struct Rls {
1232     pub compiler: Compiler,
1233     pub target: Interned<String>,
1234 }
1235
1236 impl Step for Rls {
1237     type Output = Option<PathBuf>;
1238     const ONLY_HOSTS: bool = true;
1239
1240     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1241         run.path("rls")
1242     }
1243
1244     fn make_run(run: RunConfig<'_>) {
1245         run.builder.ensure(Rls {
1246             compiler: run.builder.compiler_for(
1247                 run.builder.top_stage,
1248                 run.builder.config.build,
1249                 run.target,
1250             ),
1251             target: run.target,
1252         });
1253     }
1254
1255     fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
1256         let compiler = self.compiler;
1257         let target = self.target;
1258         assert!(builder.config.extended);
1259
1260         let src = builder.src.join("src/tools/rls");
1261         let release_num = builder.release_num("rls");
1262         let name = pkgname(builder, "rls");
1263         let version = builder.rls_info.version(builder, &release_num);
1264
1265         let tmp = tmpdir(builder);
1266         let image = tmp.join("rls-image");
1267         drop(fs::remove_dir_all(&image));
1268         t!(fs::create_dir_all(&image));
1269
1270         // Prepare the image directory
1271         // We expect RLS to build, because we've exited this step above if tool
1272         // state for RLS isn't testing.
1273         let rls = builder
1274             .ensure(tool::Rls { compiler, target, extra_features: Vec::new() })
1275             .or_else(|| {
1276                 missing_tool("RLS", builder.build.config.missing_tools);
1277                 None
1278             })?;
1279
1280         builder.install(&rls, &image.join("bin"), 0o755);
1281         let doc = image.join("share/doc/rls");
1282         builder.install(&src.join("README.md"), &doc, 0o644);
1283         builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
1284         builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1285
1286         // Prepare the overlay
1287         let overlay = tmp.join("rls-overlay");
1288         drop(fs::remove_dir_all(&overlay));
1289         t!(fs::create_dir_all(&overlay));
1290         builder.install(&src.join("README.md"), &overlay, 0o644);
1291         builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
1292         builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
1293         builder.create(&overlay.join("version"), &version);
1294
1295         // Generate the installer tarball
1296         let mut cmd = rust_installer(builder);
1297         cmd.arg("generate")
1298             .arg("--product-name=Rust")
1299             .arg("--rel-manifest-dir=rustlib")
1300             .arg("--success-message=RLS-ready-to-serve.")
1301             .arg("--image-dir")
1302             .arg(&image)
1303             .arg("--work-dir")
1304             .arg(&tmpdir(builder))
1305             .arg("--output-dir")
1306             .arg(&distdir(builder))
1307             .arg("--non-installed-overlay")
1308             .arg(&overlay)
1309             .arg(format!("--package-name={}-{}", name, target))
1310             .arg("--legacy-manifest-dirs=rustlib,cargo")
1311             .arg("--component-name=rls-preview");
1312
1313         builder.info(&format!("Dist RLS stage{} ({})", compiler.stage, target));
1314         let _time = timeit(builder);
1315         builder.run(&mut cmd);
1316         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
1317     }
1318 }
1319
1320 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1321 pub struct Clippy {
1322     pub compiler: Compiler,
1323     pub target: Interned<String>,
1324 }
1325
1326 impl Step for Clippy {
1327     type Output = Option<PathBuf>;
1328     const ONLY_HOSTS: bool = true;
1329
1330     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1331         run.path("clippy")
1332     }
1333
1334     fn make_run(run: RunConfig<'_>) {
1335         run.builder.ensure(Clippy {
1336             compiler: run.builder.compiler_for(
1337                 run.builder.top_stage,
1338                 run.builder.config.build,
1339                 run.target,
1340             ),
1341             target: run.target,
1342         });
1343     }
1344
1345     fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
1346         let compiler = self.compiler;
1347         let target = self.target;
1348         assert!(builder.config.extended);
1349
1350         let src = builder.src.join("src/tools/clippy");
1351         let release_num = builder.release_num("clippy");
1352         let name = pkgname(builder, "clippy");
1353         let version = builder.clippy_info.version(builder, &release_num);
1354
1355         let tmp = tmpdir(builder);
1356         let image = tmp.join("clippy-image");
1357         drop(fs::remove_dir_all(&image));
1358         builder.create_dir(&image);
1359
1360         // Prepare the image directory
1361         // We expect clippy to build, because we've exited this step above if tool
1362         // state for clippy isn't testing.
1363         let clippy = builder
1364             .ensure(tool::Clippy { compiler, target, extra_features: Vec::new() })
1365             .or_else(|| {
1366                 missing_tool("clippy", builder.build.config.missing_tools);
1367                 None
1368             })?;
1369         let cargoclippy = builder
1370             .ensure(tool::CargoClippy { compiler, target, extra_features: Vec::new() })
1371             .or_else(|| {
1372                 missing_tool("cargo clippy", builder.build.config.missing_tools);
1373                 None
1374             })?;
1375
1376         builder.install(&clippy, &image.join("bin"), 0o755);
1377         builder.install(&cargoclippy, &image.join("bin"), 0o755);
1378         let doc = image.join("share/doc/clippy");
1379         builder.install(&src.join("README.md"), &doc, 0o644);
1380         builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1381         builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
1382
1383         // Prepare the overlay
1384         let overlay = tmp.join("clippy-overlay");
1385         drop(fs::remove_dir_all(&overlay));
1386         t!(fs::create_dir_all(&overlay));
1387         builder.install(&src.join("README.md"), &overlay, 0o644);
1388         builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1389         builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
1390         builder.create(&overlay.join("version"), &version);
1391
1392         // Generate the installer tarball
1393         let mut cmd = rust_installer(builder);
1394         cmd.arg("generate")
1395             .arg("--product-name=Rust")
1396             .arg("--rel-manifest-dir=rustlib")
1397             .arg("--success-message=clippy-ready-to-serve.")
1398             .arg("--image-dir")
1399             .arg(&image)
1400             .arg("--work-dir")
1401             .arg(&tmpdir(builder))
1402             .arg("--output-dir")
1403             .arg(&distdir(builder))
1404             .arg("--non-installed-overlay")
1405             .arg(&overlay)
1406             .arg(format!("--package-name={}-{}", name, target))
1407             .arg("--legacy-manifest-dirs=rustlib,cargo")
1408             .arg("--component-name=clippy-preview");
1409
1410         builder.info(&format!("Dist clippy stage{} ({})", compiler.stage, target));
1411         let _time = timeit(builder);
1412         builder.run(&mut cmd);
1413         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
1414     }
1415 }
1416
1417 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1418 pub struct Miri {
1419     pub compiler: Compiler,
1420     pub target: Interned<String>,
1421 }
1422
1423 impl Step for Miri {
1424     type Output = Option<PathBuf>;
1425     const ONLY_HOSTS: bool = true;
1426
1427     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1428         run.path("miri")
1429     }
1430
1431     fn make_run(run: RunConfig<'_>) {
1432         run.builder.ensure(Miri {
1433             compiler: run.builder.compiler_for(
1434                 run.builder.top_stage,
1435                 run.builder.config.build,
1436                 run.target,
1437             ),
1438             target: run.target,
1439         });
1440     }
1441
1442     fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
1443         let compiler = self.compiler;
1444         let target = self.target;
1445         assert!(builder.config.extended);
1446
1447         let src = builder.src.join("src/tools/miri");
1448         let release_num = builder.release_num("miri");
1449         let name = pkgname(builder, "miri");
1450         let version = builder.miri_info.version(builder, &release_num);
1451
1452         let tmp = tmpdir(builder);
1453         let image = tmp.join("miri-image");
1454         drop(fs::remove_dir_all(&image));
1455         builder.create_dir(&image);
1456
1457         // Prepare the image directory
1458         // We expect miri to build, because we've exited this step above if tool
1459         // state for miri isn't testing.
1460         let miri = builder
1461             .ensure(tool::Miri { compiler, target, extra_features: Vec::new() })
1462             .or_else(|| {
1463                 missing_tool("miri", builder.build.config.missing_tools);
1464                 None
1465             })?;
1466         let cargomiri = builder
1467             .ensure(tool::CargoMiri { compiler, target, extra_features: Vec::new() })
1468             .or_else(|| {
1469                 missing_tool("cargo miri", builder.build.config.missing_tools);
1470                 None
1471             })?;
1472
1473         builder.install(&miri, &image.join("bin"), 0o755);
1474         builder.install(&cargomiri, &image.join("bin"), 0o755);
1475         let doc = image.join("share/doc/miri");
1476         builder.install(&src.join("README.md"), &doc, 0o644);
1477         builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1478         builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
1479
1480         // Prepare the overlay
1481         let overlay = tmp.join("miri-overlay");
1482         drop(fs::remove_dir_all(&overlay));
1483         t!(fs::create_dir_all(&overlay));
1484         builder.install(&src.join("README.md"), &overlay, 0o644);
1485         builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1486         builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
1487         builder.create(&overlay.join("version"), &version);
1488
1489         // Generate the installer tarball
1490         let mut cmd = rust_installer(builder);
1491         cmd.arg("generate")
1492             .arg("--product-name=Rust")
1493             .arg("--rel-manifest-dir=rustlib")
1494             .arg("--success-message=miri-ready-to-serve.")
1495             .arg("--image-dir")
1496             .arg(&image)
1497             .arg("--work-dir")
1498             .arg(&tmpdir(builder))
1499             .arg("--output-dir")
1500             .arg(&distdir(builder))
1501             .arg("--non-installed-overlay")
1502             .arg(&overlay)
1503             .arg(format!("--package-name={}-{}", name, target))
1504             .arg("--legacy-manifest-dirs=rustlib,cargo")
1505             .arg("--component-name=miri-preview");
1506
1507         builder.info(&format!("Dist miri stage{} ({})", compiler.stage, target));
1508         let _time = timeit(builder);
1509         builder.run(&mut cmd);
1510         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
1511     }
1512 }
1513
1514 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1515 pub struct Rustfmt {
1516     pub compiler: Compiler,
1517     pub target: Interned<String>,
1518 }
1519
1520 impl Step for Rustfmt {
1521     type Output = Option<PathBuf>;
1522     const ONLY_HOSTS: bool = true;
1523
1524     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1525         run.path("rustfmt")
1526     }
1527
1528     fn make_run(run: RunConfig<'_>) {
1529         run.builder.ensure(Rustfmt {
1530             compiler: run.builder.compiler_for(
1531                 run.builder.top_stage,
1532                 run.builder.config.build,
1533                 run.target,
1534             ),
1535             target: run.target,
1536         });
1537     }
1538
1539     fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
1540         let compiler = self.compiler;
1541         let target = self.target;
1542
1543         let src = builder.src.join("src/tools/rustfmt");
1544         let release_num = builder.release_num("rustfmt");
1545         let name = pkgname(builder, "rustfmt");
1546         let version = builder.rustfmt_info.version(builder, &release_num);
1547
1548         let tmp = tmpdir(builder);
1549         let image = tmp.join("rustfmt-image");
1550         drop(fs::remove_dir_all(&image));
1551         builder.create_dir(&image);
1552
1553         // Prepare the image directory
1554         let rustfmt = builder
1555             .ensure(tool::Rustfmt { compiler, target, extra_features: Vec::new() })
1556             .or_else(|| {
1557                 missing_tool("Rustfmt", builder.build.config.missing_tools);
1558                 None
1559             })?;
1560         let cargofmt = builder
1561             .ensure(tool::Cargofmt { compiler, target, extra_features: Vec::new() })
1562             .or_else(|| {
1563                 missing_tool("Cargofmt", builder.build.config.missing_tools);
1564                 None
1565             })?;
1566
1567         builder.install(&rustfmt, &image.join("bin"), 0o755);
1568         builder.install(&cargofmt, &image.join("bin"), 0o755);
1569         let doc = image.join("share/doc/rustfmt");
1570         builder.install(&src.join("README.md"), &doc, 0o644);
1571         builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
1572         builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1573
1574         // Prepare the overlay
1575         let overlay = tmp.join("rustfmt-overlay");
1576         drop(fs::remove_dir_all(&overlay));
1577         builder.create_dir(&overlay);
1578         builder.install(&src.join("README.md"), &overlay, 0o644);
1579         builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
1580         builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
1581         builder.create(&overlay.join("version"), &version);
1582
1583         // Generate the installer tarball
1584         let mut cmd = rust_installer(builder);
1585         cmd.arg("generate")
1586             .arg("--product-name=Rust")
1587             .arg("--rel-manifest-dir=rustlib")
1588             .arg("--success-message=rustfmt-ready-to-fmt.")
1589             .arg("--image-dir")
1590             .arg(&image)
1591             .arg("--work-dir")
1592             .arg(&tmpdir(builder))
1593             .arg("--output-dir")
1594             .arg(&distdir(builder))
1595             .arg("--non-installed-overlay")
1596             .arg(&overlay)
1597             .arg(format!("--package-name={}-{}", name, target))
1598             .arg("--legacy-manifest-dirs=rustlib,cargo")
1599             .arg("--component-name=rustfmt-preview");
1600
1601         builder.info(&format!("Dist Rustfmt stage{} ({})", compiler.stage, target));
1602         let _time = timeit(builder);
1603         builder.run(&mut cmd);
1604         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
1605     }
1606 }
1607
1608 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1609 pub struct Extended {
1610     stage: u32,
1611     host: Interned<String>,
1612     target: Interned<String>,
1613 }
1614
1615 impl Step for Extended {
1616     type Output = ();
1617     const DEFAULT: bool = true;
1618     const ONLY_HOSTS: bool = true;
1619
1620     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1621         let builder = run.builder;
1622         run.path("extended").default_condition(builder.config.extended)
1623     }
1624
1625     fn make_run(run: RunConfig<'_>) {
1626         run.builder.ensure(Extended {
1627             stage: run.builder.top_stage,
1628             host: run.builder.config.build,
1629             target: run.target,
1630         });
1631     }
1632
1633     /// Creates a combined installer for the specified target in the provided stage.
1634     fn run(self, builder: &Builder<'_>) {
1635         let target = self.target;
1636         let stage = self.stage;
1637         let compiler = builder.compiler_for(self.stage, self.host, self.target);
1638
1639         builder.info(&format!("Dist extended stage{} ({})", compiler.stage, target));
1640
1641         let rustc_installer = builder.ensure(Rustc { compiler: builder.compiler(stage, target) });
1642         let cargo_installer = builder.ensure(Cargo { compiler, target });
1643         let rustfmt_installer = builder.ensure(Rustfmt { compiler, target });
1644         let rls_installer = builder.ensure(Rls { compiler, target });
1645         let llvm_tools_installer = builder.ensure(LlvmTools { target });
1646         let clippy_installer = builder.ensure(Clippy { compiler, target });
1647         let miri_installer = builder.ensure(Miri { compiler, target });
1648         let lldb_installer = builder.ensure(Lldb { target });
1649         let mingw_installer = builder.ensure(Mingw { host: target });
1650         let analysis_installer = builder.ensure(Analysis { compiler, target });
1651
1652         let docs_installer = builder.ensure(Docs { host: target });
1653         let std_installer =
1654             builder.ensure(Std { compiler: builder.compiler(stage, target), target });
1655
1656         let tmp = tmpdir(builder);
1657         let overlay = tmp.join("extended-overlay");
1658         let etc = builder.src.join("src/etc/installer");
1659         let work = tmp.join("work");
1660
1661         let _ = fs::remove_dir_all(&overlay);
1662         builder.install(&builder.src.join("COPYRIGHT"), &overlay, 0o644);
1663         builder.install(&builder.src.join("LICENSE-APACHE"), &overlay, 0o644);
1664         builder.install(&builder.src.join("LICENSE-MIT"), &overlay, 0o644);
1665         let version = builder.rust_version();
1666         builder.create(&overlay.join("version"), &version);
1667         if let Some(sha) = builder.rust_sha() {
1668             builder.create(&overlay.join("git-commit-hash"), &sha);
1669         }
1670         builder.install(&etc.join("README.md"), &overlay, 0o644);
1671
1672         // When rust-std package split from rustc, we needed to ensure that during
1673         // upgrades rustc was upgraded before rust-std. To avoid rustc clobbering
1674         // the std files during uninstall. To do this ensure that rustc comes
1675         // before rust-std in the list below.
1676         let mut tarballs = Vec::new();
1677         tarballs.push(rustc_installer);
1678         tarballs.push(cargo_installer);
1679         tarballs.extend(rls_installer.clone());
1680         tarballs.extend(clippy_installer.clone());
1681         tarballs.extend(miri_installer.clone());
1682         tarballs.extend(rustfmt_installer.clone());
1683         tarballs.extend(llvm_tools_installer);
1684         tarballs.extend(lldb_installer);
1685         tarballs.push(analysis_installer);
1686         tarballs.push(std_installer);
1687         if builder.config.docs {
1688             tarballs.push(docs_installer);
1689         }
1690         if target.contains("pc-windows-gnu") {
1691             tarballs.push(mingw_installer.unwrap());
1692         }
1693         let mut input_tarballs = tarballs[0].as_os_str().to_owned();
1694         for tarball in &tarballs[1..] {
1695             input_tarballs.push(",");
1696             input_tarballs.push(tarball);
1697         }
1698
1699         builder.info("building combined installer");
1700         let mut cmd = rust_installer(builder);
1701         cmd.arg("combine")
1702             .arg("--product-name=Rust")
1703             .arg("--rel-manifest-dir=rustlib")
1704             .arg("--success-message=Rust-is-ready-to-roll.")
1705             .arg("--work-dir")
1706             .arg(&work)
1707             .arg("--output-dir")
1708             .arg(&distdir(builder))
1709             .arg(format!("--package-name={}-{}", pkgname(builder, "rust"), target))
1710             .arg("--legacy-manifest-dirs=rustlib,cargo")
1711             .arg("--input-tarballs")
1712             .arg(input_tarballs)
1713             .arg("--non-installed-overlay")
1714             .arg(&overlay);
1715         let time = timeit(&builder);
1716         builder.run(&mut cmd);
1717         drop(time);
1718
1719         let mut license = String::new();
1720         license += &builder.read(&builder.src.join("COPYRIGHT"));
1721         license += &builder.read(&builder.src.join("LICENSE-APACHE"));
1722         license += &builder.read(&builder.src.join("LICENSE-MIT"));
1723         license.push_str("\n");
1724         license.push_str("\n");
1725
1726         let rtf = r"{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Arial;}}\nowwrap\fs18";
1727         let mut rtf = rtf.to_string();
1728         rtf.push_str("\n");
1729         for line in license.lines() {
1730             rtf.push_str(line);
1731             rtf.push_str("\\line ");
1732         }
1733         rtf.push_str("}");
1734
1735         fn filter(contents: &str, marker: &str) -> String {
1736             let start = format!("tool-{}-start", marker);
1737             let end = format!("tool-{}-end", marker);
1738             let mut lines = Vec::new();
1739             let mut omitted = false;
1740             for line in contents.lines() {
1741                 if line.contains(&start) {
1742                     omitted = true;
1743                 } else if line.contains(&end) {
1744                     omitted = false;
1745                 } else if !omitted {
1746                     lines.push(line);
1747                 }
1748             }
1749
1750             lines.join("\n")
1751         }
1752
1753         let xform = |p: &Path| {
1754             let mut contents = t!(fs::read_to_string(p));
1755             if rls_installer.is_none() {
1756                 contents = filter(&contents, "rls");
1757             }
1758             if clippy_installer.is_none() {
1759                 contents = filter(&contents, "clippy");
1760             }
1761             if miri_installer.is_none() {
1762                 contents = filter(&contents, "miri");
1763             }
1764             if rustfmt_installer.is_none() {
1765                 contents = filter(&contents, "rustfmt");
1766             }
1767             let ret = tmp.join(p.file_name().unwrap());
1768             t!(fs::write(&ret, &contents));
1769             ret
1770         };
1771
1772         if target.contains("apple-darwin") {
1773             builder.info("building pkg installer");
1774             let pkg = tmp.join("pkg");
1775             let _ = fs::remove_dir_all(&pkg);
1776
1777             let pkgbuild = |component: &str| {
1778                 let mut cmd = Command::new("pkgbuild");
1779                 cmd.arg("--identifier")
1780                     .arg(format!("org.rust-lang.{}", component))
1781                     .arg("--scripts")
1782                     .arg(pkg.join(component))
1783                     .arg("--nopayload")
1784                     .arg(pkg.join(component).with_extension("pkg"));
1785                 builder.run(&mut cmd);
1786             };
1787
1788             let prepare = |name: &str| {
1789                 builder.create_dir(&pkg.join(name));
1790                 builder.cp_r(
1791                     &work.join(&format!("{}-{}", pkgname(builder, name), target)),
1792                     &pkg.join(name),
1793                 );
1794                 builder.install(&etc.join("pkg/postinstall"), &pkg.join(name), 0o755);
1795                 pkgbuild(name);
1796             };
1797             prepare("rustc");
1798             prepare("cargo");
1799             prepare("rust-docs");
1800             prepare("rust-std");
1801             prepare("rust-analysis");
1802
1803             if rls_installer.is_some() {
1804                 prepare("rls");
1805             }
1806             if clippy_installer.is_some() {
1807                 prepare("clippy");
1808             }
1809             if miri_installer.is_some() {
1810                 prepare("miri");
1811             }
1812
1813             // create an 'uninstall' package
1814             builder.install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), 0o755);
1815             pkgbuild("uninstall");
1816
1817             builder.create_dir(&pkg.join("res"));
1818             builder.create(&pkg.join("res/LICENSE.txt"), &license);
1819             builder.install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644);
1820             let mut cmd = Command::new("productbuild");
1821             cmd.arg("--distribution")
1822                 .arg(xform(&etc.join("pkg/Distribution.xml")))
1823                 .arg("--resources")
1824                 .arg(pkg.join("res"))
1825                 .arg(distdir(builder).join(format!("{}-{}.pkg", pkgname(builder, "rust"), target)))
1826                 .arg("--package-path")
1827                 .arg(&pkg);
1828             let _time = timeit(builder);
1829             builder.run(&mut cmd);
1830         }
1831
1832         if target.contains("windows") {
1833             let exe = tmp.join("exe");
1834             let _ = fs::remove_dir_all(&exe);
1835
1836             let prepare = |name: &str| {
1837                 builder.create_dir(&exe.join(name));
1838                 let dir = if name == "rust-std" || name == "rust-analysis" {
1839                     format!("{}-{}", name, target)
1840                 } else if name == "rls" {
1841                     "rls-preview".to_string()
1842                 } else if name == "clippy" {
1843                     "clippy-preview".to_string()
1844                 } else if name == "miri" {
1845                     "miri-preview".to_string()
1846                 } else {
1847                     name.to_string()
1848                 };
1849                 builder.cp_r(
1850                     &work.join(&format!("{}-{}", pkgname(builder, name), target)).join(dir),
1851                     &exe.join(name),
1852                 );
1853                 builder.remove(&exe.join(name).join("manifest.in"));
1854             };
1855             prepare("rustc");
1856             prepare("cargo");
1857             prepare("rust-analysis");
1858             prepare("rust-docs");
1859             prepare("rust-std");
1860             if rls_installer.is_some() {
1861                 prepare("rls");
1862             }
1863             if clippy_installer.is_some() {
1864                 prepare("clippy");
1865             }
1866             if miri_installer.is_some() {
1867                 prepare("miri");
1868             }
1869             if target.contains("windows-gnu") {
1870                 prepare("rust-mingw");
1871             }
1872
1873             builder.install(&xform(&etc.join("exe/rust.iss")), &exe, 0o644);
1874             builder.install(&etc.join("exe/modpath.iss"), &exe, 0o644);
1875             builder.install(&etc.join("exe/upgrade.iss"), &exe, 0o644);
1876             builder.install(&etc.join("gfx/rust-logo.ico"), &exe, 0o644);
1877             builder.create(&exe.join("LICENSE.txt"), &license);
1878
1879             // Generate exe installer
1880             builder.info("building `exe` installer with `iscc`");
1881             let mut cmd = Command::new("iscc");
1882             cmd.arg("rust.iss").arg("/Q").current_dir(&exe);
1883             if target.contains("windows-gnu") {
1884                 cmd.arg("/dMINGW");
1885             }
1886             add_env(builder, &mut cmd, target);
1887             let time = timeit(builder);
1888             builder.run(&mut cmd);
1889             drop(time);
1890             builder.install(
1891                 &exe.join(format!("{}-{}.exe", pkgname(builder, "rust"), target)),
1892                 &distdir(builder),
1893                 0o755,
1894             );
1895
1896             // Generate msi installer
1897             let wix = PathBuf::from(env::var_os("WIX").unwrap());
1898             let heat = wix.join("bin/heat.exe");
1899             let candle = wix.join("bin/candle.exe");
1900             let light = wix.join("bin/light.exe");
1901
1902             let heat_flags = ["-nologo", "-gg", "-sfrag", "-srd", "-sreg"];
1903             builder.run(
1904                 Command::new(&heat)
1905                     .current_dir(&exe)
1906                     .arg("dir")
1907                     .arg("rustc")
1908                     .args(&heat_flags)
1909                     .arg("-cg")
1910                     .arg("RustcGroup")
1911                     .arg("-dr")
1912                     .arg("Rustc")
1913                     .arg("-var")
1914                     .arg("var.RustcDir")
1915                     .arg("-out")
1916                     .arg(exe.join("RustcGroup.wxs")),
1917             );
1918             builder.run(
1919                 Command::new(&heat)
1920                     .current_dir(&exe)
1921                     .arg("dir")
1922                     .arg("rust-docs")
1923                     .args(&heat_flags)
1924                     .arg("-cg")
1925                     .arg("DocsGroup")
1926                     .arg("-dr")
1927                     .arg("Docs")
1928                     .arg("-var")
1929                     .arg("var.DocsDir")
1930                     .arg("-out")
1931                     .arg(exe.join("DocsGroup.wxs"))
1932                     .arg("-t")
1933                     .arg(etc.join("msi/squash-components.xsl")),
1934             );
1935             builder.run(
1936                 Command::new(&heat)
1937                     .current_dir(&exe)
1938                     .arg("dir")
1939                     .arg("cargo")
1940                     .args(&heat_flags)
1941                     .arg("-cg")
1942                     .arg("CargoGroup")
1943                     .arg("-dr")
1944                     .arg("Cargo")
1945                     .arg("-var")
1946                     .arg("var.CargoDir")
1947                     .arg("-out")
1948                     .arg(exe.join("CargoGroup.wxs"))
1949                     .arg("-t")
1950                     .arg(etc.join("msi/remove-duplicates.xsl")),
1951             );
1952             builder.run(
1953                 Command::new(&heat)
1954                     .current_dir(&exe)
1955                     .arg("dir")
1956                     .arg("rust-std")
1957                     .args(&heat_flags)
1958                     .arg("-cg")
1959                     .arg("StdGroup")
1960                     .arg("-dr")
1961                     .arg("Std")
1962                     .arg("-var")
1963                     .arg("var.StdDir")
1964                     .arg("-out")
1965                     .arg(exe.join("StdGroup.wxs")),
1966             );
1967             if rls_installer.is_some() {
1968                 builder.run(
1969                     Command::new(&heat)
1970                         .current_dir(&exe)
1971                         .arg("dir")
1972                         .arg("rls")
1973                         .args(&heat_flags)
1974                         .arg("-cg")
1975                         .arg("RlsGroup")
1976                         .arg("-dr")
1977                         .arg("Rls")
1978                         .arg("-var")
1979                         .arg("var.RlsDir")
1980                         .arg("-out")
1981                         .arg(exe.join("RlsGroup.wxs"))
1982                         .arg("-t")
1983                         .arg(etc.join("msi/remove-duplicates.xsl")),
1984                 );
1985             }
1986             if clippy_installer.is_some() {
1987                 builder.run(
1988                     Command::new(&heat)
1989                         .current_dir(&exe)
1990                         .arg("dir")
1991                         .arg("clippy")
1992                         .args(&heat_flags)
1993                         .arg("-cg")
1994                         .arg("ClippyGroup")
1995                         .arg("-dr")
1996                         .arg("Clippy")
1997                         .arg("-var")
1998                         .arg("var.ClippyDir")
1999                         .arg("-out")
2000                         .arg(exe.join("ClippyGroup.wxs"))
2001                         .arg("-t")
2002                         .arg(etc.join("msi/remove-duplicates.xsl")),
2003                 );
2004             }
2005             if miri_installer.is_some() {
2006                 builder.run(
2007                     Command::new(&heat)
2008                         .current_dir(&exe)
2009                         .arg("dir")
2010                         .arg("miri")
2011                         .args(&heat_flags)
2012                         .arg("-cg")
2013                         .arg("MiriGroup")
2014                         .arg("-dr")
2015                         .arg("Miri")
2016                         .arg("-var")
2017                         .arg("var.MiriDir")
2018                         .arg("-out")
2019                         .arg(exe.join("MiriGroup.wxs"))
2020                         .arg("-t")
2021                         .arg(etc.join("msi/remove-duplicates.xsl")),
2022                 );
2023             }
2024             builder.run(
2025                 Command::new(&heat)
2026                     .current_dir(&exe)
2027                     .arg("dir")
2028                     .arg("rust-analysis")
2029                     .args(&heat_flags)
2030                     .arg("-cg")
2031                     .arg("AnalysisGroup")
2032                     .arg("-dr")
2033                     .arg("Analysis")
2034                     .arg("-var")
2035                     .arg("var.AnalysisDir")
2036                     .arg("-out")
2037                     .arg(exe.join("AnalysisGroup.wxs"))
2038                     .arg("-t")
2039                     .arg(etc.join("msi/remove-duplicates.xsl")),
2040             );
2041             if target.contains("windows-gnu") {
2042                 builder.run(
2043                     Command::new(&heat)
2044                         .current_dir(&exe)
2045                         .arg("dir")
2046                         .arg("rust-mingw")
2047                         .args(&heat_flags)
2048                         .arg("-cg")
2049                         .arg("GccGroup")
2050                         .arg("-dr")
2051                         .arg("Gcc")
2052                         .arg("-var")
2053                         .arg("var.GccDir")
2054                         .arg("-out")
2055                         .arg(exe.join("GccGroup.wxs")),
2056                 );
2057             }
2058
2059             let candle = |input: &Path| {
2060                 let output = exe.join(input.file_stem().unwrap()).with_extension("wixobj");
2061                 let arch = if target.contains("x86_64") { "x64" } else { "x86" };
2062                 let mut cmd = Command::new(&candle);
2063                 cmd.current_dir(&exe)
2064                     .arg("-nologo")
2065                     .arg("-dRustcDir=rustc")
2066                     .arg("-dDocsDir=rust-docs")
2067                     .arg("-dCargoDir=cargo")
2068                     .arg("-dStdDir=rust-std")
2069                     .arg("-dAnalysisDir=rust-analysis")
2070                     .arg("-arch")
2071                     .arg(&arch)
2072                     .arg("-out")
2073                     .arg(&output)
2074                     .arg(&input);
2075                 add_env(builder, &mut cmd, target);
2076
2077                 if rls_installer.is_some() {
2078                     cmd.arg("-dRlsDir=rls");
2079                 }
2080                 if clippy_installer.is_some() {
2081                     cmd.arg("-dClippyDir=clippy");
2082                 }
2083                 if miri_installer.is_some() {
2084                     cmd.arg("-dMiriDir=miri");
2085                 }
2086                 if target.contains("windows-gnu") {
2087                     cmd.arg("-dGccDir=rust-mingw");
2088                 }
2089                 builder.run(&mut cmd);
2090             };
2091             candle(&xform(&etc.join("msi/rust.wxs")));
2092             candle(&etc.join("msi/ui.wxs"));
2093             candle(&etc.join("msi/rustwelcomedlg.wxs"));
2094             candle("RustcGroup.wxs".as_ref());
2095             candle("DocsGroup.wxs".as_ref());
2096             candle("CargoGroup.wxs".as_ref());
2097             candle("StdGroup.wxs".as_ref());
2098             if rls_installer.is_some() {
2099                 candle("RlsGroup.wxs".as_ref());
2100             }
2101             if clippy_installer.is_some() {
2102                 candle("ClippyGroup.wxs".as_ref());
2103             }
2104             if miri_installer.is_some() {
2105                 candle("MiriGroup.wxs".as_ref());
2106             }
2107             candle("AnalysisGroup.wxs".as_ref());
2108
2109             if target.contains("windows-gnu") {
2110                 candle("GccGroup.wxs".as_ref());
2111             }
2112
2113             builder.create(&exe.join("LICENSE.rtf"), &rtf);
2114             builder.install(&etc.join("gfx/banner.bmp"), &exe, 0o644);
2115             builder.install(&etc.join("gfx/dialogbg.bmp"), &exe, 0o644);
2116
2117             builder.info(&format!("building `msi` installer with {:?}", light));
2118             let filename = format!("{}-{}.msi", pkgname(builder, "rust"), target);
2119             let mut cmd = Command::new(&light);
2120             cmd.arg("-nologo")
2121                 .arg("-ext")
2122                 .arg("WixUIExtension")
2123                 .arg("-ext")
2124                 .arg("WixUtilExtension")
2125                 .arg("-out")
2126                 .arg(exe.join(&filename))
2127                 .arg("rust.wixobj")
2128                 .arg("ui.wixobj")
2129                 .arg("rustwelcomedlg.wixobj")
2130                 .arg("RustcGroup.wixobj")
2131                 .arg("DocsGroup.wixobj")
2132                 .arg("CargoGroup.wixobj")
2133                 .arg("StdGroup.wixobj")
2134                 .arg("AnalysisGroup.wixobj")
2135                 .current_dir(&exe);
2136
2137             if rls_installer.is_some() {
2138                 cmd.arg("RlsGroup.wixobj");
2139             }
2140             if clippy_installer.is_some() {
2141                 cmd.arg("ClippyGroup.wixobj");
2142             }
2143             if miri_installer.is_some() {
2144                 cmd.arg("MiriGroup.wixobj");
2145             }
2146
2147             if target.contains("windows-gnu") {
2148                 cmd.arg("GccGroup.wixobj");
2149             }
2150             // ICE57 wrongly complains about the shortcuts
2151             cmd.arg("-sice:ICE57");
2152
2153             let _time = timeit(builder);
2154             builder.run(&mut cmd);
2155
2156             if !builder.config.dry_run {
2157                 t!(fs::rename(exe.join(&filename), distdir(builder).join(&filename)));
2158             }
2159         }
2160     }
2161 }
2162
2163 fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: Interned<String>) {
2164     let mut parts = channel::CFG_RELEASE_NUM.split('.');
2165     cmd.env("CFG_RELEASE_INFO", builder.rust_version())
2166         .env("CFG_RELEASE_NUM", channel::CFG_RELEASE_NUM)
2167         .env("CFG_RELEASE", builder.rust_release())
2168         .env("CFG_VER_MAJOR", parts.next().unwrap())
2169         .env("CFG_VER_MINOR", parts.next().unwrap())
2170         .env("CFG_VER_PATCH", parts.next().unwrap())
2171         .env("CFG_VER_BUILD", "0") // just needed to build
2172         .env("CFG_PACKAGE_VERS", builder.rust_package_vers())
2173         .env("CFG_PACKAGE_NAME", pkgname(builder, "rust"))
2174         .env("CFG_BUILD", target)
2175         .env("CFG_CHANNEL", &builder.config.channel);
2176
2177     if target.contains("windows-gnu") {
2178         cmd.env("CFG_MINGW", "1").env("CFG_ABI", "GNU");
2179     } else {
2180         cmd.env("CFG_MINGW", "0").env("CFG_ABI", "MSVC");
2181     }
2182
2183     if target.contains("x86_64") {
2184         cmd.env("CFG_PLATFORM", "x64");
2185     } else {
2186         cmd.env("CFG_PLATFORM", "x86");
2187     }
2188 }
2189
2190 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
2191 pub struct HashSign;
2192
2193 impl Step for HashSign {
2194     type Output = ();
2195     const ONLY_HOSTS: bool = true;
2196
2197     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2198         run.path("hash-and-sign")
2199     }
2200
2201     fn make_run(run: RunConfig<'_>) {
2202         run.builder.ensure(HashSign);
2203     }
2204
2205     fn run(self, builder: &Builder<'_>) {
2206         // This gets called by `promote-release`
2207         // (https://github.com/rust-lang/rust-central-station/tree/master/promote-release).
2208         let mut cmd = builder.tool_cmd(Tool::BuildManifest);
2209         if builder.config.dry_run {
2210             return;
2211         }
2212         let sign = builder.config.dist_sign_folder.as_ref().unwrap_or_else(|| {
2213             panic!("\n\nfailed to specify `dist.sign-folder` in `config.toml`\n\n")
2214         });
2215         let addr = builder.config.dist_upload_addr.as_ref().unwrap_or_else(|| {
2216             panic!("\n\nfailed to specify `dist.upload-addr` in `config.toml`\n\n")
2217         });
2218         let pass = if env::var("BUILD_MANIFEST_DISABLE_SIGNING").is_err() {
2219             let file = builder.config.dist_gpg_password_file.as_ref().unwrap_or_else(|| {
2220                 panic!("\n\nfailed to specify `dist.gpg-password-file` in `config.toml`\n\n")
2221             });
2222             t!(fs::read_to_string(&file))
2223         } else {
2224             String::new()
2225         };
2226
2227         let today = output(Command::new("date").arg("+%Y-%m-%d"));
2228
2229         cmd.arg(sign);
2230         cmd.arg(distdir(builder));
2231         cmd.arg(today.trim());
2232         cmd.arg(builder.rust_package_vers());
2233         cmd.arg(addr);
2234         cmd.arg(builder.package_vers(&builder.release_num("cargo")));
2235         cmd.arg(builder.package_vers(&builder.release_num("rls")));
2236         cmd.arg(builder.package_vers(&builder.release_num("clippy")));
2237         cmd.arg(builder.package_vers(&builder.release_num("miri")));
2238         cmd.arg(builder.package_vers(&builder.release_num("rustfmt")));
2239         cmd.arg(builder.llvm_tools_package_vers());
2240         cmd.arg(builder.lldb_package_vers());
2241
2242         builder.create_dir(&distdir(builder));
2243
2244         let mut child = t!(cmd.stdin(Stdio::piped()).spawn());
2245         t!(child.stdin.take().unwrap().write_all(pass.as_bytes()));
2246         let status = t!(child.wait());
2247         assert!(status.success());
2248     }
2249 }
2250
2251 // Maybe add libLLVM.so to the lib-dir. It will only have been built if
2252 // LLVM tools are linked dynamically.
2253 //
2254 // We add this to both the libdir of the rustc binary itself (for it to load at
2255 // runtime) and also to the target directory so it can find it at link-time.
2256 //
2257 // Note: This function does no yet support Windows but we also don't support
2258 //       linking LLVM tools dynamically on Windows yet.
2259 pub fn maybe_install_llvm_dylib(builder: &Builder<'_>, target: Interned<String>, sysroot: &Path) {
2260     let src_libdir = builder.llvm_out(target).join("lib");
2261     let dst_libdir1 = sysroot.join("lib/rustlib").join(&*target).join("lib");
2262     let dst_libdir2 =
2263         sysroot.join(builder.sysroot_libdir_relative(Compiler { stage: 1, host: target }));
2264     t!(fs::create_dir_all(&dst_libdir1));
2265     t!(fs::create_dir_all(&dst_libdir2));
2266
2267     if target.contains("apple-darwin") {
2268         let llvm_dylib_path = src_libdir.join("libLLVM.dylib");
2269         if llvm_dylib_path.exists() {
2270             builder.install(&llvm_dylib_path, &dst_libdir1, 0o644);
2271             builder.install(&llvm_dylib_path, &dst_libdir2, 0o644);
2272         }
2273         return;
2274     }
2275
2276     // Usually libLLVM.so is a symlink to something like libLLVM-6.0.so.
2277     // Since tools link to the latter rather than the former, we have to
2278     // follow the symlink to find out what to distribute.
2279     let llvm_dylib_path = src_libdir.join("libLLVM.so");
2280     if llvm_dylib_path.exists() {
2281         let llvm_dylib_path = llvm_dylib_path.canonicalize().unwrap_or_else(|e| {
2282             panic!("dist: Error calling canonicalize path `{}`: {}", llvm_dylib_path.display(), e);
2283         });
2284
2285         builder.install(&llvm_dylib_path, &dst_libdir1, 0o644);
2286         builder.install(&llvm_dylib_path, &dst_libdir2, 0o644);
2287     }
2288 }
2289
2290 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
2291 pub struct LlvmTools {
2292     pub target: Interned<String>,
2293 }
2294
2295 impl Step for LlvmTools {
2296     type Output = Option<PathBuf>;
2297     const ONLY_HOSTS: bool = true;
2298
2299     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2300         run.path("llvm-tools")
2301     }
2302
2303     fn make_run(run: RunConfig<'_>) {
2304         run.builder.ensure(LlvmTools { target: run.target });
2305     }
2306
2307     fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
2308         let target = self.target;
2309         assert!(builder.config.extended);
2310
2311         /* run only if llvm-config isn't used */
2312         if let Some(config) = builder.config.target_config.get(&target) {
2313             if let Some(ref _s) = config.llvm_config {
2314                 builder.info(&format!("Skipping LlvmTools ({}): external LLVM", target));
2315                 return None;
2316             }
2317         }
2318
2319         builder.info(&format!("Dist LlvmTools ({})", target));
2320         let _time = timeit(builder);
2321         let src = builder.src.join("src/llvm-project/llvm");
2322         let name = pkgname(builder, "llvm-tools");
2323
2324         let tmp = tmpdir(builder);
2325         let image = tmp.join("llvm-tools-image");
2326         drop(fs::remove_dir_all(&image));
2327
2328         // Prepare the image directory
2329         let src_bindir = builder.llvm_out(target).join("bin");
2330         let dst_bindir = image.join("lib/rustlib").join(&*target).join("bin");
2331         t!(fs::create_dir_all(&dst_bindir));
2332         for tool in LLVM_TOOLS {
2333             let exe = src_bindir.join(exe(tool, &target));
2334             builder.install(&exe, &dst_bindir, 0o755);
2335         }
2336
2337         // Prepare the overlay
2338         let overlay = tmp.join("llvm-tools-overlay");
2339         drop(fs::remove_dir_all(&overlay));
2340         builder.create_dir(&overlay);
2341         builder.install(&src.join("README.txt"), &overlay, 0o644);
2342         builder.install(&src.join("LICENSE.TXT"), &overlay, 0o644);
2343         builder.create(&overlay.join("version"), &builder.llvm_tools_vers());
2344
2345         // Generate the installer tarball
2346         let mut cmd = rust_installer(builder);
2347         cmd.arg("generate")
2348             .arg("--product-name=Rust")
2349             .arg("--rel-manifest-dir=rustlib")
2350             .arg("--success-message=llvm-tools-installed.")
2351             .arg("--image-dir")
2352             .arg(&image)
2353             .arg("--work-dir")
2354             .arg(&tmpdir(builder))
2355             .arg("--output-dir")
2356             .arg(&distdir(builder))
2357             .arg("--non-installed-overlay")
2358             .arg(&overlay)
2359             .arg(format!("--package-name={}-{}", name, target))
2360             .arg("--legacy-manifest-dirs=rustlib,cargo")
2361             .arg("--component-name=llvm-tools-preview");
2362
2363         builder.run(&mut cmd);
2364         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
2365     }
2366 }
2367
2368 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
2369 pub struct Lldb {
2370     pub target: Interned<String>,
2371 }
2372
2373 impl Step for Lldb {
2374     type Output = Option<PathBuf>;
2375     const ONLY_HOSTS: bool = true;
2376     const DEFAULT: bool = true;
2377
2378     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2379         run.path("src/llvm-project/lldb").path("src/tools/lldb")
2380     }
2381
2382     fn make_run(run: RunConfig<'_>) {
2383         run.builder.ensure(Lldb { target: run.target });
2384     }
2385
2386     fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
2387         let target = self.target;
2388
2389         if builder.config.dry_run {
2390             return None;
2391         }
2392
2393         let bindir = builder.llvm_out(target).join("bin");
2394         let lldb_exe = bindir.join(exe("lldb", &target));
2395         if !lldb_exe.exists() {
2396             return None;
2397         }
2398
2399         builder.info(&format!("Dist Lldb ({})", target));
2400         let src = builder.src.join("src/llvm-project/lldb");
2401         let name = pkgname(builder, "lldb");
2402
2403         let tmp = tmpdir(builder);
2404         let image = tmp.join("lldb-image");
2405         drop(fs::remove_dir_all(&image));
2406
2407         // Prepare the image directory
2408         let root = image.join("lib/rustlib").join(&*target);
2409         let dst = root.join("bin");
2410         t!(fs::create_dir_all(&dst));
2411         for program in &["lldb", "lldb-argdumper", "lldb-mi", "lldb-server"] {
2412             let exe = bindir.join(exe(program, &target));
2413             builder.install(&exe, &dst, 0o755);
2414         }
2415
2416         // The libraries.
2417         let libdir = builder.llvm_out(target).join("lib");
2418         let dst = root.join("lib");
2419         t!(fs::create_dir_all(&dst));
2420         for entry in t!(fs::read_dir(&libdir)) {
2421             let entry = entry.unwrap();
2422             if let Ok(name) = entry.file_name().into_string() {
2423                 if name.starts_with("liblldb.") && !name.ends_with(".a") {
2424                     if t!(entry.file_type()).is_symlink() {
2425                         builder.copy_to_folder(&entry.path(), &dst);
2426                     } else {
2427                         builder.install(&entry.path(), &dst, 0o755);
2428                     }
2429                 }
2430             }
2431         }
2432
2433         // The lldb scripts might be installed in lib/python$version
2434         // or in lib64/python$version.  If lib64 exists, use it;
2435         // otherwise lib.
2436         let libdir = builder.llvm_out(target).join("lib64");
2437         let (libdir, libdir_name) = if libdir.exists() {
2438             (libdir, "lib64")
2439         } else {
2440             (builder.llvm_out(target).join("lib"), "lib")
2441         };
2442         for entry in t!(fs::read_dir(&libdir)) {
2443             let entry = t!(entry);
2444             if let Ok(name) = entry.file_name().into_string() {
2445                 if name.starts_with("python") {
2446                     let dst = root.join(libdir_name).join(entry.file_name());
2447                     t!(fs::create_dir_all(&dst));
2448                     builder.cp_r(&entry.path(), &dst);
2449                     break;
2450                 }
2451             }
2452         }
2453
2454         // Prepare the overlay
2455         let overlay = tmp.join("lldb-overlay");
2456         drop(fs::remove_dir_all(&overlay));
2457         builder.create_dir(&overlay);
2458         builder.install(&src.join("LICENSE.TXT"), &overlay, 0o644);
2459         builder.create(&overlay.join("version"), &builder.lldb_vers());
2460
2461         // Generate the installer tarball
2462         let mut cmd = rust_installer(builder);
2463         cmd.arg("generate")
2464             .arg("--product-name=Rust")
2465             .arg("--rel-manifest-dir=rustlib")
2466             .arg("--success-message=lldb-installed.")
2467             .arg("--image-dir")
2468             .arg(&image)
2469             .arg("--work-dir")
2470             .arg(&tmpdir(builder))
2471             .arg("--output-dir")
2472             .arg(&distdir(builder))
2473             .arg("--non-installed-overlay")
2474             .arg(&overlay)
2475             .arg(format!("--package-name={}-{}", name, target))
2476             .arg("--legacy-manifest-dirs=rustlib,cargo")
2477             .arg("--component-name=lldb-preview");
2478
2479         builder.run(&mut cmd);
2480         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
2481     }
2482 }