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