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