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