]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/dist.rs
Auto merge of #57006 - GuillaumeGomez:no-crate-filter, r=QuietMisdreavus
[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             let name = path.file_name().and_then(|s| s.to_str());
675             name != Some(builder.config.rust_codegen_backends_dir.as_str()) &&
676                 name != Some("bin")
677
678         });
679
680         let mut cmd = rust_installer(builder);
681         cmd.arg("generate")
682            .arg("--product-name=Rust")
683            .arg("--rel-manifest-dir=rustlib")
684            .arg("--success-message=std-is-standing-at-the-ready.")
685            .arg("--image-dir").arg(&image)
686            .arg("--work-dir").arg(&tmpdir(builder))
687            .arg("--output-dir").arg(&distdir(builder))
688            .arg(format!("--package-name={}-{}", name, target))
689            .arg(format!("--component-name=rust-std-{}", target))
690            .arg("--legacy-manifest-dirs=rustlib,cargo");
691         builder.run(&mut cmd);
692         builder.remove_dir(&image);
693         distdir(builder).join(format!("{}-{}.tar.gz", name, target))
694     }
695 }
696
697 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
698 pub struct Analysis {
699     pub compiler: Compiler,
700     pub target: Interned<String>,
701 }
702
703 impl Step for Analysis {
704     type Output = PathBuf;
705     const DEFAULT: bool = true;
706
707     fn should_run(run: ShouldRun) -> ShouldRun {
708         let builder = run.builder;
709         run.path("analysis").default_condition(builder.config.extended)
710     }
711
712     fn make_run(run: RunConfig) {
713         run.builder.ensure(Analysis {
714             compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
715             target: run.target,
716         });
717     }
718
719     /// Creates a tarball of save-analysis metadata, if available.
720     fn run(self, builder: &Builder) -> PathBuf {
721         let compiler = self.compiler;
722         let target = self.target;
723         assert!(builder.config.extended);
724         builder.info("Dist analysis");
725         let name = pkgname(builder, "rust-analysis");
726
727         if &compiler.host != builder.config.build {
728             builder.info("\tskipping, not a build host");
729             return distdir(builder).join(format!("{}-{}.tar.gz", name, target));
730         }
731
732         builder.ensure(Std { compiler, target });
733
734         // Package save-analysis from stage1 if not doing a full bootstrap, as the
735         // stage2 artifacts is simply copied from stage1 in that case.
736         let compiler = if builder.force_use_stage1(compiler, target) {
737             builder.compiler(1, compiler.host)
738         } else {
739             compiler.clone()
740         };
741
742         let image = tmpdir(builder).join(format!("{}-{}-image", name, target));
743
744         let src = builder.stage_out(compiler, Mode::Std)
745             .join(target).join(builder.cargo_dir()).join("deps");
746
747         let image_src = src.join("save-analysis");
748         let dst = image.join("lib/rustlib").join(target).join("analysis");
749         t!(fs::create_dir_all(&dst));
750         builder.info(&format!("image_src: {:?}, dst: {:?}", image_src, dst));
751         builder.cp_r(&image_src, &dst);
752
753         let mut cmd = rust_installer(builder);
754         cmd.arg("generate")
755            .arg("--product-name=Rust")
756            .arg("--rel-manifest-dir=rustlib")
757            .arg("--success-message=save-analysis-saved.")
758            .arg("--image-dir").arg(&image)
759            .arg("--work-dir").arg(&tmpdir(builder))
760            .arg("--output-dir").arg(&distdir(builder))
761            .arg(format!("--package-name={}-{}", name, target))
762            .arg(format!("--component-name=rust-analysis-{}", target))
763            .arg("--legacy-manifest-dirs=rustlib,cargo");
764         builder.run(&mut cmd);
765         builder.remove_dir(&image);
766         distdir(builder).join(format!("{}-{}.tar.gz", name, target))
767     }
768 }
769
770 fn copy_src_dirs(builder: &Builder, src_dirs: &[&str], exclude_dirs: &[&str], dst_dir: &Path) {
771     fn filter_fn(exclude_dirs: &[&str], dir: &str, path: &Path) -> bool {
772         let spath = match path.to_str() {
773             Some(path) => path,
774             None => return false,
775         };
776         if spath.ends_with("~") || spath.ends_with(".pyc") {
777             return false
778         }
779         if (spath.contains("llvm/test") || spath.contains("llvm\\test")) &&
780             (spath.ends_with(".ll") ||
781              spath.ends_with(".td") ||
782              spath.ends_with(".s")) {
783             return false
784         }
785         if spath.contains("test/emscripten") || spath.contains("test\\emscripten") {
786             return false
787         }
788
789         let full_path = Path::new(dir).join(path);
790         if exclude_dirs.iter().any(|excl| full_path == Path::new(excl)) {
791             return false;
792         }
793
794         let excludes = [
795             "CVS", "RCS", "SCCS", ".git", ".gitignore", ".gitmodules",
796             ".gitattributes", ".cvsignore", ".svn", ".arch-ids", "{arch}",
797             "=RELEASE-ID", "=meta-update", "=update", ".bzr", ".bzrignore",
798             ".bzrtags", ".hg", ".hgignore", ".hgrags", "_darcs",
799         ];
800         !path.iter()
801              .map(|s| s.to_str().unwrap())
802              .any(|s| excludes.contains(&s))
803     }
804
805     // Copy the directories using our filter
806     for item in src_dirs {
807         let dst = &dst_dir.join(item);
808         t!(fs::create_dir_all(dst));
809         builder.cp_filtered(
810             &builder.src.join(item), dst, &|path| filter_fn(exclude_dirs, item, path));
811     }
812 }
813
814 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
815 pub struct Src;
816
817 impl Step for Src {
818     /// The output path of the src installer tarball
819     type Output = PathBuf;
820     const DEFAULT: bool = true;
821     const ONLY_HOSTS: bool = true;
822
823     fn should_run(run: ShouldRun) -> ShouldRun {
824         run.path("src")
825     }
826
827     fn make_run(run: RunConfig) {
828         run.builder.ensure(Src);
829     }
830
831     /// Creates the `rust-src` installer component
832     fn run(self, builder: &Builder) -> PathBuf {
833         builder.info("Dist src");
834
835         let name = pkgname(builder, "rust-src");
836         let image = tmpdir(builder).join(format!("{}-image", name));
837         let _ = fs::remove_dir_all(&image);
838
839         let dst = image.join("lib/rustlib/src");
840         let dst_src = dst.join("rust");
841         t!(fs::create_dir_all(&dst_src));
842
843         let src_files = [
844             "Cargo.lock",
845         ];
846         // This is the reduced set of paths which will become the rust-src component
847         // (essentially libstd and all of its path dependencies)
848         let std_src_dirs = [
849             "src/build_helper",
850             "src/liballoc",
851             "src/libcore",
852             "src/libpanic_abort",
853             "src/libpanic_unwind",
854             "src/librustc_asan",
855             "src/librustc_lsan",
856             "src/librustc_msan",
857             "src/librustc_tsan",
858             "src/libstd",
859             "src/libunwind",
860             "src/libtest",
861             "src/libterm",
862             "src/libprofiler_builtins",
863             "src/stdsimd",
864             "src/libproc_macro",
865             "src/tools/rustc-std-workspace-core",
866         ];
867
868         copy_src_dirs(builder, &std_src_dirs[..], &[], &dst_src);
869         for file in src_files.iter() {
870             builder.copy(&builder.src.join(file), &dst_src.join(file));
871         }
872
873         // Create source tarball in rust-installer format
874         let mut cmd = rust_installer(builder);
875         cmd.arg("generate")
876            .arg("--product-name=Rust")
877            .arg("--rel-manifest-dir=rustlib")
878            .arg("--success-message=Awesome-Source.")
879            .arg("--image-dir").arg(&image)
880            .arg("--work-dir").arg(&tmpdir(builder))
881            .arg("--output-dir").arg(&distdir(builder))
882            .arg(format!("--package-name={}", name))
883            .arg("--component-name=rust-src")
884            .arg("--legacy-manifest-dirs=rustlib,cargo");
885         builder.run(&mut cmd);
886
887         builder.remove_dir(&image);
888         distdir(builder).join(&format!("{}.tar.gz", name))
889     }
890 }
891
892 const CARGO_VENDOR_VERSION: &str = "0.1.22";
893
894 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
895 pub struct PlainSourceTarball;
896
897 impl Step for PlainSourceTarball {
898     /// Produces the location of the tarball generated
899     type Output = PathBuf;
900     const DEFAULT: bool = true;
901     const ONLY_HOSTS: bool = true;
902
903     fn should_run(run: ShouldRun) -> ShouldRun {
904         let builder = run.builder;
905         run.path("src").default_condition(builder.config.rust_dist_src)
906     }
907
908     fn make_run(run: RunConfig) {
909         run.builder.ensure(PlainSourceTarball);
910     }
911
912     /// Creates the plain source tarball
913     fn run(self, builder: &Builder) -> PathBuf {
914         builder.info("Create plain source tarball");
915
916         // Make sure that the root folder of tarball has the correct name
917         let plain_name = format!("{}-src", pkgname(builder, "rustc"));
918         let plain_dst_src = tmpdir(builder).join(&plain_name);
919         let _ = fs::remove_dir_all(&plain_dst_src);
920         t!(fs::create_dir_all(&plain_dst_src));
921
922         // This is the set of root paths which will become part of the source package
923         let src_files = [
924             "COPYRIGHT",
925             "LICENSE-APACHE",
926             "LICENSE-MIT",
927             "CONTRIBUTING.md",
928             "README.md",
929             "RELEASES.md",
930             "configure",
931             "x.py",
932             "config.toml.example",
933             "Cargo.toml",
934             "Cargo.lock",
935         ];
936         let src_dirs = [
937             "src",
938         ];
939
940         copy_src_dirs(builder, &src_dirs[..], &[], &plain_dst_src);
941
942         // Copy the files normally
943         for item in &src_files {
944             builder.copy(&builder.src.join(item), &plain_dst_src.join(item));
945         }
946
947         // Create the version file
948         builder.create(&plain_dst_src.join("version"), &builder.rust_version());
949         if let Some(sha) = builder.rust_sha() {
950             builder.create(&plain_dst_src.join("git-commit-hash"), &sha);
951         }
952
953         // If we're building from git sources, we need to vendor a complete distribution.
954         if builder.rust_info.is_git() {
955             // Get cargo-vendor installed, if it isn't already.
956             let mut has_cargo_vendor = false;
957             let mut cmd = Command::new(&builder.initial_cargo);
958             for line in output(cmd.arg("install").arg("--list")).lines() {
959                 has_cargo_vendor |= line.starts_with("cargo-vendor ");
960             }
961             if !has_cargo_vendor {
962                 let mut cmd = builder.cargo(
963                     builder.compiler(0, builder.config.build),
964                     Mode::ToolBootstrap,
965                     builder.config.build,
966                     "install"
967                 );
968                 cmd.arg("--force")
969                    .arg("--debug")
970                    .arg("--vers").arg(CARGO_VENDOR_VERSION)
971                    .arg("cargo-vendor");
972                 builder.run(&mut cmd);
973             }
974
975             // Vendor all Cargo dependencies
976             let mut cmd = Command::new(&builder.initial_cargo);
977             cmd.arg("vendor")
978                .current_dir(&plain_dst_src);
979             builder.run(&mut cmd);
980         }
981
982         // Create plain source tarball
983         let plain_name = format!("rustc-{}-src", builder.rust_package_vers());
984         let mut tarball = distdir(builder).join(&format!("{}.tar.gz", plain_name));
985         tarball.set_extension(""); // strip .gz
986         tarball.set_extension(""); // strip .tar
987         if let Some(dir) = tarball.parent() {
988             builder.create_dir(&dir);
989         }
990         builder.info("running installer");
991         let mut cmd = rust_installer(builder);
992         cmd.arg("tarball")
993            .arg("--input").arg(&plain_name)
994            .arg("--output").arg(&tarball)
995            .arg("--work-dir=.")
996            .current_dir(tmpdir(builder));
997         builder.run(&mut cmd);
998         distdir(builder).join(&format!("{}.tar.gz", plain_name))
999     }
1000 }
1001
1002 // We have to run a few shell scripts, which choke quite a bit on both `\`
1003 // characters and on `C:\` paths, so normalize both of them away.
1004 pub fn sanitize_sh(path: &Path) -> String {
1005     let path = path.to_str().unwrap().replace("\\", "/");
1006     return change_drive(&path).unwrap_or(path);
1007
1008     fn change_drive(s: &str) -> Option<String> {
1009         let mut ch = s.chars();
1010         let drive = ch.next().unwrap_or('C');
1011         if ch.next() != Some(':') {
1012             return None
1013         }
1014         if ch.next() != Some('/') {
1015             return None
1016         }
1017         Some(format!("/{}/{}", drive, &s[drive.len_utf8() + 2..]))
1018     }
1019 }
1020
1021 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1022 pub struct Cargo {
1023     pub stage: u32,
1024     pub target: Interned<String>,
1025 }
1026
1027 impl Step for Cargo {
1028     type Output = PathBuf;
1029     const ONLY_HOSTS: bool = true;
1030
1031     fn should_run(run: ShouldRun) -> ShouldRun {
1032         run.path("cargo")
1033     }
1034
1035     fn make_run(run: RunConfig) {
1036         run.builder.ensure(Cargo {
1037             stage: run.builder.top_stage,
1038             target: run.target,
1039         });
1040     }
1041
1042     fn run(self, builder: &Builder) -> PathBuf {
1043         let stage = self.stage;
1044         let target = self.target;
1045
1046         builder.info(&format!("Dist cargo stage{} ({})", stage, target));
1047         let src = builder.src.join("src/tools/cargo");
1048         let etc = src.join("src/etc");
1049         let release_num = builder.release_num("cargo");
1050         let name = pkgname(builder, "cargo");
1051         let version = builder.cargo_info.version(builder, &release_num);
1052
1053         let tmp = tmpdir(builder);
1054         let image = tmp.join("cargo-image");
1055         drop(fs::remove_dir_all(&image));
1056         builder.create_dir(&image);
1057
1058         // Prepare the image directory
1059         builder.create_dir(&image.join("share/zsh/site-functions"));
1060         builder.create_dir(&image.join("etc/bash_completion.d"));
1061         let cargo = builder.ensure(tool::Cargo {
1062             compiler: builder.compiler(stage, builder.config.build),
1063             target
1064         });
1065         builder.install(&cargo, &image.join("bin"), 0o755);
1066         for man in t!(etc.join("man").read_dir()) {
1067             let man = t!(man);
1068             builder.install(&man.path(), &image.join("share/man/man1"), 0o644);
1069         }
1070         builder.install(&etc.join("_cargo"), &image.join("share/zsh/site-functions"), 0o644);
1071         builder.copy(&etc.join("cargo.bashcomp.sh"),
1072              &image.join("etc/bash_completion.d/cargo"));
1073         let doc = image.join("share/doc/cargo");
1074         builder.install(&src.join("README.md"), &doc, 0o644);
1075         builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
1076         builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1077         builder.install(&src.join("LICENSE-THIRD-PARTY"), &doc, 0o644);
1078
1079         // Prepare the overlay
1080         let overlay = tmp.join("cargo-overlay");
1081         drop(fs::remove_dir_all(&overlay));
1082         builder.create_dir(&overlay);
1083         builder.install(&src.join("README.md"), &overlay, 0o644);
1084         builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
1085         builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
1086         builder.install(&src.join("LICENSE-THIRD-PARTY"), &overlay, 0o644);
1087         builder.create(&overlay.join("version"), &version);
1088
1089         // Generate the installer tarball
1090         let mut cmd = rust_installer(builder);
1091         cmd.arg("generate")
1092            .arg("--product-name=Rust")
1093            .arg("--rel-manifest-dir=rustlib")
1094            .arg("--success-message=Rust-is-ready-to-roll.")
1095            .arg("--image-dir").arg(&image)
1096            .arg("--work-dir").arg(&tmpdir(builder))
1097            .arg("--output-dir").arg(&distdir(builder))
1098            .arg("--non-installed-overlay").arg(&overlay)
1099            .arg(format!("--package-name={}-{}", name, target))
1100            .arg("--component-name=cargo")
1101            .arg("--legacy-manifest-dirs=rustlib,cargo");
1102         builder.run(&mut cmd);
1103         distdir(builder).join(format!("{}-{}.tar.gz", name, target))
1104     }
1105 }
1106
1107 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1108 pub struct Rls {
1109     pub stage: u32,
1110     pub target: Interned<String>,
1111 }
1112
1113 impl Step for Rls {
1114     type Output = Option<PathBuf>;
1115     const ONLY_HOSTS: bool = true;
1116
1117     fn should_run(run: ShouldRun) -> ShouldRun {
1118         run.path("rls")
1119     }
1120
1121     fn make_run(run: RunConfig) {
1122         run.builder.ensure(Rls {
1123             stage: run.builder.top_stage,
1124             target: run.target,
1125         });
1126     }
1127
1128     fn run(self, builder: &Builder) -> Option<PathBuf> {
1129         let stage = self.stage;
1130         let target = self.target;
1131         assert!(builder.config.extended);
1132
1133         builder.info(&format!("Dist RLS stage{} ({})", stage, target));
1134         let src = builder.src.join("src/tools/rls");
1135         let release_num = builder.release_num("rls");
1136         let name = pkgname(builder, "rls");
1137         let version = builder.rls_info.version(builder, &release_num);
1138
1139         let tmp = tmpdir(builder);
1140         let image = tmp.join("rls-image");
1141         drop(fs::remove_dir_all(&image));
1142         t!(fs::create_dir_all(&image));
1143
1144         // Prepare the image directory
1145         // We expect RLS to build, because we've exited this step above if tool
1146         // state for RLS isn't testing.
1147         let rls = builder.ensure(tool::Rls {
1148             compiler: builder.compiler(stage, builder.config.build),
1149             target, extra_features: Vec::new()
1150         }).or_else(|| { missing_tool("RLS", builder.build.config.missing_tools); None })?;
1151
1152         builder.install(&rls, &image.join("bin"), 0o755);
1153         let doc = image.join("share/doc/rls");
1154         builder.install(&src.join("README.md"), &doc, 0o644);
1155         builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
1156         builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1157
1158         // Prepare the overlay
1159         let overlay = tmp.join("rls-overlay");
1160         drop(fs::remove_dir_all(&overlay));
1161         t!(fs::create_dir_all(&overlay));
1162         builder.install(&src.join("README.md"), &overlay, 0o644);
1163         builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
1164         builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
1165         builder.create(&overlay.join("version"), &version);
1166
1167         // Generate the installer tarball
1168         let mut cmd = rust_installer(builder);
1169         cmd.arg("generate")
1170            .arg("--product-name=Rust")
1171            .arg("--rel-manifest-dir=rustlib")
1172            .arg("--success-message=RLS-ready-to-serve.")
1173            .arg("--image-dir").arg(&image)
1174            .arg("--work-dir").arg(&tmpdir(builder))
1175            .arg("--output-dir").arg(&distdir(builder))
1176            .arg("--non-installed-overlay").arg(&overlay)
1177            .arg(format!("--package-name={}-{}", name, target))
1178            .arg("--legacy-manifest-dirs=rustlib,cargo")
1179            .arg("--component-name=rls-preview");
1180
1181         builder.run(&mut cmd);
1182         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
1183     }
1184 }
1185
1186 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1187 pub struct Clippy {
1188     pub stage: u32,
1189     pub target: Interned<String>,
1190 }
1191
1192 impl Step for Clippy {
1193     type Output = Option<PathBuf>;
1194     const ONLY_HOSTS: bool = true;
1195
1196     fn should_run(run: ShouldRun) -> ShouldRun {
1197         run.path("clippy")
1198     }
1199
1200     fn make_run(run: RunConfig) {
1201         run.builder.ensure(Clippy {
1202             stage: run.builder.top_stage,
1203             target: run.target,
1204         });
1205     }
1206
1207     fn run(self, builder: &Builder) -> Option<PathBuf> {
1208         let stage = self.stage;
1209         let target = self.target;
1210         assert!(builder.config.extended);
1211
1212         builder.info(&format!("Dist clippy stage{} ({})", stage, target));
1213         let src = builder.src.join("src/tools/clippy");
1214         let release_num = builder.release_num("clippy");
1215         let name = pkgname(builder, "clippy");
1216         let version = builder.clippy_info.version(builder, &release_num);
1217
1218         let tmp = tmpdir(builder);
1219         let image = tmp.join("clippy-image");
1220         drop(fs::remove_dir_all(&image));
1221         builder.create_dir(&image);
1222
1223         // Prepare the image directory
1224         // We expect clippy to build, because we've exited this step above if tool
1225         // state for clippy isn't testing.
1226         let clippy = builder.ensure(tool::Clippy {
1227             compiler: builder.compiler(stage, builder.config.build),
1228             target, extra_features: Vec::new()
1229         }).or_else(|| { missing_tool("clippy", builder.build.config.missing_tools); None })?;
1230         let cargoclippy = builder.ensure(tool::CargoClippy {
1231             compiler: builder.compiler(stage, builder.config.build),
1232             target, extra_features: Vec::new()
1233         }).or_else(|| { missing_tool("cargo clippy", builder.build.config.missing_tools); None })?;
1234
1235         builder.install(&clippy, &image.join("bin"), 0o755);
1236         builder.install(&cargoclippy, &image.join("bin"), 0o755);
1237         let doc = image.join("share/doc/clippy");
1238         builder.install(&src.join("README.md"), &doc, 0o644);
1239         builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1240         builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
1241
1242         // Prepare the overlay
1243         let overlay = tmp.join("clippy-overlay");
1244         drop(fs::remove_dir_all(&overlay));
1245         t!(fs::create_dir_all(&overlay));
1246         builder.install(&src.join("README.md"), &overlay, 0o644);
1247         builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1248         builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
1249         builder.create(&overlay.join("version"), &version);
1250
1251         // Generate the installer tarball
1252         let mut cmd = rust_installer(builder);
1253         cmd.arg("generate")
1254            .arg("--product-name=Rust")
1255            .arg("--rel-manifest-dir=rustlib")
1256            .arg("--success-message=clippy-ready-to-serve.")
1257            .arg("--image-dir").arg(&image)
1258            .arg("--work-dir").arg(&tmpdir(builder))
1259            .arg("--output-dir").arg(&distdir(builder))
1260            .arg("--non-installed-overlay").arg(&overlay)
1261            .arg(format!("--package-name={}-{}", name, target))
1262            .arg("--legacy-manifest-dirs=rustlib,cargo")
1263            .arg("--component-name=clippy-preview");
1264
1265         builder.run(&mut cmd);
1266         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
1267     }
1268 }
1269
1270 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1271 pub struct Rustfmt {
1272     pub stage: u32,
1273     pub target: Interned<String>,
1274 }
1275
1276 impl Step for Rustfmt {
1277     type Output = Option<PathBuf>;
1278     const ONLY_HOSTS: bool = true;
1279
1280     fn should_run(run: ShouldRun) -> ShouldRun {
1281         run.path("rustfmt")
1282     }
1283
1284     fn make_run(run: RunConfig) {
1285         run.builder.ensure(Rustfmt {
1286             stage: run.builder.top_stage,
1287             target: run.target,
1288         });
1289     }
1290
1291     fn run(self, builder: &Builder) -> Option<PathBuf> {
1292         let stage = self.stage;
1293         let target = self.target;
1294
1295         builder.info(&format!("Dist Rustfmt stage{} ({})", stage, target));
1296         let src = builder.src.join("src/tools/rustfmt");
1297         let release_num = builder.release_num("rustfmt");
1298         let name = pkgname(builder, "rustfmt");
1299         let version = builder.rustfmt_info.version(builder, &release_num);
1300
1301         let tmp = tmpdir(builder);
1302         let image = tmp.join("rustfmt-image");
1303         drop(fs::remove_dir_all(&image));
1304         builder.create_dir(&image);
1305
1306         // Prepare the image directory
1307         let rustfmt = builder.ensure(tool::Rustfmt {
1308             compiler: builder.compiler(stage, builder.config.build),
1309             target, extra_features: Vec::new()
1310         }).or_else(|| { missing_tool("Rustfmt", builder.build.config.missing_tools); None })?;
1311         let cargofmt = builder.ensure(tool::Cargofmt {
1312             compiler: builder.compiler(stage, builder.config.build),
1313             target, extra_features: Vec::new()
1314         }).or_else(|| { missing_tool("Cargofmt", builder.build.config.missing_tools); None })?;
1315
1316         builder.install(&rustfmt, &image.join("bin"), 0o755);
1317         builder.install(&cargofmt, &image.join("bin"), 0o755);
1318         let doc = image.join("share/doc/rustfmt");
1319         builder.install(&src.join("README.md"), &doc, 0o644);
1320         builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
1321         builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
1322
1323         // Prepare the overlay
1324         let overlay = tmp.join("rustfmt-overlay");
1325         drop(fs::remove_dir_all(&overlay));
1326         builder.create_dir(&overlay);
1327         builder.install(&src.join("README.md"), &overlay, 0o644);
1328         builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
1329         builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
1330         builder.create(&overlay.join("version"), &version);
1331
1332         // Generate the installer tarball
1333         let mut cmd = rust_installer(builder);
1334         cmd.arg("generate")
1335            .arg("--product-name=Rust")
1336            .arg("--rel-manifest-dir=rustlib")
1337            .arg("--success-message=rustfmt-ready-to-fmt.")
1338            .arg("--image-dir").arg(&image)
1339            .arg("--work-dir").arg(&tmpdir(builder))
1340            .arg("--output-dir").arg(&distdir(builder))
1341            .arg("--non-installed-overlay").arg(&overlay)
1342            .arg(format!("--package-name={}-{}", name, target))
1343            .arg("--legacy-manifest-dirs=rustlib,cargo")
1344            .arg("--component-name=rustfmt-preview");
1345
1346         builder.run(&mut cmd);
1347         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
1348     }
1349 }
1350
1351 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1352 pub struct Extended {
1353     stage: u32,
1354     host: Interned<String>,
1355     target: Interned<String>,
1356 }
1357
1358 impl Step for Extended {
1359     type Output = ();
1360     const DEFAULT: bool = true;
1361     const ONLY_HOSTS: bool = true;
1362
1363     fn should_run(run: ShouldRun) -> ShouldRun {
1364         let builder = run.builder;
1365         run.path("extended").default_condition(builder.config.extended)
1366     }
1367
1368     fn make_run(run: RunConfig) {
1369         run.builder.ensure(Extended {
1370             stage: run.builder.top_stage,
1371             host: run.builder.config.build,
1372             target: run.target,
1373         });
1374     }
1375
1376     /// Creates a combined installer for the specified target in the provided stage.
1377     fn run(self, builder: &Builder) {
1378         let stage = self.stage;
1379         let target = self.target;
1380
1381         builder.info(&format!("Dist extended stage{} ({})", stage, target));
1382
1383         let rustc_installer = builder.ensure(Rustc {
1384             compiler: builder.compiler(stage, target),
1385         });
1386         let cargo_installer = builder.ensure(Cargo { stage, target });
1387         let rustfmt_installer = builder.ensure(Rustfmt { stage, target });
1388         let rls_installer = builder.ensure(Rls { stage, target });
1389         let llvm_tools_installer = builder.ensure(LlvmTools { stage, target });
1390         let clippy_installer = builder.ensure(Clippy { stage, target });
1391         let lldb_installer = builder.ensure(Lldb { target });
1392         let mingw_installer = builder.ensure(Mingw { host: target });
1393         let analysis_installer = builder.ensure(Analysis {
1394             compiler: builder.compiler(stage, self.host),
1395             target
1396         });
1397
1398         let docs_installer = builder.ensure(Docs { stage, host: target, });
1399         let std_installer = builder.ensure(Std {
1400             compiler: builder.compiler(stage, self.host),
1401             target,
1402         });
1403
1404         let tmp = tmpdir(builder);
1405         let overlay = tmp.join("extended-overlay");
1406         let etc = builder.src.join("src/etc/installer");
1407         let work = tmp.join("work");
1408
1409         let _ = fs::remove_dir_all(&overlay);
1410         builder.install(&builder.src.join("COPYRIGHT"), &overlay, 0o644);
1411         builder.install(&builder.src.join("LICENSE-APACHE"), &overlay, 0o644);
1412         builder.install(&builder.src.join("LICENSE-MIT"), &overlay, 0o644);
1413         let version = builder.rust_version();
1414         builder.create(&overlay.join("version"), &version);
1415         if let Some(sha) = builder.rust_sha() {
1416             builder.create(&overlay.join("git-commit-hash"), &sha);
1417         }
1418         builder.install(&etc.join("README.md"), &overlay, 0o644);
1419
1420         // When rust-std package split from rustc, we needed to ensure that during
1421         // upgrades rustc was upgraded before rust-std. To avoid rustc clobbering
1422         // the std files during uninstall. To do this ensure that rustc comes
1423         // before rust-std in the list below.
1424         let mut tarballs = Vec::new();
1425         tarballs.push(rustc_installer);
1426         tarballs.push(cargo_installer);
1427         tarballs.extend(rls_installer.clone());
1428         tarballs.extend(clippy_installer.clone());
1429         tarballs.extend(rustfmt_installer.clone());
1430         tarballs.extend(llvm_tools_installer);
1431         tarballs.extend(lldb_installer);
1432         tarballs.push(analysis_installer);
1433         tarballs.push(std_installer);
1434         if builder.config.docs {
1435             tarballs.push(docs_installer);
1436         }
1437         if target.contains("pc-windows-gnu") {
1438             tarballs.push(mingw_installer.unwrap());
1439         }
1440         let mut input_tarballs = tarballs[0].as_os_str().to_owned();
1441         for tarball in &tarballs[1..] {
1442             input_tarballs.push(",");
1443             input_tarballs.push(tarball);
1444         }
1445
1446         let mut cmd = rust_installer(builder);
1447         cmd.arg("combine")
1448             .arg("--product-name=Rust")
1449             .arg("--rel-manifest-dir=rustlib")
1450             .arg("--success-message=Rust-is-ready-to-roll.")
1451             .arg("--work-dir").arg(&work)
1452             .arg("--output-dir").arg(&distdir(builder))
1453             .arg(format!("--package-name={}-{}", pkgname(builder, "rust"), target))
1454             .arg("--legacy-manifest-dirs=rustlib,cargo")
1455             .arg("--input-tarballs").arg(input_tarballs)
1456             .arg("--non-installed-overlay").arg(&overlay);
1457         builder.run(&mut cmd);
1458
1459         let mut license = String::new();
1460         license += &builder.read(&builder.src.join("COPYRIGHT"));
1461         license += &builder.read(&builder.src.join("LICENSE-APACHE"));
1462         license += &builder.read(&builder.src.join("LICENSE-MIT"));
1463         license.push_str("\n");
1464         license.push_str("\n");
1465
1466         let rtf = r"{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Arial;}}\nowwrap\fs18";
1467         let mut rtf = rtf.to_string();
1468         rtf.push_str("\n");
1469         for line in license.lines() {
1470             rtf.push_str(line);
1471             rtf.push_str("\\line ");
1472         }
1473         rtf.push_str("}");
1474
1475         fn filter(contents: &str, marker: &str) -> String {
1476             let start = format!("tool-{}-start", marker);
1477             let end = format!("tool-{}-end", marker);
1478             let mut lines = Vec::new();
1479             let mut omitted = false;
1480             for line in contents.lines() {
1481                 if line.contains(&start) {
1482                     omitted = true;
1483                 } else if line.contains(&end) {
1484                     omitted = false;
1485                 } else if !omitted {
1486                     lines.push(line);
1487                 }
1488             }
1489
1490             lines.join("\n")
1491         }
1492
1493         let xform = |p: &Path| {
1494             let mut contents = t!(fs::read_to_string(p));
1495             if rls_installer.is_none() {
1496                 contents = filter(&contents, "rls");
1497             }
1498             if clippy_installer.is_none() {
1499                 contents = filter(&contents, "clippy");
1500             }
1501             if rustfmt_installer.is_none() {
1502                 contents = filter(&contents, "rustfmt");
1503             }
1504             let ret = tmp.join(p.file_name().unwrap());
1505             t!(fs::write(&ret, &contents));
1506             ret
1507         };
1508
1509         if target.contains("apple-darwin") {
1510             let pkg = tmp.join("pkg");
1511             let _ = fs::remove_dir_all(&pkg);
1512
1513             let pkgbuild = |component: &str| {
1514                 let mut cmd = Command::new("pkgbuild");
1515                 cmd.arg("--identifier").arg(format!("org.rust-lang.{}", component))
1516                     .arg("--scripts").arg(pkg.join(component))
1517                     .arg("--nopayload")
1518                     .arg(pkg.join(component).with_extension("pkg"));
1519                 builder.run(&mut cmd);
1520             };
1521
1522             let prepare = |name: &str| {
1523                 builder.create_dir(&pkg.join(name));
1524                 builder.cp_r(&work.join(&format!("{}-{}", pkgname(builder, name), target)),
1525                         &pkg.join(name));
1526                 builder.install(&etc.join("pkg/postinstall"), &pkg.join(name), 0o755);
1527                 pkgbuild(name);
1528             };
1529             prepare("rustc");
1530             prepare("cargo");
1531             prepare("rust-docs");
1532             prepare("rust-std");
1533             prepare("rust-analysis");
1534
1535             if rls_installer.is_some() {
1536                 prepare("rls");
1537             }
1538             if clippy_installer.is_some() {
1539                 prepare("clippy");
1540             }
1541
1542             // create an 'uninstall' package
1543             builder.install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), 0o755);
1544             pkgbuild("uninstall");
1545
1546             builder.create_dir(&pkg.join("res"));
1547             builder.create(&pkg.join("res/LICENSE.txt"), &license);
1548             builder.install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644);
1549             let mut cmd = Command::new("productbuild");
1550             cmd.arg("--distribution").arg(xform(&etc.join("pkg/Distribution.xml")))
1551                 .arg("--resources").arg(pkg.join("res"))
1552                 .arg(distdir(builder).join(format!("{}-{}.pkg",
1553                                                     pkgname(builder, "rust"),
1554                                                     target)))
1555                 .arg("--package-path").arg(&pkg);
1556             builder.run(&mut cmd);
1557         }
1558
1559         if target.contains("windows") {
1560             let exe = tmp.join("exe");
1561             let _ = fs::remove_dir_all(&exe);
1562
1563             let prepare = |name: &str| {
1564                 builder.create_dir(&exe.join(name));
1565                 let dir = if name == "rust-std" || name == "rust-analysis" {
1566                     format!("{}-{}", name, target)
1567                 } else if name == "rls" {
1568                     "rls-preview".to_string()
1569                 } else if name == "clippy" {
1570                     "clippy-preview".to_string()
1571                 } else {
1572                     name.to_string()
1573                 };
1574                 builder.cp_r(&work.join(&format!("{}-{}", pkgname(builder, name), target))
1575                             .join(dir),
1576                         &exe.join(name));
1577                 builder.remove(&exe.join(name).join("manifest.in"));
1578             };
1579             prepare("rustc");
1580             prepare("cargo");
1581             prepare("rust-analysis");
1582             prepare("rust-docs");
1583             prepare("rust-std");
1584             if rls_installer.is_some() {
1585                 prepare("rls");
1586             }
1587             if clippy_installer.is_some() {
1588                 prepare("clippy");
1589             }
1590             if target.contains("windows-gnu") {
1591                 prepare("rust-mingw");
1592             }
1593
1594             builder.install(&xform(&etc.join("exe/rust.iss")), &exe, 0o644);
1595             builder.install(&etc.join("exe/modpath.iss"), &exe, 0o644);
1596             builder.install(&etc.join("exe/upgrade.iss"), &exe, 0o644);
1597             builder.install(&etc.join("gfx/rust-logo.ico"), &exe, 0o644);
1598             builder.create(&exe.join("LICENSE.txt"), &license);
1599
1600             // Generate exe installer
1601             let mut cmd = Command::new("iscc");
1602             cmd.arg("rust.iss")
1603                 .current_dir(&exe);
1604             if target.contains("windows-gnu") {
1605                 cmd.arg("/dMINGW");
1606             }
1607             add_env(builder, &mut cmd, target);
1608             builder.run(&mut cmd);
1609             builder.install(&exe.join(format!("{}-{}.exe", pkgname(builder, "rust"), target)),
1610                     &distdir(builder),
1611                     0o755);
1612
1613             // Generate msi installer
1614             let wix = PathBuf::from(env::var_os("WIX").unwrap());
1615             let heat = wix.join("bin/heat.exe");
1616             let candle = wix.join("bin/candle.exe");
1617             let light = wix.join("bin/light.exe");
1618
1619             let heat_flags = ["-nologo", "-gg", "-sfrag", "-srd", "-sreg"];
1620             builder.run(Command::new(&heat)
1621                             .current_dir(&exe)
1622                             .arg("dir")
1623                             .arg("rustc")
1624                             .args(&heat_flags)
1625                             .arg("-cg").arg("RustcGroup")
1626                             .arg("-dr").arg("Rustc")
1627                             .arg("-var").arg("var.RustcDir")
1628                             .arg("-out").arg(exe.join("RustcGroup.wxs")));
1629             builder.run(Command::new(&heat)
1630                             .current_dir(&exe)
1631                             .arg("dir")
1632                             .arg("rust-docs")
1633                             .args(&heat_flags)
1634                             .arg("-cg").arg("DocsGroup")
1635                             .arg("-dr").arg("Docs")
1636                             .arg("-var").arg("var.DocsDir")
1637                             .arg("-out").arg(exe.join("DocsGroup.wxs"))
1638                             .arg("-t").arg(etc.join("msi/squash-components.xsl")));
1639             builder.run(Command::new(&heat)
1640                             .current_dir(&exe)
1641                             .arg("dir")
1642                             .arg("cargo")
1643                             .args(&heat_flags)
1644                             .arg("-cg").arg("CargoGroup")
1645                             .arg("-dr").arg("Cargo")
1646                             .arg("-var").arg("var.CargoDir")
1647                             .arg("-out").arg(exe.join("CargoGroup.wxs"))
1648                             .arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
1649             builder.run(Command::new(&heat)
1650                             .current_dir(&exe)
1651                             .arg("dir")
1652                             .arg("rust-std")
1653                             .args(&heat_flags)
1654                             .arg("-cg").arg("StdGroup")
1655                             .arg("-dr").arg("Std")
1656                             .arg("-var").arg("var.StdDir")
1657                             .arg("-out").arg(exe.join("StdGroup.wxs")));
1658             if rls_installer.is_some() {
1659                 builder.run(Command::new(&heat)
1660                                 .current_dir(&exe)
1661                                 .arg("dir")
1662                                 .arg("rls")
1663                                 .args(&heat_flags)
1664                                 .arg("-cg").arg("RlsGroup")
1665                                 .arg("-dr").arg("Rls")
1666                                 .arg("-var").arg("var.RlsDir")
1667                                 .arg("-out").arg(exe.join("RlsGroup.wxs"))
1668                                 .arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
1669             }
1670             if clippy_installer.is_some() {
1671                 builder.run(Command::new(&heat)
1672                                 .current_dir(&exe)
1673                                 .arg("dir")
1674                                 .arg("clippy")
1675                                 .args(&heat_flags)
1676                                 .arg("-cg").arg("ClippyGroup")
1677                                 .arg("-dr").arg("Clippy")
1678                                 .arg("-var").arg("var.ClippyDir")
1679                                 .arg("-out").arg(exe.join("ClippyGroup.wxs"))
1680                                 .arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
1681             }
1682             builder.run(Command::new(&heat)
1683                             .current_dir(&exe)
1684                             .arg("dir")
1685                             .arg("rust-analysis")
1686                             .args(&heat_flags)
1687                             .arg("-cg").arg("AnalysisGroup")
1688                             .arg("-dr").arg("Analysis")
1689                             .arg("-var").arg("var.AnalysisDir")
1690                             .arg("-out").arg(exe.join("AnalysisGroup.wxs"))
1691                             .arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
1692             if target.contains("windows-gnu") {
1693                 builder.run(Command::new(&heat)
1694                                 .current_dir(&exe)
1695                                 .arg("dir")
1696                                 .arg("rust-mingw")
1697                                 .args(&heat_flags)
1698                                 .arg("-cg").arg("GccGroup")
1699                                 .arg("-dr").arg("Gcc")
1700                                 .arg("-var").arg("var.GccDir")
1701                                 .arg("-out").arg(exe.join("GccGroup.wxs")));
1702             }
1703
1704             let candle = |input: &Path| {
1705                 let output = exe.join(input.file_stem().unwrap())
1706                                 .with_extension("wixobj");
1707                 let arch = if target.contains("x86_64") {"x64"} else {"x86"};
1708                 let mut cmd = Command::new(&candle);
1709                 cmd.current_dir(&exe)
1710                     .arg("-nologo")
1711                     .arg("-dRustcDir=rustc")
1712                     .arg("-dDocsDir=rust-docs")
1713                     .arg("-dCargoDir=cargo")
1714                     .arg("-dStdDir=rust-std")
1715                     .arg("-dAnalysisDir=rust-analysis")
1716                     .arg("-arch").arg(&arch)
1717                     .arg("-out").arg(&output)
1718                     .arg(&input);
1719                 add_env(builder, &mut cmd, target);
1720
1721                 if rls_installer.is_some() {
1722                     cmd.arg("-dRlsDir=rls");
1723                 }
1724                 if clippy_installer.is_some() {
1725                     cmd.arg("-dClippyDir=clippy");
1726                 }
1727                 if target.contains("windows-gnu") {
1728                     cmd.arg("-dGccDir=rust-mingw");
1729                 }
1730                 builder.run(&mut cmd);
1731             };
1732             candle(&xform(&etc.join("msi/rust.wxs")));
1733             candle(&etc.join("msi/ui.wxs"));
1734             candle(&etc.join("msi/rustwelcomedlg.wxs"));
1735             candle("RustcGroup.wxs".as_ref());
1736             candle("DocsGroup.wxs".as_ref());
1737             candle("CargoGroup.wxs".as_ref());
1738             candle("StdGroup.wxs".as_ref());
1739             if rls_installer.is_some() {
1740                 candle("RlsGroup.wxs".as_ref());
1741             }
1742             if clippy_installer.is_some() {
1743                 candle("ClippyGroup.wxs".as_ref());
1744             }
1745             candle("AnalysisGroup.wxs".as_ref());
1746
1747             if target.contains("windows-gnu") {
1748                 candle("GccGroup.wxs".as_ref());
1749             }
1750
1751             builder.create(&exe.join("LICENSE.rtf"), &rtf);
1752             builder.install(&etc.join("gfx/banner.bmp"), &exe, 0o644);
1753             builder.install(&etc.join("gfx/dialogbg.bmp"), &exe, 0o644);
1754
1755             let filename = format!("{}-{}.msi", pkgname(builder, "rust"), target);
1756             let mut cmd = Command::new(&light);
1757             cmd.arg("-nologo")
1758                 .arg("-ext").arg("WixUIExtension")
1759                 .arg("-ext").arg("WixUtilExtension")
1760                 .arg("-out").arg(exe.join(&filename))
1761                 .arg("rust.wixobj")
1762                 .arg("ui.wixobj")
1763                 .arg("rustwelcomedlg.wixobj")
1764                 .arg("RustcGroup.wixobj")
1765                 .arg("DocsGroup.wixobj")
1766                 .arg("CargoGroup.wixobj")
1767                 .arg("StdGroup.wixobj")
1768                 .arg("AnalysisGroup.wixobj")
1769                 .current_dir(&exe);
1770
1771             if rls_installer.is_some() {
1772                 cmd.arg("RlsGroup.wixobj");
1773             }
1774             if clippy_installer.is_some() {
1775                 cmd.arg("ClippyGroup.wixobj");
1776             }
1777
1778             if target.contains("windows-gnu") {
1779                 cmd.arg("GccGroup.wixobj");
1780             }
1781             // ICE57 wrongly complains about the shortcuts
1782             cmd.arg("-sice:ICE57");
1783
1784             builder.run(&mut cmd);
1785
1786             if !builder.config.dry_run {
1787                 t!(fs::rename(exe.join(&filename), distdir(builder).join(&filename)));
1788             }
1789         }
1790     }
1791 }
1792
1793 fn add_env(builder: &Builder, cmd: &mut Command, target: Interned<String>) {
1794     let mut parts = channel::CFG_RELEASE_NUM.split('.');
1795     cmd.env("CFG_RELEASE_INFO", builder.rust_version())
1796        .env("CFG_RELEASE_NUM", channel::CFG_RELEASE_NUM)
1797        .env("CFG_RELEASE", builder.rust_release())
1798        .env("CFG_VER_MAJOR", parts.next().unwrap())
1799        .env("CFG_VER_MINOR", parts.next().unwrap())
1800        .env("CFG_VER_PATCH", parts.next().unwrap())
1801        .env("CFG_VER_BUILD", "0") // just needed to build
1802        .env("CFG_PACKAGE_VERS", builder.rust_package_vers())
1803        .env("CFG_PACKAGE_NAME", pkgname(builder, "rust"))
1804        .env("CFG_BUILD", target)
1805        .env("CFG_CHANNEL", &builder.config.channel);
1806
1807     if target.contains("windows-gnu") {
1808        cmd.env("CFG_MINGW", "1")
1809           .env("CFG_ABI", "GNU");
1810     } else {
1811        cmd.env("CFG_MINGW", "0")
1812           .env("CFG_ABI", "MSVC");
1813     }
1814
1815     if target.contains("x86_64") {
1816        cmd.env("CFG_PLATFORM", "x64");
1817     } else {
1818        cmd.env("CFG_PLATFORM", "x86");
1819     }
1820 }
1821
1822 #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
1823 pub struct HashSign;
1824
1825 impl Step for HashSign {
1826     type Output = ();
1827     const ONLY_HOSTS: bool = true;
1828
1829     fn should_run(run: ShouldRun) -> ShouldRun {
1830         run.path("hash-and-sign")
1831     }
1832
1833     fn make_run(run: RunConfig) {
1834         run.builder.ensure(HashSign);
1835     }
1836
1837     fn run(self, builder: &Builder) {
1838         let mut cmd = builder.tool_cmd(Tool::BuildManifest);
1839         if builder.config.dry_run {
1840             return;
1841         }
1842         let sign = builder.config.dist_sign_folder.as_ref().unwrap_or_else(|| {
1843             panic!("\n\nfailed to specify `dist.sign-folder` in `config.toml`\n\n")
1844         });
1845         let addr = builder.config.dist_upload_addr.as_ref().unwrap_or_else(|| {
1846             panic!("\n\nfailed to specify `dist.upload-addr` in `config.toml`\n\n")
1847         });
1848         let file = builder.config.dist_gpg_password_file.as_ref().unwrap_or_else(|| {
1849             panic!("\n\nfailed to specify `dist.gpg-password-file` in `config.toml`\n\n")
1850         });
1851         let pass = t!(fs::read_to_string(&file));
1852
1853         let today = output(Command::new("date").arg("+%Y-%m-%d"));
1854
1855         cmd.arg(sign);
1856         cmd.arg(distdir(builder));
1857         cmd.arg(today.trim());
1858         cmd.arg(builder.rust_package_vers());
1859         cmd.arg(builder.package_vers(&builder.release_num("cargo")));
1860         cmd.arg(builder.package_vers(&builder.release_num("rls")));
1861         cmd.arg(builder.package_vers(&builder.release_num("clippy")));
1862         cmd.arg(builder.package_vers(&builder.release_num("rustfmt")));
1863         cmd.arg(builder.llvm_tools_package_vers());
1864         cmd.arg(builder.lldb_package_vers());
1865         cmd.arg(addr);
1866
1867         builder.create_dir(&distdir(builder));
1868
1869         let mut child = t!(cmd.stdin(Stdio::piped()).spawn());
1870         t!(child.stdin.take().unwrap().write_all(pass.as_bytes()));
1871         let status = t!(child.wait());
1872         assert!(status.success());
1873     }
1874 }
1875
1876 // Maybe add libLLVM.so to the lib-dir. It will only have been built if
1877 // LLVM tools are linked dynamically.
1878 // Note: This function does no yet support Windows but we also don't support
1879 //       linking LLVM tools dynamically on Windows yet.
1880 fn maybe_install_llvm_dylib(builder: &Builder,
1881                             target: Interned<String>,
1882                             image: &Path) {
1883     let src_libdir = builder
1884         .llvm_out(target)
1885         .join("lib");
1886     let dst_libdir = image.join("lib/rustlib").join(&*target).join("lib");
1887     t!(fs::create_dir_all(&dst_libdir));
1888
1889     if target.contains("apple-darwin") {
1890         let llvm_dylib_path = src_libdir.join("libLLVM.dylib");
1891         if llvm_dylib_path.exists() {
1892             builder.install(&llvm_dylib_path, &dst_libdir, 0o644);
1893         }
1894         return
1895     }
1896
1897     // Usually libLLVM.so is a symlink to something like libLLVM-6.0.so.
1898     // Since tools link to the latter rather than the former, we have to
1899     // follow the symlink to find out what to distribute.
1900     let llvm_dylib_path = src_libdir.join("libLLVM.so");
1901     if llvm_dylib_path.exists() {
1902         let llvm_dylib_path = llvm_dylib_path.canonicalize().unwrap_or_else(|e| {
1903             panic!("dist: Error calling canonicalize path `{}`: {}",
1904                    llvm_dylib_path.display(), e);
1905         });
1906
1907
1908         builder.install(&llvm_dylib_path, &dst_libdir, 0o644);
1909     }
1910 }
1911
1912 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1913 pub struct LlvmTools {
1914     pub stage: u32,
1915     pub target: Interned<String>,
1916 }
1917
1918 impl Step for LlvmTools {
1919     type Output = Option<PathBuf>;
1920     const ONLY_HOSTS: bool = true;
1921
1922     fn should_run(run: ShouldRun) -> ShouldRun {
1923         run.path("llvm-tools")
1924     }
1925
1926     fn make_run(run: RunConfig) {
1927         run.builder.ensure(LlvmTools {
1928             stage: run.builder.top_stage,
1929             target: run.target,
1930         });
1931     }
1932
1933     fn run(self, builder: &Builder) -> Option<PathBuf> {
1934         let stage = self.stage;
1935         let target = self.target;
1936         assert!(builder.config.extended);
1937
1938         /* run only if llvm-config isn't used */
1939         if let Some(config) = builder.config.target_config.get(&target) {
1940             if let Some(ref _s) = config.llvm_config {
1941                 builder.info(&format!("Skipping LlvmTools stage{} ({}): external LLVM",
1942                     stage, target));
1943                 return None;
1944             }
1945         }
1946
1947         builder.info(&format!("Dist LlvmTools stage{} ({})", stage, target));
1948         let src = builder.src.join("src/llvm");
1949         let name = pkgname(builder, "llvm-tools");
1950
1951         let tmp = tmpdir(builder);
1952         let image = tmp.join("llvm-tools-image");
1953         drop(fs::remove_dir_all(&image));
1954
1955         // Prepare the image directory
1956         let src_bindir = builder
1957             .llvm_out(target)
1958             .join("bin");
1959         let dst_bindir = image.join("lib/rustlib")
1960             .join(&*target)
1961             .join("bin");
1962         t!(fs::create_dir_all(&dst_bindir));
1963         for tool in LLVM_TOOLS {
1964             let exe = src_bindir.join(exe(tool, &target));
1965             builder.install(&exe, &dst_bindir, 0o755);
1966         }
1967
1968         // Prepare the overlay
1969         let overlay = tmp.join("llvm-tools-overlay");
1970         drop(fs::remove_dir_all(&overlay));
1971         builder.create_dir(&overlay);
1972         builder.install(&src.join("README.txt"), &overlay, 0o644);
1973         builder.install(&src.join("LICENSE.TXT"), &overlay, 0o644);
1974         builder.create(&overlay.join("version"), &builder.llvm_tools_vers());
1975
1976         // Generate the installer tarball
1977         let mut cmd = rust_installer(builder);
1978         cmd.arg("generate")
1979             .arg("--product-name=Rust")
1980             .arg("--rel-manifest-dir=rustlib")
1981             .arg("--success-message=llvm-tools-installed.")
1982             .arg("--image-dir").arg(&image)
1983             .arg("--work-dir").arg(&tmpdir(builder))
1984             .arg("--output-dir").arg(&distdir(builder))
1985             .arg("--non-installed-overlay").arg(&overlay)
1986             .arg(format!("--package-name={}-{}", name, target))
1987             .arg("--legacy-manifest-dirs=rustlib,cargo")
1988             .arg("--component-name=llvm-tools-preview");
1989
1990
1991         builder.run(&mut cmd);
1992         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
1993     }
1994 }
1995
1996 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
1997 pub struct Lldb {
1998     pub target: Interned<String>,
1999 }
2000
2001 impl Step for Lldb {
2002     type Output = Option<PathBuf>;
2003     const ONLY_HOSTS: bool = true;
2004     const DEFAULT: bool = true;
2005
2006     fn should_run(run: ShouldRun) -> ShouldRun {
2007         run.path("src/tools/lldb")
2008     }
2009
2010     fn make_run(run: RunConfig) {
2011         run.builder.ensure(Lldb {
2012             target: run.target,
2013         });
2014     }
2015
2016     fn run(self, builder: &Builder) -> Option<PathBuf> {
2017         let target = self.target;
2018
2019         if builder.config.dry_run {
2020             return None;
2021         }
2022
2023         let bindir = builder
2024             .llvm_out(target)
2025             .join("bin");
2026         let lldb_exe = bindir.join(exe("lldb", &target));
2027         if !lldb_exe.exists() {
2028             return None;
2029         }
2030
2031         builder.info(&format!("Dist Lldb ({})", target));
2032         let src = builder.src.join("src/tools/lldb");
2033         let name = pkgname(builder, "lldb");
2034
2035         let tmp = tmpdir(builder);
2036         let image = tmp.join("lldb-image");
2037         drop(fs::remove_dir_all(&image));
2038
2039         // Prepare the image directory
2040         let root = image.join("lib/rustlib").join(&*target);
2041         let dst = root.join("bin");
2042         t!(fs::create_dir_all(&dst));
2043         for program in &["lldb", "lldb-argdumper", "lldb-mi", "lldb-server"] {
2044             let exe = bindir.join(exe(program, &target));
2045             builder.install(&exe, &dst, 0o755);
2046         }
2047
2048         // The libraries.
2049         let libdir = builder.llvm_out(target).join("lib");
2050         let dst = root.join("lib");
2051         t!(fs::create_dir_all(&dst));
2052         for entry in t!(fs::read_dir(&libdir)) {
2053             let entry = entry.unwrap();
2054             if let Ok(name) = entry.file_name().into_string() {
2055                 if name.starts_with("liblldb.") && !name.ends_with(".a") {
2056                     if t!(entry.file_type()).is_symlink() {
2057                         builder.copy_to_folder(&entry.path(), &dst);
2058                     } else {
2059                        builder.install(&entry.path(), &dst, 0o755);
2060                     }
2061                 }
2062             }
2063         }
2064
2065         // The lldb scripts might be installed in lib/python$version
2066         // or in lib64/python$version.  If lib64 exists, use it;
2067         // otherwise lib.
2068         let libdir = builder.llvm_out(target).join("lib64");
2069         let (libdir, libdir_name) = if libdir.exists() {
2070             (libdir, "lib64")
2071         } else {
2072             (builder.llvm_out(target).join("lib"), "lib")
2073         };
2074         for entry in t!(fs::read_dir(&libdir)) {
2075             let entry = t!(entry);
2076             if let Ok(name) = entry.file_name().into_string() {
2077                 if name.starts_with("python") {
2078                     let dst = root.join(libdir_name)
2079                         .join(entry.file_name());
2080                     t!(fs::create_dir_all(&dst));
2081                     builder.cp_r(&entry.path(), &dst);
2082                     break;
2083                 }
2084             }
2085         }
2086
2087         // Prepare the overlay
2088         let overlay = tmp.join("lldb-overlay");
2089         drop(fs::remove_dir_all(&overlay));
2090         builder.create_dir(&overlay);
2091         builder.install(&src.join("LICENSE.TXT"), &overlay, 0o644);
2092         builder.create(&overlay.join("version"), &builder.lldb_vers());
2093
2094         // Generate the installer tarball
2095         let mut cmd = rust_installer(builder);
2096         cmd.arg("generate")
2097             .arg("--product-name=Rust")
2098             .arg("--rel-manifest-dir=rustlib")
2099             .arg("--success-message=lldb-installed.")
2100             .arg("--image-dir").arg(&image)
2101             .arg("--work-dir").arg(&tmpdir(builder))
2102             .arg("--output-dir").arg(&distdir(builder))
2103             .arg("--non-installed-overlay").arg(&overlay)
2104             .arg(format!("--package-name={}-{}", name, target))
2105             .arg("--legacy-manifest-dirs=rustlib,cargo")
2106             .arg("--component-name=lldb-preview");
2107
2108
2109         builder.run(&mut cmd);
2110         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
2111     }
2112 }