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