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