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