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