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