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