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