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