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