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