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