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