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