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