]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/dist.rs
Rollup merge of #106797 - FawazTirmizi:dev/issues/104284, r=bjorn3
[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         if target.contains("riscv64") {
1134             // riscv64 currently has an LLVM bug that makes rust-analyzer unable
1135             // to build. See #74813 for details.
1136             return None;
1137         }
1138
1139         let rust_analyzer = builder
1140             .ensure(tool::RustAnalyzer { compiler, target })
1141             .expect("rust-analyzer always builds");
1142
1143         let mut tarball = Tarball::new(builder, "rust-analyzer", &target.triple);
1144         tarball.set_overlay(OverlayKind::RustAnalyzer);
1145         tarball.is_preview(true);
1146         tarball.add_file(rust_analyzer, "bin", 0o755);
1147         tarball.add_legal_and_readme_to("share/doc/rust-analyzer");
1148         Some(tarball.generate())
1149     }
1150 }
1151
1152 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1153 pub struct Clippy {
1154     pub compiler: Compiler,
1155     pub target: TargetSelection,
1156 }
1157
1158 impl Step for Clippy {
1159     type Output = Option<GeneratedTarball>;
1160     const DEFAULT: bool = true;
1161     const ONLY_HOSTS: bool = true;
1162
1163     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1164         let default = should_build_extended_tool(&run.builder, "clippy");
1165         run.alias("clippy").default_condition(default)
1166     }
1167
1168     fn make_run(run: RunConfig<'_>) {
1169         run.builder.ensure(Clippy {
1170             compiler: run.builder.compiler_for(
1171                 run.builder.top_stage,
1172                 run.builder.config.build,
1173                 run.target,
1174             ),
1175             target: run.target,
1176         });
1177     }
1178
1179     fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1180         let compiler = self.compiler;
1181         let target = self.target;
1182
1183         // Prepare the image directory
1184         // We expect clippy to build, because we've exited this step above if tool
1185         // state for clippy isn't testing.
1186         let clippy = builder
1187             .ensure(tool::Clippy { compiler, target, extra_features: Vec::new() })
1188             .expect("clippy expected to build - essential tool");
1189         let cargoclippy = builder
1190             .ensure(tool::CargoClippy { compiler, target, extra_features: Vec::new() })
1191             .expect("clippy expected to build - essential tool");
1192
1193         let mut tarball = Tarball::new(builder, "clippy", &target.triple);
1194         tarball.set_overlay(OverlayKind::Clippy);
1195         tarball.is_preview(true);
1196         tarball.add_file(clippy, "bin", 0o755);
1197         tarball.add_file(cargoclippy, "bin", 0o755);
1198         tarball.add_legal_and_readme_to("share/doc/clippy");
1199         Some(tarball.generate())
1200     }
1201 }
1202
1203 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1204 pub struct Miri {
1205     pub compiler: Compiler,
1206     pub target: TargetSelection,
1207 }
1208
1209 impl Step for Miri {
1210     type Output = Option<GeneratedTarball>;
1211     const DEFAULT: bool = true;
1212     const ONLY_HOSTS: bool = true;
1213
1214     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1215         let default = should_build_extended_tool(&run.builder, "miri");
1216         run.alias("miri").default_condition(default)
1217     }
1218
1219     fn make_run(run: RunConfig<'_>) {
1220         run.builder.ensure(Miri {
1221             compiler: run.builder.compiler_for(
1222                 run.builder.top_stage,
1223                 run.builder.config.build,
1224                 run.target,
1225             ),
1226             target: run.target,
1227         });
1228     }
1229
1230     fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1231         // This prevents miri from being built for "dist" or "install"
1232         // on the stable/beta channels. It is a nightly-only tool and should
1233         // not be included.
1234         if !builder.build.unstable_features() {
1235             return None;
1236         }
1237         let compiler = self.compiler;
1238         let target = self.target;
1239
1240         let miri = builder.ensure(tool::Miri { compiler, target, extra_features: Vec::new() })?;
1241         let cargomiri =
1242             builder.ensure(tool::CargoMiri { compiler, target, extra_features: Vec::new() })?;
1243
1244         let mut tarball = Tarball::new(builder, "miri", &target.triple);
1245         tarball.set_overlay(OverlayKind::Miri);
1246         tarball.is_preview(true);
1247         tarball.add_file(miri, "bin", 0o755);
1248         tarball.add_file(cargomiri, "bin", 0o755);
1249         tarball.add_legal_and_readme_to("share/doc/miri");
1250         Some(tarball.generate())
1251     }
1252 }
1253
1254 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1255 pub struct Rustfmt {
1256     pub compiler: Compiler,
1257     pub target: TargetSelection,
1258 }
1259
1260 impl Step for Rustfmt {
1261     type Output = Option<GeneratedTarball>;
1262     const DEFAULT: bool = true;
1263     const ONLY_HOSTS: bool = true;
1264
1265     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1266         let default = should_build_extended_tool(&run.builder, "rustfmt");
1267         run.alias("rustfmt").default_condition(default)
1268     }
1269
1270     fn make_run(run: RunConfig<'_>) {
1271         run.builder.ensure(Rustfmt {
1272             compiler: run.builder.compiler_for(
1273                 run.builder.top_stage,
1274                 run.builder.config.build,
1275                 run.target,
1276             ),
1277             target: run.target,
1278         });
1279     }
1280
1281     fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1282         let compiler = self.compiler;
1283         let target = self.target;
1284
1285         let rustfmt = builder
1286             .ensure(tool::Rustfmt { compiler, target, extra_features: Vec::new() })
1287             .expect("rustfmt expected to build - essential tool");
1288         let cargofmt = builder
1289             .ensure(tool::Cargofmt { compiler, target, extra_features: Vec::new() })
1290             .expect("cargo fmt expected to build - essential tool");
1291         let mut tarball = Tarball::new(builder, "rustfmt", &target.triple);
1292         tarball.set_overlay(OverlayKind::Rustfmt);
1293         tarball.is_preview(true);
1294         tarball.add_file(rustfmt, "bin", 0o755);
1295         tarball.add_file(cargofmt, "bin", 0o755);
1296         tarball.add_legal_and_readme_to("share/doc/rustfmt");
1297         Some(tarball.generate())
1298     }
1299 }
1300
1301 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1302 pub struct RustDemangler {
1303     pub compiler: Compiler,
1304     pub target: TargetSelection,
1305 }
1306
1307 impl Step for RustDemangler {
1308     type Output = Option<GeneratedTarball>;
1309     const DEFAULT: bool = true;
1310     const ONLY_HOSTS: bool = true;
1311
1312     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1313         // While other tools use `should_build_extended_tool` to decide whether to be run by
1314         // default or not, `rust-demangler` must be build when *either* it's enabled as a tool like
1315         // the other ones or if `profiler = true`. Because we don't know the target at this stage
1316         // we run the step by default when only `extended = true`, and decide whether to actually
1317         // run it or not later.
1318         let default = run.builder.config.extended;
1319         run.alias("rust-demangler").default_condition(default)
1320     }
1321
1322     fn make_run(run: RunConfig<'_>) {
1323         run.builder.ensure(RustDemangler {
1324             compiler: run.builder.compiler_for(
1325                 run.builder.top_stage,
1326                 run.builder.config.build,
1327                 run.target,
1328             ),
1329             target: run.target,
1330         });
1331     }
1332
1333     fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1334         let compiler = self.compiler;
1335         let target = self.target;
1336
1337         // Only build this extended tool if explicitly included in `tools`, or if `profiler = true`
1338         let condition = should_build_extended_tool(builder, "rust-demangler")
1339             || builder.config.profiler_enabled(target);
1340         if builder.config.extended && !condition {
1341             return None;
1342         }
1343
1344         let rust_demangler = builder
1345             .ensure(tool::RustDemangler { compiler, target, extra_features: Vec::new() })
1346             .expect("rust-demangler expected to build - in-tree tool");
1347
1348         // Prepare the image directory
1349         let mut tarball = Tarball::new(builder, "rust-demangler", &target.triple);
1350         tarball.set_overlay(OverlayKind::RustDemangler);
1351         tarball.is_preview(true);
1352         tarball.add_file(&rust_demangler, "bin", 0o755);
1353         tarball.add_legal_and_readme_to("share/doc/rust-demangler");
1354         Some(tarball.generate())
1355     }
1356 }
1357
1358 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1359 pub struct Extended {
1360     stage: u32,
1361     host: TargetSelection,
1362     target: TargetSelection,
1363 }
1364
1365 impl Step for Extended {
1366     type Output = ();
1367     const DEFAULT: bool = true;
1368     const ONLY_HOSTS: bool = true;
1369
1370     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1371         let builder = run.builder;
1372         run.alias("extended").default_condition(builder.config.extended)
1373     }
1374
1375     fn make_run(run: RunConfig<'_>) {
1376         run.builder.ensure(Extended {
1377             stage: run.builder.top_stage,
1378             host: run.builder.config.build,
1379             target: run.target,
1380         });
1381     }
1382
1383     /// Creates a combined installer for the specified target in the provided stage.
1384     fn run(self, builder: &Builder<'_>) {
1385         let target = self.target;
1386         let stage = self.stage;
1387         let compiler = builder.compiler_for(self.stage, self.host, self.target);
1388
1389         builder.info(&format!("Dist extended stage{} ({})", compiler.stage, target));
1390
1391         let mut tarballs = Vec::new();
1392         let mut built_tools = HashSet::new();
1393         macro_rules! add_component {
1394             ($name:expr => $step:expr) => {
1395                 if let Some(tarball) = builder.ensure_if_default($step, Kind::Dist) {
1396                     tarballs.push(tarball);
1397                     built_tools.insert($name);
1398                 }
1399             };
1400         }
1401
1402         // When rust-std package split from rustc, we needed to ensure that during
1403         // upgrades rustc was upgraded before rust-std. To avoid rustc clobbering
1404         // the std files during uninstall. To do this ensure that rustc comes
1405         // before rust-std in the list below.
1406         tarballs.push(builder.ensure(Rustc { compiler: builder.compiler(stage, target) }));
1407         tarballs.push(builder.ensure(Std { compiler, target }).expect("missing std"));
1408
1409         if target.ends_with("windows-gnu") {
1410             tarballs.push(builder.ensure(Mingw { host: target }).expect("missing mingw"));
1411         }
1412
1413         add_component!("rust-docs" => Docs { host: target });
1414         add_component!("rust-json-docs" => JsonDocs { host: target });
1415         add_component!("rust-demangler"=> RustDemangler { compiler, target });
1416         add_component!("cargo" => Cargo { compiler, target });
1417         add_component!("rustfmt" => Rustfmt { compiler, target });
1418         add_component!("rls" => Rls { compiler, target });
1419         add_component!("rust-analyzer" => RustAnalyzer { compiler, target });
1420         add_component!("llvm-components" => LlvmTools { target });
1421         add_component!("clippy" => Clippy { compiler, target });
1422         add_component!("miri" => Miri { compiler, target });
1423         add_component!("analysis" => Analysis { compiler, target });
1424
1425         let etc = builder.src.join("src/etc/installer");
1426
1427         // Avoid producing tarballs during a dry run.
1428         if builder.config.dry_run() {
1429             return;
1430         }
1431
1432         let tarball = Tarball::new(builder, "rust", &target.triple);
1433         let generated = tarball.combine(&tarballs);
1434
1435         let tmp = tmpdir(builder).join("combined-tarball");
1436         let work = generated.work_dir();
1437
1438         let mut license = String::new();
1439         license += &builder.read(&builder.src.join("COPYRIGHT"));
1440         license += &builder.read(&builder.src.join("LICENSE-APACHE"));
1441         license += &builder.read(&builder.src.join("LICENSE-MIT"));
1442         license.push('\n');
1443         license.push('\n');
1444
1445         let rtf = r"{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Arial;}}\nowwrap\fs18";
1446         let mut rtf = rtf.to_string();
1447         rtf.push('\n');
1448         for line in license.lines() {
1449             rtf.push_str(line);
1450             rtf.push_str("\\line ");
1451         }
1452         rtf.push('}');
1453
1454         fn filter(contents: &str, marker: &str) -> String {
1455             let start = format!("tool-{}-start", marker);
1456             let end = format!("tool-{}-end", marker);
1457             let mut lines = Vec::new();
1458             let mut omitted = false;
1459             for line in contents.lines() {
1460                 if line.contains(&start) {
1461                     omitted = true;
1462                 } else if line.contains(&end) {
1463                     omitted = false;
1464                 } else if !omitted {
1465                     lines.push(line);
1466                 }
1467             }
1468
1469             lines.join("\n")
1470         }
1471
1472         let xform = |p: &Path| {
1473             let mut contents = t!(fs::read_to_string(p));
1474             for tool in &["rust-demangler", "miri"] {
1475                 if !built_tools.contains(tool) {
1476                     contents = filter(&contents, tool);
1477                 }
1478             }
1479             let ret = tmp.join(p.file_name().unwrap());
1480             t!(fs::write(&ret, &contents));
1481             ret
1482         };
1483
1484         if target.contains("apple-darwin") {
1485             builder.info("building pkg installer");
1486             let pkg = tmp.join("pkg");
1487             let _ = fs::remove_dir_all(&pkg);
1488
1489             let pkgbuild = |component: &str| {
1490                 let mut cmd = Command::new("pkgbuild");
1491                 cmd.arg("--identifier")
1492                     .arg(format!("org.rust-lang.{}", component))
1493                     .arg("--scripts")
1494                     .arg(pkg.join(component))
1495                     .arg("--nopayload")
1496                     .arg(pkg.join(component).with_extension("pkg"));
1497                 builder.run(&mut cmd);
1498             };
1499
1500             let prepare = |name: &str| {
1501                 builder.create_dir(&pkg.join(name));
1502                 builder.cp_r(
1503                     &work.join(&format!("{}-{}", pkgname(builder, name), target.triple)),
1504                     &pkg.join(name),
1505                 );
1506                 builder.install(&etc.join("pkg/postinstall"), &pkg.join(name), 0o755);
1507                 pkgbuild(name);
1508             };
1509             prepare("rustc");
1510             prepare("cargo");
1511             prepare("rust-std");
1512             prepare("rust-analysis");
1513             prepare("clippy");
1514             prepare("rust-analyzer");
1515             for tool in &["rust-docs", "rust-demangler", "miri"] {
1516                 if built_tools.contains(tool) {
1517                     prepare(tool);
1518                 }
1519             }
1520             // create an 'uninstall' package
1521             builder.install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), 0o755);
1522             pkgbuild("uninstall");
1523
1524             builder.create_dir(&pkg.join("res"));
1525             builder.create(&pkg.join("res/LICENSE.txt"), &license);
1526             builder.install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644);
1527             let mut cmd = Command::new("productbuild");
1528             cmd.arg("--distribution")
1529                 .arg(xform(&etc.join("pkg/Distribution.xml")))
1530                 .arg("--resources")
1531                 .arg(pkg.join("res"))
1532                 .arg(distdir(builder).join(format!(
1533                     "{}-{}.pkg",
1534                     pkgname(builder, "rust"),
1535                     target.triple
1536                 )))
1537                 .arg("--package-path")
1538                 .arg(&pkg);
1539             let _time = timeit(builder);
1540             builder.run(&mut cmd);
1541         }
1542
1543         if target.contains("windows") {
1544             let exe = tmp.join("exe");
1545             let _ = fs::remove_dir_all(&exe);
1546
1547             let prepare = |name: &str| {
1548                 builder.create_dir(&exe.join(name));
1549                 let dir = if name == "rust-std" || name == "rust-analysis" {
1550                     format!("{}-{}", name, target.triple)
1551                 } else if name == "rust-analyzer" {
1552                     "rust-analyzer-preview".to_string()
1553                 } else if name == "clippy" {
1554                     "clippy-preview".to_string()
1555                 } else if name == "rust-demangler" {
1556                     "rust-demangler-preview".to_string()
1557                 } else if name == "miri" {
1558                     "miri-preview".to_string()
1559                 } else {
1560                     name.to_string()
1561                 };
1562                 builder.cp_r(
1563                     &work.join(&format!("{}-{}", pkgname(builder, name), target.triple)).join(dir),
1564                     &exe.join(name),
1565                 );
1566                 builder.remove(&exe.join(name).join("manifest.in"));
1567             };
1568             prepare("rustc");
1569             prepare("cargo");
1570             prepare("rust-analysis");
1571             prepare("rust-docs");
1572             prepare("rust-std");
1573             prepare("clippy");
1574             prepare("rust-analyzer");
1575             for tool in &["rust-demangler", "miri"] {
1576                 if built_tools.contains(tool) {
1577                     prepare(tool);
1578                 }
1579             }
1580             if target.ends_with("windows-gnu") {
1581                 prepare("rust-mingw");
1582             }
1583
1584             builder.install(&etc.join("gfx/rust-logo.ico"), &exe, 0o644);
1585
1586             // Generate msi installer
1587             let wix_path = env::var_os("WIX")
1588                 .expect("`WIX` environment variable must be set for generating MSI installer(s).");
1589             let wix = PathBuf::from(wix_path);
1590             let heat = wix.join("bin/heat.exe");
1591             let candle = wix.join("bin/candle.exe");
1592             let light = wix.join("bin/light.exe");
1593
1594             let heat_flags = ["-nologo", "-gg", "-sfrag", "-srd", "-sreg"];
1595             builder.run(
1596                 Command::new(&heat)
1597                     .current_dir(&exe)
1598                     .arg("dir")
1599                     .arg("rustc")
1600                     .args(&heat_flags)
1601                     .arg("-cg")
1602                     .arg("RustcGroup")
1603                     .arg("-dr")
1604                     .arg("Rustc")
1605                     .arg("-var")
1606                     .arg("var.RustcDir")
1607                     .arg("-out")
1608                     .arg(exe.join("RustcGroup.wxs")),
1609             );
1610             builder.run(
1611                 Command::new(&heat)
1612                     .current_dir(&exe)
1613                     .arg("dir")
1614                     .arg("rust-docs")
1615                     .args(&heat_flags)
1616                     .arg("-cg")
1617                     .arg("DocsGroup")
1618                     .arg("-dr")
1619                     .arg("Docs")
1620                     .arg("-var")
1621                     .arg("var.DocsDir")
1622                     .arg("-out")
1623                     .arg(exe.join("DocsGroup.wxs"))
1624                     .arg("-t")
1625                     .arg(etc.join("msi/squash-components.xsl")),
1626             );
1627             builder.run(
1628                 Command::new(&heat)
1629                     .current_dir(&exe)
1630                     .arg("dir")
1631                     .arg("cargo")
1632                     .args(&heat_flags)
1633                     .arg("-cg")
1634                     .arg("CargoGroup")
1635                     .arg("-dr")
1636                     .arg("Cargo")
1637                     .arg("-var")
1638                     .arg("var.CargoDir")
1639                     .arg("-out")
1640                     .arg(exe.join("CargoGroup.wxs"))
1641                     .arg("-t")
1642                     .arg(etc.join("msi/remove-duplicates.xsl")),
1643             );
1644             builder.run(
1645                 Command::new(&heat)
1646                     .current_dir(&exe)
1647                     .arg("dir")
1648                     .arg("rust-std")
1649                     .args(&heat_flags)
1650                     .arg("-cg")
1651                     .arg("StdGroup")
1652                     .arg("-dr")
1653                     .arg("Std")
1654                     .arg("-var")
1655                     .arg("var.StdDir")
1656                     .arg("-out")
1657                     .arg(exe.join("StdGroup.wxs")),
1658             );
1659             builder.run(
1660                 Command::new(&heat)
1661                     .current_dir(&exe)
1662                     .arg("dir")
1663                     .arg("rust-analyzer")
1664                     .args(&heat_flags)
1665                     .arg("-cg")
1666                     .arg("RustAnalyzerGroup")
1667                     .arg("-dr")
1668                     .arg("RustAnalyzer")
1669                     .arg("-var")
1670                     .arg("var.RustAnalyzerDir")
1671                     .arg("-out")
1672                     .arg(exe.join("RustAnalyzerGroup.wxs"))
1673                     .arg("-t")
1674                     .arg(etc.join("msi/remove-duplicates.xsl")),
1675             );
1676             builder.run(
1677                 Command::new(&heat)
1678                     .current_dir(&exe)
1679                     .arg("dir")
1680                     .arg("clippy")
1681                     .args(&heat_flags)
1682                     .arg("-cg")
1683                     .arg("ClippyGroup")
1684                     .arg("-dr")
1685                     .arg("Clippy")
1686                     .arg("-var")
1687                     .arg("var.ClippyDir")
1688                     .arg("-out")
1689                     .arg(exe.join("ClippyGroup.wxs"))
1690                     .arg("-t")
1691                     .arg(etc.join("msi/remove-duplicates.xsl")),
1692             );
1693             if built_tools.contains("rust-demangler") {
1694                 builder.run(
1695                     Command::new(&heat)
1696                         .current_dir(&exe)
1697                         .arg("dir")
1698                         .arg("rust-demangler")
1699                         .args(&heat_flags)
1700                         .arg("-cg")
1701                         .arg("RustDemanglerGroup")
1702                         .arg("-dr")
1703                         .arg("RustDemangler")
1704                         .arg("-var")
1705                         .arg("var.RustDemanglerDir")
1706                         .arg("-out")
1707                         .arg(exe.join("RustDemanglerGroup.wxs"))
1708                         .arg("-t")
1709                         .arg(etc.join("msi/remove-duplicates.xsl")),
1710                 );
1711             }
1712             if built_tools.contains("miri") {
1713                 builder.run(
1714                     Command::new(&heat)
1715                         .current_dir(&exe)
1716                         .arg("dir")
1717                         .arg("miri")
1718                         .args(&heat_flags)
1719                         .arg("-cg")
1720                         .arg("MiriGroup")
1721                         .arg("-dr")
1722                         .arg("Miri")
1723                         .arg("-var")
1724                         .arg("var.MiriDir")
1725                         .arg("-out")
1726                         .arg(exe.join("MiriGroup.wxs"))
1727                         .arg("-t")
1728                         .arg(etc.join("msi/remove-duplicates.xsl")),
1729                 );
1730             }
1731             builder.run(
1732                 Command::new(&heat)
1733                     .current_dir(&exe)
1734                     .arg("dir")
1735                     .arg("rust-analysis")
1736                     .args(&heat_flags)
1737                     .arg("-cg")
1738                     .arg("AnalysisGroup")
1739                     .arg("-dr")
1740                     .arg("Analysis")
1741                     .arg("-var")
1742                     .arg("var.AnalysisDir")
1743                     .arg("-out")
1744                     .arg(exe.join("AnalysisGroup.wxs"))
1745                     .arg("-t")
1746                     .arg(etc.join("msi/remove-duplicates.xsl")),
1747             );
1748             if target.ends_with("windows-gnu") {
1749                 builder.run(
1750                     Command::new(&heat)
1751                         .current_dir(&exe)
1752                         .arg("dir")
1753                         .arg("rust-mingw")
1754                         .args(&heat_flags)
1755                         .arg("-cg")
1756                         .arg("GccGroup")
1757                         .arg("-dr")
1758                         .arg("Gcc")
1759                         .arg("-var")
1760                         .arg("var.GccDir")
1761                         .arg("-out")
1762                         .arg(exe.join("GccGroup.wxs")),
1763                 );
1764             }
1765
1766             let candle = |input: &Path| {
1767                 let output = exe.join(input.file_stem().unwrap()).with_extension("wixobj");
1768                 let arch = if target.contains("x86_64") { "x64" } else { "x86" };
1769                 let mut cmd = Command::new(&candle);
1770                 cmd.current_dir(&exe)
1771                     .arg("-nologo")
1772                     .arg("-dRustcDir=rustc")
1773                     .arg("-dDocsDir=rust-docs")
1774                     .arg("-dCargoDir=cargo")
1775                     .arg("-dStdDir=rust-std")
1776                     .arg("-dAnalysisDir=rust-analysis")
1777                     .arg("-dClippyDir=clippy")
1778                     .arg("-arch")
1779                     .arg(&arch)
1780                     .arg("-out")
1781                     .arg(&output)
1782                     .arg(&input);
1783                 add_env(builder, &mut cmd, target);
1784
1785                 if built_tools.contains("rust-demangler") {
1786                     cmd.arg("-dRustDemanglerDir=rust-demangler");
1787                 }
1788                 if built_tools.contains("rust-analyzer") {
1789                     cmd.arg("-dRustAnalyzerDir=rust-analyzer");
1790                 }
1791                 if built_tools.contains("miri") {
1792                     cmd.arg("-dMiriDir=miri");
1793                 }
1794                 if target.ends_with("windows-gnu") {
1795                     cmd.arg("-dGccDir=rust-mingw");
1796                 }
1797                 builder.run(&mut cmd);
1798             };
1799             candle(&xform(&etc.join("msi/rust.wxs")));
1800             candle(&etc.join("msi/ui.wxs"));
1801             candle(&etc.join("msi/rustwelcomedlg.wxs"));
1802             candle("RustcGroup.wxs".as_ref());
1803             candle("DocsGroup.wxs".as_ref());
1804             candle("CargoGroup.wxs".as_ref());
1805             candle("StdGroup.wxs".as_ref());
1806             candle("ClippyGroup.wxs".as_ref());
1807             if built_tools.contains("miri") {
1808                 candle("MiriGroup.wxs".as_ref());
1809             }
1810             if built_tools.contains("rust-demangler") {
1811                 candle("RustDemanglerGroup.wxs".as_ref());
1812             }
1813             if built_tools.contains("rust-analyzer") {
1814                 candle("RustAnalyzerGroup.wxs".as_ref());
1815             }
1816             candle("AnalysisGroup.wxs".as_ref());
1817
1818             if target.ends_with("windows-gnu") {
1819                 candle("GccGroup.wxs".as_ref());
1820             }
1821
1822             builder.create(&exe.join("LICENSE.rtf"), &rtf);
1823             builder.install(&etc.join("gfx/banner.bmp"), &exe, 0o644);
1824             builder.install(&etc.join("gfx/dialogbg.bmp"), &exe, 0o644);
1825
1826             builder.info(&format!("building `msi` installer with {:?}", light));
1827             let filename = format!("{}-{}.msi", pkgname(builder, "rust"), target.triple);
1828             let mut cmd = Command::new(&light);
1829             cmd.arg("-nologo")
1830                 .arg("-ext")
1831                 .arg("WixUIExtension")
1832                 .arg("-ext")
1833                 .arg("WixUtilExtension")
1834                 .arg("-out")
1835                 .arg(exe.join(&filename))
1836                 .arg("rust.wixobj")
1837                 .arg("ui.wixobj")
1838                 .arg("rustwelcomedlg.wixobj")
1839                 .arg("RustcGroup.wixobj")
1840                 .arg("DocsGroup.wixobj")
1841                 .arg("CargoGroup.wixobj")
1842                 .arg("StdGroup.wixobj")
1843                 .arg("AnalysisGroup.wixobj")
1844                 .arg("ClippyGroup.wixobj")
1845                 .current_dir(&exe);
1846
1847             if built_tools.contains("miri") {
1848                 cmd.arg("MiriGroup.wixobj");
1849             }
1850             if built_tools.contains("rust-analyzer") {
1851                 cmd.arg("RustAnalyzerGroup.wixobj");
1852             }
1853             if built_tools.contains("rust-demangler") {
1854                 cmd.arg("RustDemanglerGroup.wixobj");
1855             }
1856
1857             if target.ends_with("windows-gnu") {
1858                 cmd.arg("GccGroup.wixobj");
1859             }
1860             // ICE57 wrongly complains about the shortcuts
1861             cmd.arg("-sice:ICE57");
1862
1863             let _time = timeit(builder);
1864             builder.run(&mut cmd);
1865
1866             if !builder.config.dry_run() {
1867                 t!(fs::rename(exe.join(&filename), distdir(builder).join(&filename)));
1868             }
1869         }
1870     }
1871 }
1872
1873 fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: TargetSelection) {
1874     let mut parts = builder.version.split('.');
1875     cmd.env("CFG_RELEASE_INFO", builder.rust_version())
1876         .env("CFG_RELEASE_NUM", &builder.version)
1877         .env("CFG_RELEASE", builder.rust_release())
1878         .env("CFG_VER_MAJOR", parts.next().unwrap())
1879         .env("CFG_VER_MINOR", parts.next().unwrap())
1880         .env("CFG_VER_PATCH", parts.next().unwrap())
1881         .env("CFG_VER_BUILD", "0") // just needed to build
1882         .env("CFG_PACKAGE_VERS", builder.rust_package_vers())
1883         .env("CFG_PACKAGE_NAME", pkgname(builder, "rust"))
1884         .env("CFG_BUILD", target.triple)
1885         .env("CFG_CHANNEL", &builder.config.channel);
1886
1887     if target.contains("windows-gnullvm") {
1888         cmd.env("CFG_MINGW", "1").env("CFG_ABI", "LLVM");
1889     } else if target.contains("windows-gnu") {
1890         cmd.env("CFG_MINGW", "1").env("CFG_ABI", "GNU");
1891     } else {
1892         cmd.env("CFG_MINGW", "0").env("CFG_ABI", "MSVC");
1893     }
1894 }
1895
1896 /// Maybe add LLVM object files to the given destination lib-dir. Allows either static or dynamic linking.
1897 ///
1898 /// Returns whether the files were actually copied.
1899 fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir: &Path) -> bool {
1900     if let Some(config) = builder.config.target_config.get(&target) {
1901         if config.llvm_config.is_some() && !builder.config.llvm_from_ci {
1902             // If the LLVM was externally provided, then we don't currently copy
1903             // artifacts into the sysroot. This is not necessarily the right
1904             // choice (in particular, it will require the LLVM dylib to be in
1905             // the linker's load path at runtime), but the common use case for
1906             // external LLVMs is distribution provided LLVMs, and in that case
1907             // they're usually in the standard search path (e.g., /usr/lib) and
1908             // copying them here is going to cause problems as we may end up
1909             // with the wrong files and isn't what distributions want.
1910             //
1911             // This behavior may be revisited in the future though.
1912             //
1913             // If the LLVM is coming from ourselves (just from CI) though, we
1914             // still want to install it, as it otherwise won't be available.
1915             return false;
1916         }
1917     }
1918
1919     // On macOS, rustc (and LLVM tools) link to an unversioned libLLVM.dylib
1920     // instead of libLLVM-11-rust-....dylib, as on linux. It's not entirely
1921     // clear why this is the case, though. llvm-config will emit the versioned
1922     // paths and we don't want those in the sysroot (as we're expecting
1923     // unversioned paths).
1924     if target.contains("apple-darwin") && builder.llvm_link_shared() {
1925         let src_libdir = builder.llvm_out(target).join("lib");
1926         let llvm_dylib_path = src_libdir.join("libLLVM.dylib");
1927         if llvm_dylib_path.exists() {
1928             builder.install(&llvm_dylib_path, dst_libdir, 0o644);
1929         }
1930         !builder.config.dry_run()
1931     } else if let Ok(native::LlvmResult { llvm_config, .. }) =
1932         native::prebuilt_llvm_config(builder, target)
1933     {
1934         let mut cmd = Command::new(llvm_config);
1935         cmd.arg("--libfiles");
1936         builder.verbose(&format!("running {:?}", cmd));
1937         let files = if builder.config.dry_run() { "".into() } else { output(&mut cmd) };
1938         let build_llvm_out = &builder.llvm_out(builder.config.build);
1939         let target_llvm_out = &builder.llvm_out(target);
1940         for file in files.trim_end().split(' ') {
1941             // If we're not using a custom LLVM, make sure we package for the target.
1942             let file = if let Ok(relative_path) = Path::new(file).strip_prefix(build_llvm_out) {
1943                 target_llvm_out.join(relative_path)
1944             } else {
1945                 PathBuf::from(file)
1946             };
1947             builder.install(&file, dst_libdir, 0o644);
1948         }
1949         !builder.config.dry_run()
1950     } else {
1951         false
1952     }
1953 }
1954
1955 /// Maybe add libLLVM.so to the target lib-dir for linking.
1956 pub fn maybe_install_llvm_target(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) {
1957     let dst_libdir = sysroot.join("lib/rustlib").join(&*target.triple).join("lib");
1958     // We do not need to copy LLVM files into the sysroot if it is not
1959     // dynamically linked; it is already included into librustc_llvm
1960     // statically.
1961     if builder.llvm_link_shared() {
1962         maybe_install_llvm(builder, target, &dst_libdir);
1963     }
1964 }
1965
1966 /// Maybe add libLLVM.so to the runtime lib-dir for rustc itself.
1967 pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) {
1968     let dst_libdir =
1969         sysroot.join(builder.sysroot_libdir_relative(Compiler { stage: 1, host: target }));
1970     // We do not need to copy LLVM files into the sysroot if it is not
1971     // dynamically linked; it is already included into librustc_llvm
1972     // statically.
1973     if builder.llvm_link_shared() {
1974         maybe_install_llvm(builder, target, &dst_libdir);
1975     }
1976 }
1977
1978 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1979 pub struct LlvmTools {
1980     pub target: TargetSelection,
1981 }
1982
1983 impl Step for LlvmTools {
1984     type Output = Option<GeneratedTarball>;
1985     const ONLY_HOSTS: bool = true;
1986     const DEFAULT: bool = true;
1987
1988     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1989         let default = should_build_extended_tool(&run.builder, "llvm-tools");
1990         // FIXME: allow using the names of the tools themselves?
1991         run.alias("llvm-tools").default_condition(default)
1992     }
1993
1994     fn make_run(run: RunConfig<'_>) {
1995         run.builder.ensure(LlvmTools { target: run.target });
1996     }
1997
1998     fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
1999         let target = self.target;
2000
2001         /* run only if llvm-config isn't used */
2002         if let Some(config) = builder.config.target_config.get(&target) {
2003             if let Some(ref _s) = config.llvm_config {
2004                 builder.info(&format!("Skipping LlvmTools ({}): external LLVM", target));
2005                 return None;
2006             }
2007         }
2008
2009         builder.ensure(crate::native::Llvm { target });
2010
2011         let mut tarball = Tarball::new(builder, "llvm-tools", &target.triple);
2012         tarball.set_overlay(OverlayKind::LLVM);
2013         tarball.is_preview(true);
2014
2015         // Prepare the image directory
2016         let src_bindir = builder.llvm_out(target).join("bin");
2017         let dst_bindir = format!("lib/rustlib/{}/bin", target.triple);
2018         for tool in LLVM_TOOLS {
2019             let exe = src_bindir.join(exe(tool, target));
2020             tarball.add_file(&exe, &dst_bindir, 0o755);
2021         }
2022
2023         // Copy libLLVM.so to the target lib dir as well, so the RPATH like
2024         // `$ORIGIN/../lib` can find it. It may also be used as a dependency
2025         // of `rustc-dev` to support the inherited `-lLLVM` when using the
2026         // compiler libraries.
2027         maybe_install_llvm_target(builder, target, tarball.image_dir());
2028
2029         Some(tarball.generate())
2030     }
2031 }
2032
2033 // Tarball intended for internal consumption to ease rustc/std development.
2034 //
2035 // Should not be considered stable by end users.
2036 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
2037 pub struct RustDev {
2038     pub target: TargetSelection,
2039 }
2040
2041 impl Step for RustDev {
2042     type Output = Option<GeneratedTarball>;
2043     const DEFAULT: bool = true;
2044     const ONLY_HOSTS: bool = true;
2045
2046     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2047         run.alias("rust-dev")
2048     }
2049
2050     fn make_run(run: RunConfig<'_>) {
2051         run.builder.ensure(RustDev { target: run.target });
2052     }
2053
2054     fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2055         let target = self.target;
2056
2057         /* run only if llvm-config isn't used */
2058         if let Some(config) = builder.config.target_config.get(&target) {
2059             if let Some(ref _s) = config.llvm_config {
2060                 builder.info(&format!("Skipping RustDev ({}): external LLVM", target));
2061                 return None;
2062             }
2063         }
2064
2065         let mut tarball = Tarball::new(builder, "rust-dev", &target.triple);
2066         tarball.set_overlay(OverlayKind::LLVM);
2067
2068         builder.ensure(crate::native::Llvm { target });
2069
2070         // We want to package `lld` to use it with `download-ci-llvm`.
2071         builder.ensure(crate::native::Lld { target });
2072
2073         let src_bindir = builder.llvm_out(target).join("bin");
2074         // If updating this list, you likely want to change
2075         // src/bootstrap/download-ci-llvm-stamp as well, otherwise local users
2076         // will not pick up the extra file until LLVM gets bumped.
2077         for bin in &[
2078             "llvm-config",
2079             "llvm-ar",
2080             "llvm-objdump",
2081             "llvm-profdata",
2082             "llvm-bcanalyzer",
2083             "llvm-cov",
2084             "llvm-dwp",
2085             "llvm-nm",
2086             "llvm-dwarfdump",
2087             "llvm-dis",
2088             "llvm-tblgen",
2089         ] {
2090             tarball.add_file(src_bindir.join(exe(bin, target)), "bin", 0o755);
2091         }
2092
2093         // We don't build LLD on some platforms, so only add it if it exists
2094         let lld_path = builder.lld_out(target).join("bin").join(exe("lld", target));
2095         if lld_path.exists() {
2096             tarball.add_file(lld_path, "bin", 0o755);
2097         }
2098
2099         tarball.add_file(&builder.llvm_filecheck(target), "bin", 0o755);
2100
2101         // Copy the include directory as well; needed mostly to build
2102         // librustc_llvm properly (e.g., llvm-config.h is in here). But also
2103         // just broadly useful to be able to link against the bundled LLVM.
2104         tarball.add_dir(&builder.llvm_out(target).join("include"), "include");
2105
2106         // Copy libLLVM.so to the target lib dir as well, so the RPATH like
2107         // `$ORIGIN/../lib` can find it. It may also be used as a dependency
2108         // of `rustc-dev` to support the inherited `-lLLVM` when using the
2109         // compiler libraries.
2110         let dst_libdir = tarball.image_dir().join("lib");
2111         maybe_install_llvm(builder, target, &dst_libdir);
2112         let link_type = if builder.llvm_link_shared() { "dynamic" } else { "static" };
2113         t!(std::fs::write(tarball.image_dir().join("link-type.txt"), link_type), dst_libdir);
2114
2115         Some(tarball.generate())
2116     }
2117 }
2118
2119 // Tarball intended for internal consumption to ease rustc/std development.
2120 //
2121 // Should not be considered stable by end users.
2122 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
2123 pub struct Bootstrap {
2124     pub target: TargetSelection,
2125 }
2126
2127 impl Step for Bootstrap {
2128     type Output = Option<GeneratedTarball>;
2129     const DEFAULT: bool = false;
2130     const ONLY_HOSTS: bool = true;
2131
2132     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2133         run.alias("bootstrap")
2134     }
2135
2136     fn make_run(run: RunConfig<'_>) {
2137         run.builder.ensure(Bootstrap { target: run.target });
2138     }
2139
2140     fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
2141         let target = self.target;
2142
2143         let tarball = Tarball::new(builder, "bootstrap", &target.triple);
2144
2145         let bootstrap_outdir = &builder.bootstrap_out;
2146         for file in &["bootstrap", "rustc", "rustdoc", "sccache-plus-cl"] {
2147             tarball.add_file(bootstrap_outdir.join(exe(file, target)), "bootstrap/bin", 0o755);
2148         }
2149
2150         Some(tarball.generate())
2151     }
2152 }
2153
2154 /// Tarball containing a prebuilt version of the build-manifest tool, intended to be used by the
2155 /// release process to avoid cloning the monorepo and building stuff.
2156 ///
2157 /// Should not be considered stable by end users.
2158 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
2159 pub struct BuildManifest {
2160     pub target: TargetSelection,
2161 }
2162
2163 impl Step for BuildManifest {
2164     type Output = GeneratedTarball;
2165     const DEFAULT: bool = false;
2166     const ONLY_HOSTS: bool = true;
2167
2168     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2169         run.alias("build-manifest")
2170     }
2171
2172     fn make_run(run: RunConfig<'_>) {
2173         run.builder.ensure(BuildManifest { target: run.target });
2174     }
2175
2176     fn run(self, builder: &Builder<'_>) -> GeneratedTarball {
2177         let build_manifest = builder.tool_exe(Tool::BuildManifest);
2178
2179         let tarball = Tarball::new(builder, "build-manifest", &self.target.triple);
2180         tarball.add_file(&build_manifest, "bin", 0o755);
2181         tarball.generate()
2182     }
2183 }
2184
2185 /// Tarball containing artifacts necessary to reproduce the build of rustc.
2186 ///
2187 /// Currently this is the PGO profile data.
2188 ///
2189 /// Should not be considered stable by end users.
2190 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
2191 pub struct ReproducibleArtifacts {
2192     pub target: TargetSelection,
2193 }
2194
2195 impl Step for ReproducibleArtifacts {
2196     type Output = Option<GeneratedTarball>;
2197     const DEFAULT: bool = true;
2198     const ONLY_HOSTS: bool = true;
2199
2200     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2201         run.alias("reproducible-artifacts")
2202     }
2203
2204     fn make_run(run: RunConfig<'_>) {
2205         run.builder.ensure(ReproducibleArtifacts { target: run.target });
2206     }
2207
2208     fn run(self, builder: &Builder<'_>) -> Self::Output {
2209         let mut added_anything = false;
2210         let tarball = Tarball::new(builder, "reproducible-artifacts", &self.target.triple);
2211         if let Some(path) = builder.config.rust_profile_use.as_ref() {
2212             tarball.add_file(path, ".", 0o644);
2213             added_anything = true;
2214         }
2215         if let Some(path) = builder.config.llvm_profile_use.as_ref() {
2216             tarball.add_file(path, ".", 0o644);
2217             added_anything = true;
2218         }
2219         if let Some(path) = builder.config.llvm_bolt_profile_use.as_ref() {
2220             tarball.add_file(path, ".", 0o644);
2221             added_anything = true;
2222         }
2223         if added_anything { Some(tarball.generate()) } else { None }
2224     }
2225 }